Skip to content

Commit

Permalink
Merge branch 'master' of github.com:machinezone/IXWebSocket
Browse files Browse the repository at this point in the history
  • Loading branch information
bsergean committed Mar 28, 2024
2 parents 92beef8 + 755d98d commit 93e673d
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/unittest_windows_gcc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- uses: seanmiddleditch/gha-setup-ninja@master
- uses: egor-tensin/setup-mingw@v2.2.0
- uses: bsergean/setup-mingw@d79ce405bac9edef3a1726ef00554a56f0bafe66
- run: |
mkdir build
cd build
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ ws/.srl
ixhttpd
makefile
a.out
.idea/
cmake-build-debug/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Hello world

(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 ?)

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.

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.
Expand Down
11 changes: 11 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,17 @@ server.wait();

```
### Heartbeat
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.
To enable a 45 second heartbeat on a `WebSocketServer`:
```cpp
int pingIntervalSeconds = 45;
ix::WebSocketServer server(port, host, backlog, maxConnections, handshakeTimeoutSecs, addressFamily, pingIntervalSeconds);
```

## HTTP client API

```cpp
Expand Down
20 changes: 12 additions & 8 deletions ixwebsocket/IXHttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,20 @@ namespace ix
if (headers.find("Content-Length") != headers.end())
{
int contentLength = 0;
try
{
contentLength = std::stoi(headers["Content-Length"]);
const char* p = headers["Content-Length"].c_str();
char* p_end{};
errno = 0;
long val = std::strtol(p, &p_end, 10);
if (p_end == p // invalid argument
|| errno == ERANGE // out of range
|| val < std::numeric_limits<int>::min()
|| val > std::numeric_limits<int>::max()) {
return std::make_tuple(
false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
}
contentLength = val;
}
catch (const std::exception&)
{
return std::make_tuple(
false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
}

if (contentLength < 0)
{
return std::make_tuple(
Expand Down
8 changes: 6 additions & 2 deletions ixwebsocket/IXSelectInterruptPipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ namespace ix

SelectInterruptPipe::~SelectInterruptPipe()
{
::close(_fildes[kPipeReadIndex]);
::close(_fildes[kPipeWriteIndex]);
if (-1 != _fildes[kPipeReadIndex]) {
::close(_fildes[kPipeReadIndex]);
}
if (-1 != _fildes[kPipeWriteIndex]) {
::close(_fildes[kPipeWriteIndex]);
}
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
}
Expand Down
5 changes: 5 additions & 0 deletions ixwebsocket/IXSocketMbedTLS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,11 @@ namespace ix
return res;
}

if (res == 0)
{
errno = ECONNRESET;
}

if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
{
errno = EWOULDBLOCK;
Expand Down
7 changes: 7 additions & 0 deletions ixwebsocket/IXSocketOpenSSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#ifdef _WIN32
// For manipulating the certificate store
#include <windows.h>
#include <wincrypt.h>
#endif

Expand Down Expand Up @@ -293,10 +294,16 @@ namespace ix
*/
bool SocketOpenSSL::checkHost(const std::string& host, const char* pattern)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
return true;
#else

#ifdef _WIN32
return PathMatchSpecA(host.c_str(), pattern);
#else
return fnmatch(pattern, host.c_str(), 0) != FNM_NOMATCH;
#endif

#endif
}

Expand Down
10 changes: 6 additions & 4 deletions ixwebsocket/IXUrlParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ namespace
bHasUserName = true;
break;
}
else if (*LocalString == '/')
else if (*LocalString == '/' || *LocalString == '?')
{
// end of <host>:<port> specification
bHasUserName = false;
Expand Down Expand Up @@ -242,7 +242,7 @@ namespace
LocalString++;
break;
}
else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/'))
else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/' || *LocalString == '?'))
{
// port number is specified
break;
Expand Down Expand Up @@ -280,12 +280,14 @@ namespace
}

// skip '/'
if (*CurrentString != '/')
if (*CurrentString != '/' && *CurrentString != '?')
{
return clParseURL(LUrlParserError_NoSlash);
}

CurrentString++;
if (*CurrentString != '?') {
CurrentString++;
}

// parse the path
LocalString = CurrentString;
Expand Down
2 changes: 1 addition & 1 deletion ixwebsocket/IXWebSocketProxyServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace ix
server.setOnConnectionCallback(
[remoteUrl, remoteUrlsMapping](std::weak_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
auto state = std::dynamic_pointer_cast<ProxyConnectionState>(connectionState);
auto state = std::static_pointer_cast<ProxyConnectionState>(connectionState);
auto remoteIp = connectionState->getRemoteIp();

// Server connection
Expand Down
6 changes: 5 additions & 1 deletion ixwebsocket/IXWebSocketServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ namespace ix
{
const int WebSocketServer::kDefaultHandShakeTimeoutSecs(3); // 3 seconds
const bool WebSocketServer::kDefaultEnablePong(true);
const int WebSocketServer::kPingIntervalSeconds(-1); // disable heartbeat

WebSocketServer::WebSocketServer(int port,
const std::string& host,
int backlog,
size_t maxConnections,
int handshakeTimeoutSecs,
int addressFamily)
int addressFamily,
int pingIntervalSeconds)
: SocketServer(port, host, backlog, maxConnections, addressFamily)
, _handshakeTimeoutSecs(handshakeTimeoutSecs)
, _enablePong(kDefaultEnablePong)
, _enablePerMessageDeflate(true)
, _pingIntervalSeconds(pingIntervalSeconds)
{
}

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

webSocket->setAutoThreadName(false);
webSocket->setPingInterval(_pingIntervalSeconds);

if (_onConnectionCallback)
{
Expand Down
5 changes: 4 additions & 1 deletion ixwebsocket/IXWebSocketServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ namespace ix
int backlog = SocketServer::kDefaultTcpBacklog,
size_t maxConnections = SocketServer::kDefaultMaxConnections,
int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs,
int addressFamily = SocketServer::kDefaultAddressFamily);
int addressFamily = SocketServer::kDefaultAddressFamily,
int pingIntervalSeconds = WebSocketServer::kPingIntervalSeconds);
virtual ~WebSocketServer();
virtual void stop() final;

Expand Down Expand Up @@ -61,6 +62,7 @@ namespace ix
int _handshakeTimeoutSecs;
bool _enablePong;
bool _enablePerMessageDeflate;
int _pingIntervalSeconds;

OnConnectionCallback _onConnectionCallback;
OnClientMessageCallback _onClientMessageCallback;
Expand All @@ -69,6 +71,7 @@ namespace ix
std::set<std::shared_ptr<WebSocket>> _clients;

const static bool kDefaultEnablePong;
const static int kPingIntervalSeconds;

// Methods
virtual void handleConnection(std::unique_ptr<Socket> socket,
Expand Down
34 changes: 34 additions & 0 deletions test/IXUrlParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,40 @@ namespace ix
REQUIRE(port == 443); // default port for wss
}

SECTION("wss://google.com/?arg=value")
{
std::string url = "wss://google.com/?arg=value&arg2=value2";
std::string protocol, host, path, query;
int port;
bool res;

res = UrlParser::parse(url, protocol, host, path, query, port);

REQUIRE(res);
REQUIRE(protocol == "wss");
REQUIRE(host == "google.com");
REQUIRE(path == "/?arg=value&arg2=value2");
REQUIRE(query == "arg=value&arg2=value2");
REQUIRE(port == 443); // default port for wss
}

SECTION("wss://google.com?arg=value")
{
std::string url = "wss://google.com?arg=value&arg2=value2";
std::string protocol, host, path, query;
int port;
bool res;

res = UrlParser::parse(url, protocol, host, path, query, port);

REQUIRE(res);
REQUIRE(protocol == "wss");
REQUIRE(host == "google.com");
REQUIRE(path == "/?arg=value&arg2=value2");
REQUIRE(query == "arg=value&arg2=value2");
REQUIRE(port == 443); // default port for wss
}

SECTION("real test")
{
std::string url =
Expand Down

0 comments on commit 93e673d

Please sign in to comment.