Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
option(EOSERV_WANT_MYSQL "Enables MariaDB/MySQL server database support." ON)
option(EOSERV_WANT_SQLITE "Enables SQLite3 embedded database support." ON)
option(EOSERV_WANT_SQLSERVER "Enables Microsoft SQL Server database support." ON)
option(EOSERV_WANT_WEBSOCKET "Enables WebSocket listener for web client connections." OFF)

option(EOSERV_USE_PRECOMPILED_HEADERS "Uses a precompiled header to speed up compilation." ON)
option(EOSERV_USE_UNITY_BUILD "Compiles multiple source files in one translation unit to speed up compilation." ON)
Expand Down Expand Up @@ -253,6 +254,15 @@ target_include_directories(eoserv_lib PUBLIC ${CMAKE_SOURCE_DIR}/json)
target_link_libraries(etheos eoserv_lib)
target_link_libraries(eoserv_lib ${eoserv_LIBRARIES})

if(EOSERV_WANT_WEBSOCKET)
include(DownloadIXWebSocket)
target_include_directories(etheos PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-src)
target_include_directories(eoserv_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-src)
list(APPEND eoserv_LIBRARIES ixwebsocket)
target_link_libraries(eoserv_lib ixwebsocket)
add_compile_definitions(WEBSOCKET_SUPPORT)
endif()

install(TARGETS etheos RUNTIME DESTINATION .)
install(TARGETS eoserv_test RUNTIME DESTINATION ./test)

Expand Down
13 changes: 13 additions & 0 deletions build-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function main() {
local mariadb="ON"
local sqlite="ON"
local sqlserver="ON"
local websocket="OFF"

local option
while [[ "$#" -gt 0 ]]
Expand Down Expand Up @@ -53,6 +54,10 @@ function main() {
sqlserver="$2"
shift
;;
--websocket)
websocket="$2"
shift
;;
*)
echo "Error: unsupported option \"${option}\""
return 1
Expand Down Expand Up @@ -86,13 +91,19 @@ function main() {
return 1
fi

if [[ "${websocket}" != "ON" && "${websocket}" != "OFF" ]]; then
echo "Error: acceptable values for option --websocket are ON|OFF"
return 1
fi

echo ""
echo "Build mode: ${build_mode}"
echo "Build directory: ${build_dir}"
echo "Install directory: ${install_dir}"
echo "MariaDB support: ${mariadb}"
echo "SQLite support: ${sqlite}"
echo "SQL Server support: ${sqlserver}"
echo "WebSocket support: ${websocket}"

if [[ "${opt_clean}" == "true" ]]; then
echo ""
Expand All @@ -114,6 +125,7 @@ function main() {
cmake_macros+=("-DEOSERV_WANT_MYSQL=${mariadb}")
cmake_macros+=("-DEOSERV_WANT_SQLITE=${sqlite}")
cmake_macros+=("-DEOSERV_WANT_SQLSERVER=${sqlserver}")
cmake_macros+=("-DEOSERV_WANT_WEBSOCKET=${websocket}")

pushd "${build_dir}" > /dev/null

Expand Down Expand Up @@ -154,6 +166,7 @@ function display_usage() {
echo " --mariadb (ON|OFF) MariaDB/MySQL support [default: OFF]."
echo " --sqlite (ON|OFF) SQLite support [default: OFF]."
echo " --sqlserver (ON|OFF) SQL Server support [default: ON]."
echo " --websocket (ON|OFF) WebSocket listener support [default: OFF]."
echo " -h --help Display this message."
}

Expand Down
30 changes: 30 additions & 0 deletions cmake/DownloadIXWebSocket.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

# Download and unpack IXWebSocket at configure time
if (NOT EOSERV_OFFLINE)
configure_file(${CMAKE_SOURCE_DIR}/cmake/ixwebsocketproj.cmake ixwebsocket-download/CMakeLists.txt)

execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-download )
if(result)
message(FATAL_ERROR "CMake step for IXWebSocket failed: ${result}")
endif()

execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-download )
if(result)
message(FATAL_ERROR "Build step for IXWebSocket failed: ${result}")
endif()
endif()

# Configure IXWebSocket options before adding subdirectory
set(USE_TLS OFF CACHE BOOL "" FORCE)
set(USE_OPEN_SSL OFF CACHE BOOL "" FORCE)
set(USE_MBED_TLS OFF CACHE BOOL "" FORCE)
set(IXWEBSOCKET_INSTALL OFF CACHE BOOL "" FORCE)

# Add IXWebSocket directly to our build
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-src
${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-build
EXCLUDE_FROM_ALL)
15 changes: 15 additions & 0 deletions cmake/ixwebsocketproj.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.5)

project(ixwebsocket-download NONE)

include(ExternalProject)
ExternalProject_Add(ixwebsocket
GIT_REPOSITORY https://github.com/machinezone/IXWebSocket.git
GIT_TAG v11.4.5
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
9 changes: 9 additions & 0 deletions config/server.ini
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,12 @@ ThreadPoolThreads = 0
## WorldDumpFile (string)
# Path to a file used as a json dump for the world when the server crashes or exits
WorldDumpFile = ./world.bak.json

## WebSocketEnabled (bool)
# Enable WebSocket listener for web client connections
# Requires the server to be compiled with EOSERV_WANT_WEBSOCKET (--websocket ON)
WebSocketEnabled = no

## WebSocketPort (number)
# The port the WebSocket listener should listen on
WebSocketPort = 8082
2 changes: 2 additions & 0 deletions src/eoserv_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ void eoserv_config_validate_config(Config& config)
eoserv_config_default(config, "ThreadPoolThreads" , 0);
eoserv_config_default(config, "AutoCreateDatabase" , false);
eoserv_config_default(config, "WorldDumpFile" , "./world.bak.json");
eoserv_config_default(config, "WebSocketEnabled" , false);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this default enabled, I want web sockets to be a native feature not an optional addon

eoserv_config_default(config, "WebSocketPort" , 8082);
}

void eoserv_config_validate_admin(Config& config)
Expand Down
54 changes: 53 additions & 1 deletion src/eoserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#include <utility>
#include <vector>

#ifdef WEBSOCKET_SUPPORT
#include "wsserver.hpp"
#endif

void server_ping_all(void *server_void)
{
EOServer *server = static_cast<EOServer *>(server_void);
Expand Down Expand Up @@ -67,7 +71,7 @@ void server_check_hangup(void *server_void)
{
EOClient *client = static_cast<EOClient *>(rawclient);

if (client->Connected() && !client->Accepted() && client->start + delay < now)
if (client->Connected() && !client->Accepted() && !client->IsWebSocket() && client->start + delay < now)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to have it so that all clients (both regular socket clients and web socket clients) could be in the same collection so that the implementation could handle stuff like this (i.e. client->IsWebSocket() check should not be necessary since the client method implementations can just handle this transparently). Is it possible to rearchitect the change around that design goal?

{
server->RecordClientRejection(client->GetRemoteAddr(), "hanging up on idle client");
client->Close(true);
Expand Down Expand Up @@ -193,6 +197,26 @@ void EOServer::Initialize(std::shared_ptr<DatabaseFactory> databaseFactory, cons
this->start = Timer::GetTime();

this->UpdateConfig();

#ifdef WEBSOCKET_SUPPORT
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the CMake arg and the #ifdef guards, this should be always enabled

if (this->world->config["WebSocketEnabled"])
{
int ws_port = int(this->world->config["WebSocketPort"]);
std::string host = std::string(this->world->config["Host"]);
this->wsserver = new WSServer(this, host, ws_port);

if (this->wsserver->Start())
{
Console::Out("WebSocket server listening on %s:%i", host.c_str(), ws_port);
}
else
{
Console::Err("Failed to start WebSocket server on port %i", ws_port);
delete this->wsserver;
this->wsserver = nullptr;
}
}
#endif
}

Client *EOServer::ClientFactory(const Socket &sock)
Expand Down Expand Up @@ -295,6 +319,13 @@ void EOServer::Tick()

this->BuryTheDead();

#ifdef WEBSOCKET_SUPPORT
if (this->wsserver)
{
this->wsserver->Tick();
}
#endif

this->world->timer.Tick();
}

Expand All @@ -312,8 +343,29 @@ void EOServer::RecordClientRejection(const IPAddress& ip, const char* reason)
}
}

void EOServer::OnClientRemoved(Client *client)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing where this is called. What is this used for? Can BuryTheDead have a call into the wsserver that does something similar?

{
#ifdef WEBSOCKET_SUPPORT
if (client->IsWebSocket() && this->wsserver)
{
this->wsserver->RemoveClient(client);
}
#else
(void)client;
#endif
}

EOServer::~EOServer()
{
#ifdef WEBSOCKET_SUPPORT
if (this->wsserver)
{
this->wsserver->Stop();
delete this->wsserver;
this->wsserver = nullptr;
}
#endif

// All clients must be fully closed before the world ends
UTIL_FOREACH(this->clients, client)
{
Expand Down
10 changes: 10 additions & 0 deletions src/eoserver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

#include "socket.hpp"

#ifdef WEBSOCKET_SUPPORT
#include "fwd/wsserver.hpp"
#endif

#include <array>
#include <string>
#include <unordered_map>
Expand Down Expand Up @@ -66,7 +70,13 @@ class EOServer : public Server
void RecordClientRejection(const IPAddress& ip, const char* reason);
void CleanupConnectionLog();

void OnClientRemoved(Client *client) override;

~EOServer();

#ifdef WEBSOCKET_SUPPORT
WSServer *wsserver = nullptr;
#endif
};

#endif // EOSERVER_HPP_INCLUDED
14 changes: 14 additions & 0 deletions src/fwd/wsclient.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

/* $Id$
* EOSERV is released under the zlib license.
* See LICENSE.txt for more info.
*/

#ifndef FWD_WSCLIENT_HPP_INCLUDED
#define FWD_WSCLIENT_HPP_INCLUDED

#ifdef WEBSOCKET_SUPPORT
class WSClient;
#endif // WEBSOCKET_SUPPORT

#endif // FWD_WSCLIENT_HPP_INCLUDED
14 changes: 14 additions & 0 deletions src/fwd/wsserver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

/* $Id$
* EOSERV is released under the zlib license.
* See LICENSE.txt for more info.
*/

#ifndef FWD_WSSERVER_HPP_INCLUDED
#define FWD_WSSERVER_HPP_INCLUDED

#ifdef WEBSOCKET_SUPPORT
class WSServer;
#endif // WEBSOCKET_SUPPORT

#endif // FWD_WSSERVER_HPP_INCLUDED
8 changes: 6 additions & 2 deletions src/socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ class Client
Server *server;
bool connected;
bool accepted = false;
bool is_websocket = false;
std::time_t closed_time;
std::time_t connect_time;

Expand Down Expand Up @@ -270,9 +271,10 @@ class Client

bool Accepted() const { return accepted; }
void MarkAccepted() { accepted = true; }
bool IsWebSocket() const { return is_websocket; }

virtual bool Connected() const;
IPAddress GetRemoteAddr() const;
virtual IPAddress GetRemoteAddr() const;

void AsyncOpPending(bool asyncOpPending) { this->async_op_pending = asyncOpPending; }
bool IsAsyncOpPending() const { return this->async_op_pending; }
Expand Down Expand Up @@ -437,7 +439,9 @@ class Server
return this->maxconn;
}

virtual ~Server();
virtual void OnClientRemoved(Client *) {}

virtual ~Server();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the indentation here

};


Expand Down
Loading
Loading