diff options
Diffstat (limited to 'masterserver')
| -rw-r--r-- | masterserver/default.bam | 18 | ||||
| -rw-r--r-- | masterserver/include/common.h | 6 | ||||
| -rw-r--r-- | masterserver/include/masterserver.h | 48 | ||||
| -rw-r--r-- | masterserver/include/network.h | 13 | ||||
| -rw-r--r-- | masterserver/include/serverinfo.h | 69 | ||||
| -rw-r--r-- | masterserver/src/main.cpp | 29 | ||||
| -rw-r--r-- | masterserver/src/masterserver.cpp | 176 | ||||
| -rw-r--r-- | masterserver/src/network.cpp | 39 |
8 files changed, 398 insertions, 0 deletions
diff --git a/masterserver/default.bam b/masterserver/default.bam new file mode 100644 index 00000000..06492b70 --- /dev/null +++ b/masterserver/default.bam @@ -0,0 +1,18 @@ +baselib = Import("../../baselib/baselib.bam") +--scheme = Import("scheme/scheme.bam") + +settings = NewSettings() +baselib.use(settings) +--scheme.use(settings) +settings.cc.includes:add("include") +--settings.cc.includes:add("include/python") +--settings.cc.frameworks:add("Python") +--//settings.linker.libs:add("/opt/local/lib/python2.5/config/libpython2.5.a") +--settings.linker.frameworks:add("Python") + +src = Collect("src/*.cpp") +objs = Compile(settings, src) +exe = Link(settings, "server", objs) + +--Target(baselib.lib) +Target(exe) diff --git a/masterserver/include/common.h b/masterserver/include/common.h new file mode 100644 index 00000000..ff03a61b --- /dev/null +++ b/masterserver/include/common.h @@ -0,0 +1,6 @@ +#ifndef _COMMON_H +#define _COMMON_H + +typedef int int32; + +#endif diff --git a/masterserver/include/masterserver.h b/masterserver/include/masterserver.h new file mode 100644 index 00000000..7e042aaa --- /dev/null +++ b/masterserver/include/masterserver.h @@ -0,0 +1,48 @@ +#ifndef _MASTERSERVER_H +#define _MASTERSERVER_H + +#include <baselib/network.h> +#include "serverinfo.h" + +using namespace baselib; + +#define HEARTBEAT_SIZE 216 +#define HEARTBEAT_SIGNATURE 'TWHB' +#define HEARTBEAT_LIFETIME 10 +#define MAXSERVERS 1024 +#define SERVERINFOOUT_SIZE 212 +#define SERVERINFOHEADER_SIZE 12 +#define MASTERSERVER_VERSION 0 + +class CMasterServer +{ + CServerInfo m_Servers[MAXSERVERS]; + int m_ServerCount; + socket_udp4 m_UDPSocket; + socket_tcp4 m_TCPSocket; + int m_CurrentTime; + char m_ServerListPacket[MAXSERVERS * SERVERINFOOUT_SIZE + SERVERINFOHEADER_SIZE]; + int m_ServerListPacketSize; + bool m_ServerListPacketIsOld; + + void ListenForServerListPolls(); + void BuildServerListPacket(); + void ListenForHeartBeats(); + void ProcessHeartBeat(CServerInfo info); + CServerInfo *FindServerInfo(int32 ip, int32 port); + CServerInfo *GetUnusedSlot(); + void CleanUpServerList(); +public: + CMasterServer() + { + m_ServerCount = 0; + m_ServerListPacketIsOld = true; + } + + void Init(int port); + void Shutdown(); + + void Tick(); +}; + +#endif diff --git a/masterserver/include/network.h b/masterserver/include/network.h new file mode 100644 index 00000000..455fe681 --- /dev/null +++ b/masterserver/include/network.h @@ -0,0 +1,13 @@ +#ifndef _NETWORK_H +#define _NETWORK_H + +#include <cstring> +#include "common.h" + +char *WriteInt32(char *buffer, int32 value); +char *WriteFixedString(char *buffer, const char *string, int strlen); + +char *ReadInt32(char *buffer, int32 *value); +char *ReadFixedString(char *buffer, char *string, int strlen); + +#endif diff --git a/masterserver/include/serverinfo.h b/masterserver/include/serverinfo.h new file mode 100644 index 00000000..c63e11ba --- /dev/null +++ b/masterserver/include/serverinfo.h @@ -0,0 +1,69 @@ +#ifndef _SERVERINFO_H +#define _SERVERINFO_H + +#include <baselib/network.h> + +#include "common.h" +#include "network.h" + +class CServerInfo +{ + int32 m_Version; + int32 m_IP; + int32 m_Port; + int32 m_Players; + int32 m_MaxPlayers; + char m_Name[128]; + char m_Map[64]; + + int m_LastRefresh; + +public: + int32 IP() const { return m_IP; } + int32 Port() const { return m_Port; } + int32 Players() const { return m_Players; } + int32 MaxPlayers() const { return m_MaxPlayers; }; + const char *Name() const { return m_Name; } + const char *Map() const { return m_Map; } + + void Refresh(int time) { m_LastRefresh = time; } + int LastRefresh() { return m_LastRefresh; } + + void SetAddress(baselib::netaddr4 *addr) + { + m_IP = addr->ip[0] << 24; + m_IP |= addr->ip[1] << 16; + m_IP |= addr->ip[2] << 8; + m_IP |= addr->ip[3]; + + m_Port = addr->port; + } + + char *Serialize(char *buffer) const + { + buffer = WriteInt32(buffer, m_Version); + buffer = WriteInt32(buffer, m_IP); + buffer = WriteInt32(buffer, m_Port); + buffer = WriteInt32(buffer, m_Players); + buffer = WriteInt32(buffer, m_MaxPlayers); + buffer = WriteFixedString(buffer, m_Name, sizeof(m_Name)); + buffer = WriteFixedString(buffer, m_Map, sizeof(m_Map)); + + return buffer; + } + + char *Deserialize(char *buffer) + { + buffer = ReadInt32(buffer, &m_Version); + buffer = ReadInt32(buffer, &m_IP); + buffer = ReadInt32(buffer, &m_Port); + buffer = ReadInt32(buffer, &m_Players); + buffer = ReadInt32(buffer, &m_MaxPlayers); + buffer = ReadFixedString(buffer, m_Name, sizeof(m_Name)); + buffer = ReadFixedString(buffer, m_Map, sizeof(m_Map)); + + return buffer; + } +}; + +#endif diff --git a/masterserver/src/main.cpp b/masterserver/src/main.cpp new file mode 100644 index 00000000..380830ad --- /dev/null +++ b/masterserver/src/main.cpp @@ -0,0 +1,29 @@ +#include <cstdio> +#include <cstdlib> + +#include "masterserver.h" + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + puts("Usage: masterserver <port> (this will bind the server to the port specified (both udp and tcp)."); + return -1; + } + + int port = atoi(argv[1]); + + CMasterServer masterServer; + masterServer.Init(port); + + while (1) + { + masterServer.Tick(); + + thread_sleep(10); + } + + masterServer.Shutdown(); + + return 0; +} diff --git a/masterserver/src/masterserver.cpp b/masterserver/src/masterserver.cpp new file mode 100644 index 00000000..383c696e --- /dev/null +++ b/masterserver/src/masterserver.cpp @@ -0,0 +1,176 @@ +#include <ctime> + +#include "masterserver.h" + +void CMasterServer::Init(int port) +{ + netaddr4 addr(0, 0, 0, 0, port); + addr.port = port; + + net_init(); + m_UDPSocket.open(port); + m_TCPSocket.open(&addr); + m_TCPSocket.set_non_blocking(); + m_TCPSocket.listen(); +} + +void CMasterServer::Shutdown() +{ + m_UDPSocket.close(); +} + +void CMasterServer::Tick() +{ + m_CurrentTime = time(NULL); + + ListenForHeartBeats(); + ListenForServerListPolls(); + + CleanUpServerList(); +} + +void CMasterServer::ListenForHeartBeats() +{ + netaddr4 from; + char data[1024]; + int dataSize; + + // read udp data while there is data to read :) + while ((dataSize = m_UDPSocket.recv(&from, (char *)data, sizeof(data))) > 0) + { + // compare the received data size to the expected size + if (dataSize == HEARTBEAT_SIZE) + { + char *d = data; + int32 signature; + d = ReadInt32(d, &signature); + + // make sure the signature is correct + if (signature == HEARTBEAT_SIGNATURE) + { + CServerInfo info; + info.Deserialize(d); + + from.port = 8303; + info.SetAddress(&from); + + dbg_msg("got heartbeat", "IP: %i.%i.%i.%i:%i", (int)from.ip[0], (int)from.ip[1], (int)from.ip[2], (int)from.ip[3], from.port); + + dbg_msg("refresh", "okay. server count: %i", m_ServerCount); + + ProcessHeartBeat(info); + } + else + {} // unexpected signature + } + else + {} // unknown data received + } +} + +void CMasterServer::ProcessHeartBeat(CServerInfo info) +{ + // find the corresponding server info + CServerInfo *serverInfo = FindServerInfo(info.IP(), info.Port()); + + // if it isn't in the list already, try to get an unused slot + if (!serverInfo) + serverInfo = GetUnusedSlot(); + + // if we STILL don't have one, we're out of luck. + if (!serverInfo) + return; + + *serverInfo = info; + serverInfo->Refresh(m_CurrentTime); + + // mark the server list packet as old + m_ServerListPacketIsOld = true; +} + +CServerInfo *CMasterServer::FindServerInfo(int32 ip, int32 port) +{ + // for now, just loop over the array + for (int i = 0; i < m_ServerCount; i++) + { + CServerInfo *info = &m_Servers[i]; + if (info->IP() == ip && info->Port() == port) + return info; + } + + return 0x0; +} + +CServerInfo *CMasterServer::GetUnusedSlot() +{ + if (m_ServerCount == MAXSERVERS) + return 0x0; + else + return &m_Servers[m_ServerCount++]; +} + +void CMasterServer::CleanUpServerList() +{ + for (int i = 0; i < m_ServerCount; i++) + { + CServerInfo *serverInfo = &m_Servers[i]; + + // check if it's time to remove it from the list + if (serverInfo->LastRefresh() + HEARTBEAT_LIFETIME < m_CurrentTime) + { + if (i + 1 == m_ServerCount) + { + // if we're at the last one, just decrease m_ServerCount + --m_ServerCount; + } + else + { + // otherwise, copy the last slot here and then decrease i and m_ServerCount + *serverInfo = m_Servers[m_ServerCount - 1]; + --i; + --m_ServerCount; + } + + // mark the server list packet as old and outdated + m_ServerListPacketIsOld = true; + } + } +} + +void CMasterServer::ListenForServerListPolls() +{ + socket_tcp4 client; + + // accept clients while there are clients to be accepted + while (m_TCPSocket.accept(&client)) + { + // maybe we've prepared the packet already... it'd be silly to do it twice + if (m_ServerListPacketIsOld) + { + BuildServerListPacket(); + } + + // send the server list and then close the socket + client.send(m_ServerListPacket, m_ServerListPacketSize); + client.close(); + } +} + +void CMasterServer::BuildServerListPacket() +{ + char *d = m_ServerListPacket; + + d = WriteInt32(d, 'TWSL'); + d = WriteInt32(d, MASTERSERVER_VERSION); + + d = WriteInt32(d, m_ServerCount); + + for (int i = 0; i < m_ServerCount; i++) + { + CServerInfo *info = &m_Servers[i]; + d = info->Serialize(d); + } + + m_ServerListPacketSize = d - m_ServerListPacket; + m_ServerListPacketIsOld = false; +} diff --git a/masterserver/src/network.cpp b/masterserver/src/network.cpp new file mode 100644 index 00000000..7d557cdf --- /dev/null +++ b/masterserver/src/network.cpp @@ -0,0 +1,39 @@ +#include <cstring> +#include "common.h" +#include "network.h" + +char *WriteInt32(char *buffer, int32 value) +{ + buffer[0] = value >> 24; + buffer[1] = value >> 16; + buffer[2] = value >> 8; + buffer[3] = value; + + return buffer + sizeof(int32); +} + +char *WriteFixedString(char *buffer, const char *string, int strlen) +{ + memcpy(buffer, string, strlen); + + return buffer + strlen; +} + + + +char *ReadInt32(char *buffer, int32 *value) +{ + *value = buffer[0] << 24; + *value |= buffer[1] << 16; + *value |= buffer[2] << 8; + *value |= buffer[3]; + + return buffer + sizeof(int32); +} + +char *ReadFixedString(char *buffer, char *string, int strlen) +{ + memcpy(string, buffer, strlen); + + return buffer + strlen; +} |