[Master] Implement Master server

pull/176/merge
Koncord 8 years ago
parent 4c939f6d0a
commit c35d5a2c6c

@ -62,6 +62,7 @@ option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time"
# Apps and tools
option(BUILD_OPENMW "build OpenMW" ON)
option(BUILD_OPENMW_MP "build OpenMW-MP" ON)
option(BUILD_MASTER "build tes3mp master server" OFF)
option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON)
@ -571,6 +572,10 @@ if (BUILD_OPENMW_MP)
add_subdirectory( apps/openmw-mp )
endif()
if (BUILD_MASTER)
add_subdirectory( apps/master )
endif()
if (BUILD_OPENMW)
add_subdirectory( apps/openmw )
endif()

@ -0,0 +1,26 @@
project(masterserver)
set(CMAKE_CXX_STANDARD 14)
include_directories("./")
set(SOURCE_FILES main.cpp MasterServer.cpp MasterServer.hpp)
add_executable(masterserver ${SOURCE_FILES})
target_link_libraries(masterserver ${RakNet_LIBRARY} components)
option(BUILD_MASTER_TEST "build master server test program" OFF)
if(BUILD_MASTER_TEST)
add_executable(ServerTest ServerTest.cpp)
target_link_libraries(ServerTest ${RakNet_LIBRARY} components)
endif()
if (UNIX)
# Fix for not visible pthreads functions for linker with glibc 2.15
if(NOT APPLE)
target_link_libraries(masterserver ${CMAKE_THREAD_LIBS_INIT})
if(BUILD_MASTER_TEST)
target_link_libraries(ServerTest ${CMAKE_THREAD_LIBS_INIT})
endif()
endif(NOT APPLE)
endif(UNIX)

@ -0,0 +1,193 @@
//
// Created by koncord on 21.04.17.
//
#include <RakPeerInterface.h>
#include <RakSleep.h>
#include <BitStream.h>
#include <iostream>
#include "MasterServer.hpp"
#include <components/openmw-mp/Master/PacketMasterQuery.hpp>
#include <components/openmw-mp/Master/PacketMasterUpdate.hpp>
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
using namespace RakNet;
using namespace std;
using namespace mwmp;
MasterServer::MasterServer(unsigned short maxConnections, unsigned short port)
{
peer = RakPeerInterface::GetInstance();
sockdescr = SocketDescriptor(port, 0);
peer->Startup(maxConnections, &sockdescr, 1, 1000);
peer->SetMaximumIncomingConnections(maxConnections);
peer->SetIncomingPassword("pass", (int) strlen("pass"));
run = false;
}
MasterServer::~MasterServer()
{
Stop(true);
}
using namespace chrono;
void MasterServer::Thread()
{
unsigned char packetId = 0;
auto startTime = chrono::steady_clock::now();
while (run)
{
Packet *packet = peer->Receive();
auto now = chrono::steady_clock::now();
if (now - startTime >= 60s)
{
startTime = chrono::steady_clock::now();
for (auto it = servers.begin(); it != servers.end();)
{
if (it->second.lastUpdate + 60s <= now)
servers.erase(it++);
else ++it;
}
}
if (packet == nullptr)
RakSleep(10);
else
for (; packet; peer->DeallocatePacket(packet), packet = peer->Receive())
{
BitStream data(packet->data, packet->length, false);
data.Read(packetId);
switch (packetId)
{
case ID_NEW_INCOMING_CONNECTION:
cout << "New incoming connection: " << packet->systemAddress.ToString() << endl;
break;
case ID_DISCONNECTION_NOTIFICATION:
cout << "Disconnected: " << packet->systemAddress.ToString() << endl;
break;
case ID_CONNECTION_LOST:
cout << "Connection lost: " << packet->systemAddress.ToString() << endl;
break;
case ID_MASTER_QUERY:
{
BitStream send;
PacketMasterQuery pmq(peer);
pmq.SetSendStream(&send);
pmq.SetServers(reinterpret_cast<map<SystemAddress, Server> *>(&servers));
pmq.Send(packet->systemAddress);
cout << "Sent info about all " << servers.size() << " servers to "
<< packet->systemAddress.ToString() << endl;
peer->CloseConnection(packet->systemAddress, true);
break;
}
case ID_MASTER_UPDATE:
{
SystemAddress addr;
data.Read(addr); // update 1 server
ServerIter it = servers.find(addr);
if (it != servers.end())
{
mwmp::PacketMasterUpdate pmu(peer);
BitStream send;
pmu.SetSendStream(&send);
pair<SystemAddress, Server> pairPtr(it->first, static_cast<Server>(it->second));
pmu.SetServer(&pairPtr);
pmu.Send(packet->systemAddress);
cout << "Sent info about " << addr.ToString() << " to " << packet->systemAddress.ToString()
<< endl;
}
peer->CloseConnection(packet->systemAddress, true);
break;
}
case ID_MASTER_ANNOUNCE:
{
ServerIter iter = servers.find(packet->systemAddress);
PacketMasterAnnounce pma(peer);
pma.SetReadStream(&data);
SServer server;
pma.SetServer(&server);
pma.Read();
switch (pma.GetFunc())
{
case PacketMasterAnnounce::FUNCTION_DELETE:
{
if (iter != servers.end())
servers.erase(iter);
cout << "Deleted";
break;
}
case PacketMasterAnnounce::FUNCTION_ANNOUNCE:
{
if (iter == servers.end())
cout << "Added";
else
cout << "Updated";
iter = servers.insert({packet->systemAddress, server}).first;
break;
}
default:
cout << "Keeping alive";
}
cout << " server " << packet->systemAddress.ToString() << endl;
if (pma.GetFunc() != PacketMasterAnnounce::FUNCTION_DELETE)
iter->second.lastUpdate = now;
peer->CloseConnection(packet->systemAddress, true);
break;
}
default:
cout << "Wrong packet" << endl;
peer->CloseConnection(packet->systemAddress, true);
}
}
}
peer->Shutdown(1000);
RakPeerInterface::DestroyInstance(peer);
cout << "Server thread stopped" << endl;
}
void MasterServer::Start()
{
if (!run)
{
run = true;
tMasterThread = thread(&MasterServer::Thread, this);
cout << "Started" << endl;
}
}
void MasterServer::Stop(bool wait)
{
if (run)
{
run = false;
if (wait && tMasterThread.joinable())
tMasterThread.join();
}
}
bool MasterServer::isRunning()
{
return run;
}
void MasterServer::Wait()
{
if (run)
{
if (tMasterThread.joinable())
tMasterThread.join();
}
}

@ -0,0 +1,55 @@
//
// Created by koncord on 21.04.17.
//
#ifndef NEWMASTERPROTO_MASTERSERVER_HPP
#define NEWMASTERPROTO_MASTERSERVER_HPP
#include <thread>
#include <chrono>
#include <RakPeerInterface.h>
#include <components/openmw-mp/Master/MasterData.hpp>
class MasterServer
{
public:
MasterServer(unsigned short maxConnections, unsigned short port);
~MasterServer();
void Start();
void Stop(bool wait = false);
bool isRunning();
void Wait();
struct SServer : Server
{
std::chrono::steady_clock::time_point lastUpdate;
};
struct Ban
{
RakNet::SystemAddress sa;
bool permanent;
struct Date
{
} date;
};
typedef std::map<RakNet::SystemAddress, SServer> ServerMap;
typedef ServerMap::const_iterator ServerCIter;
typedef ServerMap::iterator ServerIter;
private:
void Thread();
private:
std::thread tMasterThread;
RakNet::RakPeerInterface* peer;
RakNet::SocketDescriptor sockdescr;
ServerMap servers;
bool run;
};
#endif //NEWMASTERPROTO_MASTERSERVER_HPP

@ -0,0 +1,186 @@
//
// Created by koncord on 21.04.17.
//
#include <RakPeerInterface.h>
#include <RakSleep.h>
#include <BitStream.h>
#include <iostream>
#include <Kbhit.h>
#include <Gets.h>
#include <components/openmw-mp/Master/MasterData.hpp>
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
#include <components/openmw-mp/Master/PacketMasterUpdate.hpp>
#include <components/openmw-mp/Master/PacketMasterQuery.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
using namespace std;
using namespace RakNet;
using namespace mwmp;
int main()
{
cout << "Server test" << endl;
SystemAddress masterAddr("127.0.0.1", 25560);
RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
RakNet::SocketDescriptor sd(25565, 0);
peer->Startup(8, &sd, 1);
ConnectionAttemptResult result = peer->Connect(masterAddr.ToString(false), masterAddr.GetPort(), "pass",
(int)(strlen("pass")), 0, 0, 5, 500);
assert(result == RakNet::CONNECTION_ATTEMPT_STARTED);
char message[2048];
BitStream send;
PacketMasterQuery pmq(peer);
pmq.SetSendStream(&send);
PacketMasterAnnounce pma(peer);
pma.SetSendStream(&send);
while (true)
{
RakSleep(30);
if (kbhit())
{
Gets(message, sizeof(message));
if (strcmp(message, "quit") == 0)
{
puts("Quitting.");
break;
}
else if (strcmp(message, "send") == 0)
{
puts("Sending data about server");
Server server;
server.SetName("Super Server");
server.SetPlayers(0);
server.SetMaxPlayers(0);
pma.SetServer(&server);
pma.SetFunc(PacketMasterAnnounce::FUNCTION_ANNOUNCE);
pma.Send(masterAddr);
}
else if (strcmp(message, "get") == 0)
{
puts("Request query info");
send.Reset();
send.Write((unsigned char) (ID_MASTER_QUERY));
peer->Send(&send, HIGH_PRIORITY, RELIABLE_ORDERED, CHANNEL_MASTER, masterAddr, false);
}
else if (strcmp(message, "getme") == 0)
{
send.Reset();
send.Write((unsigned char) (ID_MASTER_UPDATE));
send.Write(SystemAddress("127.0.0.1", 25565));
peer->Send(&send, HIGH_PRIORITY, RELIABLE_ORDERED, CHANNEL_MASTER, masterAddr, false);
}
else if (strcmp(message, "status") == 0)
{
cout << (peer->GetConnectionState(masterAddr) == IS_CONNECTED ? "Connected" : "Not connected") << endl;
}
else if (strcmp(message, "keep") == 0)
{
cout << "Sending keep alive" << endl;
pma.SetFunc(PacketMasterAnnounce::FUNCTION_KEEP);
pma.Send(masterAddr);
}
}
for (RakNet::Packet *packet = peer->Receive(); packet; peer->DeallocatePacket(packet), packet = peer->Receive())
{
BitStream data(packet->data, packet->length, false);
unsigned char packetID;
data.Read(packetID);
switch (packetID)
{
case ID_DISCONNECTION_NOTIFICATION:
// Connection lost normally
printf("ID_DISCONNECTION_NOTIFICATION\n");
break;
case ID_ALREADY_CONNECTED:
// Connection lost normally
printf("ID_ALREADY_CONNECTED with guid %lu\n", packet->guid.g);
break;
case ID_INCOMPATIBLE_PROTOCOL_VERSION:
printf("ID_INCOMPATIBLE_PROTOCOL_VERSION\n");
break;
case ID_REMOTE_DISCONNECTION_NOTIFICATION: // Server telling the clients of another client disconnecting gracefully. You can manually broadcast this in a peer to peer enviroment if you want.
printf("ID_REMOTE_DISCONNECTION_NOTIFICATION\n");
break;
case ID_REMOTE_CONNECTION_LOST: // Server telling the clients of another client disconnecting forcefully. You can manually broadcast this in a peer to peer enviroment if you want.
printf("ID_REMOTE_CONNECTION_LOST\n");
break;
case ID_REMOTE_NEW_INCOMING_CONNECTION: // Server telling the clients of another client connecting. You can manually broadcast this in a peer to peer enviroment if you want.
printf("ID_REMOTE_NEW_INCOMING_CONNECTION\n");
break;
case ID_CONNECTION_BANNED: // Banned from this server
printf("We are banned from this server.\n");
break;
case ID_CONNECTION_ATTEMPT_FAILED:
printf("Connection attempt failed\n");
break;
case ID_NO_FREE_INCOMING_CONNECTIONS:
// Sorry, the server is full. I don't do anything here but
// A real app should tell the user
printf("ID_NO_FREE_INCOMING_CONNECTIONS\n");
break;
case ID_INVALID_PASSWORD:
printf("ID_INVALID_PASSWORD\n");
break;
case ID_CONNECTION_LOST:
// Couldn't deliver a reliable packet - i.e. the other system was abnormally
// terminated
printf("ID_CONNECTION_LOST\n");
return 0;
break;
case ID_CONNECTION_REQUEST_ACCEPTED:
// This tells the client they have connected
printf("ID_CONNECTION_REQUEST_ACCEPTED to %s with GUID %s\n", packet->systemAddress.ToString(true),
packet->guid.ToString());
printf("My external address is %s\n", peer->GetExternalID(packet->systemAddress).ToString(true));
break;
case ID_MASTER_QUERY:
{
map<SystemAddress, Server> servers;
pmq.SetReadStream(&data);
pmq.SetServers(&servers);
pmq.Read();
cout << "Received query data about " << servers.size() << " servers" << endl;
for (auto serv : servers)
cout << serv.second.GetName() << endl;
break;
}
case ID_MASTER_UPDATE:
{
pair<SystemAddress, Server> serverPair;
PacketMasterUpdate pmu(peer);
pmu.SetReadStream(&data);
pmu.SetServer(&serverPair);
pmu.Read();
cout << "Received info about " << serverPair.first.ToString() << endl;
cout << serverPair.second.GetName() << endl;
break;
}
default:
cout << "Wrong packet" << endl;
}
}
}
peer->Shutdown(1000);
RakPeerInterface::DestroyInstance(peer);
}

@ -0,0 +1,30 @@
#include <iostream>
#include <Kbhit.h>
#include <RakSleep.h>
#include "MasterServer.hpp"
using namespace RakNet;
using namespace std;
int main()
{
MasterServer masterServer(2000, 25560);
masterServer.Start();
/*while(true)
{
if(kbhit())
{
if(getch() == 'e')
{
cout << endl;
masterServer.Stop(true);
break;
}
}
RakSleep(100);
}*/
masterServer.Wait();
return 0;
}

@ -160,7 +160,7 @@ add_component_dir (openmw-mp\\Controllers
)
add_component_dir(openmw-mp\\Master
MasterData PacketMasterQuery PacketMasterUpdate PacketMasterAnnounce BaseMasterPacket
MasterData PacketMasterQuery PacketMasterUpdate PacketMasterAnnounce BaseMasterPacket ProxyMasterPacket
)
add_component_dir (openmw-mp\\Packets

Loading…
Cancel
Save