forked from teamnwah/openmw-tes3coop
[Master] Implement Master server
parent
4c939f6d0a
commit
c35d5a2c6c
@ -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;
|
||||
}
|
Loading…
Reference in New Issue