2018-12-29 23:15:27 -08:00
|
|
|
/*
|
|
|
|
* IXWebSocketServer.cpp
|
|
|
|
* Author: Benjamin Sergeant
|
|
|
|
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "IXWebSocketServer.h"
|
2018-12-30 22:00:49 -08:00
|
|
|
|
2019-09-23 10:25:23 -07:00
|
|
|
#include "IXNetSystem.h"
|
2020-02-23 09:44:58 -08:00
|
|
|
#include "IXSetThreadName.h"
|
2019-09-23 10:25:23 -07:00
|
|
|
#include "IXSocketConnect.h"
|
|
|
|
#include "IXWebSocket.h"
|
|
|
|
#include "IXWebSocketTransport.h"
|
2019-01-01 13:47:25 -08:00
|
|
|
#include <future>
|
2019-09-23 10:25:23 -07:00
|
|
|
#include <sstream>
|
2019-01-01 17:13:26 -08:00
|
|
|
#include <string.h>
|
2018-12-29 23:15:27 -08:00
|
|
|
|
2019-02-20 18:59:07 -08:00
|
|
|
namespace ix
|
2018-12-29 23:15:27 -08:00
|
|
|
{
|
2019-01-03 18:33:08 -08:00
|
|
|
const int WebSocketServer::kDefaultHandShakeTimeoutSecs(3); // 3 seconds
|
2019-04-18 18:24:16 +02:00
|
|
|
const bool WebSocketServer::kDefaultEnablePong(true);
|
2019-01-01 14:28:41 -08:00
|
|
|
|
2019-01-03 17:05:44 -08:00
|
|
|
WebSocketServer::WebSocketServer(int port,
|
|
|
|
const std::string& host,
|
|
|
|
int backlog,
|
2019-01-03 18:33:08 -08:00
|
|
|
size_t maxConnections,
|
2020-01-26 16:17:26 -08:00
|
|
|
int handshakeTimeoutSecs,
|
|
|
|
int addressFamily)
|
|
|
|
: SocketServer(port, host, backlog, maxConnections, addressFamily)
|
2019-09-23 10:25:23 -07:00
|
|
|
, _handshakeTimeoutSecs(handshakeTimeoutSecs)
|
|
|
|
, _enablePong(kDefaultEnablePong)
|
2020-02-18 21:38:28 -08:00
|
|
|
, _enablePerMessageDeflate(true)
|
2018-12-29 23:15:27 -08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
WebSocketServer::~WebSocketServer()
|
|
|
|
{
|
2019-01-01 14:52:14 -08:00
|
|
|
stop();
|
2018-12-29 23:15:27 -08:00
|
|
|
}
|
|
|
|
|
2019-01-01 14:52:14 -08:00
|
|
|
void WebSocketServer::stop()
|
|
|
|
{
|
2019-04-24 09:45:53 -07:00
|
|
|
stopAcceptingConnections();
|
|
|
|
|
2019-01-01 21:25:15 -08:00
|
|
|
auto clients = getClients();
|
|
|
|
for (auto client : clients)
|
|
|
|
{
|
|
|
|
client->close();
|
|
|
|
}
|
|
|
|
|
2019-01-06 12:01:33 -08:00
|
|
|
SocketServer::stop();
|
2019-01-01 14:52:14 -08:00
|
|
|
}
|
|
|
|
|
2019-04-18 18:24:16 +02:00
|
|
|
void WebSocketServer::enablePong()
|
|
|
|
{
|
|
|
|
_enablePong = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebSocketServer::disablePong()
|
|
|
|
{
|
|
|
|
_enablePong = false;
|
|
|
|
}
|
|
|
|
|
2020-02-18 21:38:28 -08:00
|
|
|
void WebSocketServer::disablePerMessageDeflate()
|
|
|
|
{
|
|
|
|
_enablePerMessageDeflate = false;
|
|
|
|
}
|
|
|
|
|
2019-01-06 12:01:33 -08:00
|
|
|
void WebSocketServer::setOnConnectionCallback(const OnConnectionCallback& callback)
|
2018-12-30 22:00:49 -08:00
|
|
|
{
|
2019-01-06 12:01:33 -08:00
|
|
|
_onConnectionCallback = callback;
|
2018-12-30 21:16:05 -08:00
|
|
|
}
|
|
|
|
|
2020-07-23 19:29:41 -07:00
|
|
|
void WebSocketServer::setOnClientMessageCallback(const OnClientMessageCallback& callback)
|
|
|
|
{
|
|
|
|
_onClientMessageCallback = callback;
|
|
|
|
}
|
|
|
|
|
2020-03-24 12:40:58 -07:00
|
|
|
void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket,
|
2020-07-08 12:10:35 -07:00
|
|
|
std::shared_ptr<ConnectionState> connectionState,
|
|
|
|
std::unique_ptr<ConnectionInfo> connectionInfo)
|
2018-12-30 21:16:05 -08:00
|
|
|
{
|
2020-02-23 09:44:58 -08:00
|
|
|
setThreadName("WebSocketServer::" + connectionState->getId());
|
|
|
|
|
2019-01-11 21:25:06 -08:00
|
|
|
auto webSocket = std::make_shared<WebSocket>();
|
2020-07-23 19:29:41 -07:00
|
|
|
if (_onConnectionCallback)
|
|
|
|
{
|
|
|
|
_onConnectionCallback(webSocket, connectionState, std::move(connectionInfo));
|
|
|
|
}
|
|
|
|
else if (_onClientMessageCallback)
|
|
|
|
{
|
|
|
|
webSocket->setOnMessageCallback(
|
|
|
|
[this, &ws = *webSocket.get(), connectionState, &ci = *connectionInfo.get()](
|
|
|
|
const WebSocketMessagePtr& msg) {
|
|
|
|
_onClientMessageCallback(connectionState, ci, ws, msg);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
logError(
|
|
|
|
"WebSocketServer Application developer error: No server callback is registerered.");
|
|
|
|
logError("Missing call to setOnConnectionCallback or setOnClientMessageCallback.");
|
|
|
|
connectionState->setTerminated();
|
|
|
|
return;
|
|
|
|
}
|
2018-12-30 22:12:13 -08:00
|
|
|
|
2019-01-01 21:25:15 -08:00
|
|
|
webSocket->disableAutomaticReconnection();
|
|
|
|
|
2019-04-18 18:24:16 +02:00
|
|
|
if (_enablePong)
|
2020-02-18 21:38:28 -08:00
|
|
|
{
|
2019-04-18 18:24:16 +02:00
|
|
|
webSocket->enablePong();
|
2020-02-18 21:38:28 -08:00
|
|
|
}
|
2019-04-18 18:24:16 +02:00
|
|
|
else
|
2020-02-18 21:38:28 -08:00
|
|
|
{
|
2019-04-18 18:24:16 +02:00
|
|
|
webSocket->disablePong();
|
2020-02-18 21:38:28 -08:00
|
|
|
}
|
|
|
|
|
2019-01-01 21:25:15 -08:00
|
|
|
// Add this client to our client set
|
2019-01-01 14:28:41 -08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(_clientsMutex);
|
|
|
|
_clients.insert(webSocket);
|
|
|
|
}
|
2019-01-01 13:47:25 -08:00
|
|
|
|
2020-03-24 12:40:58 -07:00
|
|
|
auto status = webSocket->connectToSocket(std::move(socket), _handshakeTimeoutSecs);
|
2019-01-02 16:08:32 -08:00
|
|
|
if (status.success)
|
|
|
|
{
|
2019-02-20 18:59:07 -08:00
|
|
|
// Process incoming messages and execute callbacks
|
2019-01-02 16:08:32 -08:00
|
|
|
// until the connection is closed
|
|
|
|
webSocket->run();
|
|
|
|
}
|
|
|
|
else
|
2019-01-01 13:47:25 -08:00
|
|
|
{
|
2019-01-01 14:28:41 -08:00
|
|
|
std::stringstream ss;
|
2019-09-23 10:25:23 -07:00
|
|
|
ss << "WebSocketServer::handleConnection() HTTP status: " << status.http_status
|
|
|
|
<< " error: " << status.errorStr;
|
2019-01-01 14:28:41 -08:00
|
|
|
logError(ss.str());
|
2019-01-01 13:47:25 -08:00
|
|
|
}
|
2018-12-31 12:43:47 -08:00
|
|
|
|
2020-07-24 09:41:02 -07:00
|
|
|
webSocket->setOnMessageCallback(nullptr);
|
|
|
|
|
2019-01-01 21:25:15 -08:00
|
|
|
// Remove this client from our client set
|
2019-01-01 14:28:41 -08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(_clientsMutex);
|
2019-01-01 21:25:15 -08:00
|
|
|
if (_clients.erase(webSocket) != 1)
|
|
|
|
{
|
|
|
|
logError("Cannot delete client");
|
|
|
|
}
|
2019-01-01 14:28:41 -08:00
|
|
|
}
|
|
|
|
|
2019-04-17 16:23:24 -07:00
|
|
|
connectionState->setTerminated();
|
2019-01-01 14:28:41 -08:00
|
|
|
}
|
2019-01-01 13:47:25 -08:00
|
|
|
|
2019-01-01 14:28:41 -08:00
|
|
|
std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(_clientsMutex);
|
|
|
|
return _clients;
|
2018-12-29 23:15:27 -08:00
|
|
|
}
|
2019-01-03 17:05:44 -08:00
|
|
|
|
|
|
|
size_t WebSocketServer::getConnectedClientsCount()
|
|
|
|
{
|
2019-01-11 21:25:06 -08:00
|
|
|
std::lock_guard<std::mutex> lock(_clientsMutex);
|
|
|
|
return _clients.size();
|
2019-01-03 17:05:44 -08:00
|
|
|
}
|
2019-09-23 10:25:23 -07:00
|
|
|
} // namespace ix
|