diff options
Diffstat (limited to 'Starserver')
-rw-r--r-- | Starserver/CMakeLists.txt | 4 | ||||
-rw-r--r-- | Starserver/NetAdminChat.cpp | 120 | ||||
-rw-r--r-- | Starserver/NetAdminChat.h | 32 | ||||
-rw-r--r-- | Starserver/NetAdminServer.cpp | 784 | ||||
-rw-r--r-- | Starserver/NetAdminServer.h | 90 | ||||
-rw-r--r-- | Starserver/NetFileServlet.cpp | 117 | ||||
-rw-r--r-- | Starserver/NetFileServlet.h | 49 | ||||
-rw-r--r-- | Starserver/StarServer.cpp | 309 | ||||
-rw-r--r-- | Starserver/StarServer.h | 54 |
9 files changed, 1559 insertions, 0 deletions
diff --git a/Starserver/CMakeLists.txt b/Starserver/CMakeLists.txt index 3142ce2..779b494 100644 --- a/Starserver/CMakeLists.txt +++ b/Starserver/CMakeLists.txt @@ -2,6 +2,10 @@ project(Starserver) add_executable( Starserver Main.cpp + NetAdminChat.cpp + NetAdminServer.cpp + NetFileServlet.cpp + StarServer.cpp ) target_include_directories( Starserver diff --git a/Starserver/NetAdminChat.cpp b/Starserver/NetAdminChat.cpp new file mode 100644 index 0000000..359173a --- /dev/null +++ b/Starserver/NetAdminChat.cpp @@ -0,0 +1,120 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet Engine for Multiplayer Admin +*/ + + +#include "NetAdminChat.h" +#include "NetLobbyServer.h" +#include "NetServerConfig.h" +#include "NetUser.h" +#include "NetChat.h" +#include "NetUtil.h" + +#include "HttpServlet.h" +#include "NetLayer.h" +#include "FormatUtil.h" + +// +-------------------------------------------------------------------+ + +NetAdminChat::NetAdminChat() +{ } + +// +-------------------------------------------------------------------+ + +bool +NetAdminChat::DoGet(HttpRequest& request, HttpResponse& response) +{ + if (CheckUser(request, response)) { + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) { + Text msg = request.GetParam("msg"); + Text act = request.GetParam("action"); + + if (msg.length()) { + lobby->AddChat(user, msg); + + if (user) + NetUtil::SendChat(0xffff, user->Name(), msg); + } + + else if (act.length()) { + if (act == "clear") + lobby->ClearChat(); + + else if (act == "save") + lobby->SaveChat(); + } + } + + response.SetStatus(HttpResponse::SC_OK); + response.AddHeader("MIME-Version", "1.0"); + response.AddHeader("Content-Type", "text/html"); + response.AddHeader("Cache-Control", "no-cache"); + response.AddHeader("Expires", "-1"); + + response.SetContent(GetHead("Chat") + + GetTitleBar(GetStatLine(), + "onLoad=\"self.focus();document.chatForm.msg.focus();\"") + + GetContent() + + GetBodyClose()); + } + + return true; +} + +// +-------------------------------------------------------------------+ + +Text +NetAdminChat::GetContent() +{ + Text content = "<div style=\"overflow-y:scroll; height:240px; padding-right:4pt; padding-left:4pt; padding-bottom:4pt; padding-top:4pt; margin:4pt;\">\n"; + + int nchat = 0; + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + if (lobby) { + content += "\n<table width=\"90%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n"; + + ListIter<NetChatEntry> iter = lobby->GetChat(); + while (++iter) { + NetChatEntry* c = iter.value(); + + content += " <tr><td nowrap width=\"130\" class=\"tiny\">"; + content += FormatTimeString(c->GetTime()); + content += "</td><td nowrap width=\"80\" class=\"tiny\">"; + content += c->GetUser(); + content += "</td><td class=\"tiny\">"; + content += c->GetMessage(); + content += "</td></tr>\n"; + } + + content += "</table>\n\n"; + } + + content += "</div>\n<div class=\"content\">\n\ +<form name=\"chatForm\" method=\"post\"action=\"/chat\">\n\ +<table border=\"0\">\n\ + <tr>\n\ + <td valign=\"middle\"> <input type=\"text\" name=\"msg\" size=\"80\"></td>\n\ + <td valign=\"middle\"> <input type=\"submit\" value=\"Send\"></td>\n\ + </tr>\n\ + <tr>\n\ + <td colspan=\"2\" valign=\"middle\" class=\"std\"> <a href=\"/chat\">Refresh</a>\ + · <a href=\"/chat?action=save\">Save</a> · <a href=\"/chat?action=clear\">Clear</a></td>\n\ + </tr>\n\ +</table>\n\ +</form>\n\ +</div>\n\n"; + + content += GetCopyright(); + return content; +} diff --git a/Starserver/NetAdminChat.h b/Starserver/NetAdminChat.h new file mode 100644 index 0000000..2ce1fba --- /dev/null +++ b/Starserver/NetAdminChat.h @@ -0,0 +1,32 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet Engine for Multiplayer Admin +*/ + + +#ifndef NetAdminChat_h +#define NetAdminChat_h + +#include "NetAdminServer.h" + +// +-------------------------------------------------------------------+ + +class NetAdminChat : public NetAdminServlet +{ +public: + NetAdminChat(); + virtual ~NetAdminChat() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response); + virtual Text GetContent(); +}; + +#endif // NetAdminChat_h
\ No newline at end of file diff --git a/Starserver/NetAdminServer.cpp b/Starserver/NetAdminServer.cpp new file mode 100644 index 0000000..7e82801 --- /dev/null +++ b/Starserver/NetAdminServer.cpp @@ -0,0 +1,784 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet Engine for Multiplayer Admin +*/ + + +#include "NetAdminServer.h" +#include "NetLobbyServer.h" +#include "NetServerConfig.h" +#include "NetClientConfig.h" +#include "NetAdminChat.h" +#include "NetUser.h" +#include "NetChat.h" + +#include "HttpServlet.h" +#include "NetLayer.h" + +#include "DataLoader.h" +#include "FormatUtil.h" +#include "MachineInfo.h" +#include "VersionInfo.h" + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminLogin : public NetAdminServlet +{ +public: + NetAdminLogin() { } + virtual ~NetAdminLogin() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + NetServerConfig* config = NetServerConfig::GetInstance(); + + Text admin_name = "system"; + Text admin_pass = "manager"; + + if (config) { + admin_name = config->GetAdminName(); + admin_pass = config->GetAdminPass(); + } + + Text name = request.GetParam("user"); + Text pass = request.GetParam("pass"); + + Sleep(500); + + if (CheckUser(request, response)) { + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/home"); + + response.SetContent(GetHead("Login") + + "<body><br>You are already logged in.<br>" + + GetBodyClose()); + } + + else if (name == admin_name && pass == admin_pass) { + user = new NetUser(name); + user->SetAddress(request.GetClientAddr()); + + if (session) + user->SetSessionID(session->GetID()); + + admin->AddUser(user); + + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/home"); + + response.SetContent(GetHead("Login") + + "<body><br>You have successfully logged in.<br>" + + GetBodyClose()); + } + + else { + response.SetStatus(HttpResponse::SC_OK); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + + response.SetContent(GetHead("Login") + + GetTitleBar(0, "onLoad=\"self.focus();document.loginForm.user.focus();\"") + + GetContent() + + GetBodyClose()); + } + + return true; + } + + virtual Text GetContent() { Text content = + " <table border=\"0\" cellspacing=\"0\" cellpadding=\"4\" align=\"left\" width =\"100%\">\n\ + <tr>\n\ + <td width=\"100\"> </td>\n\ + <td valign=\"top\" align=\"left\" width=\"400\"><br><br>\n\ + <span class=\"subhead\">Welcome to the Starshatter Server!</span><br><br>\n\ + <span class=\"std\">Login to access the server <b>"; + + NetServerConfig* config = NetServerConfig::GetInstance(); + if (config) + content += config->Name(); + else + content += "server"; + + content += "</b></span><br>\n\ + <form name=\"loginForm\" method=\"get\" action=\"/login\">\n\ + <table border=\"0\" cellspacing=\"0\" cellpadding=\"4\" width=\"100\">\n\ + <tr>\n\ + <td align=\"left\" valign=\"middle\" width=\"80\"><span class=\"std\">Username:</span></td>\n\ + <td align=\"left\" valign=\"middle\"><input type=\"text\" name=\"user\" size=\"25\"></td>\n\ + </tr>\n\ + <tr>\n\ + <td align=\"left\" valign=\"middle\" width=\"80\"><span class=\"std\">Password:</span></td>\n\ + <td align=\"left\" valign=\"middle\"><input type=\"password\" name=\"pass\" size=\"25\"></td>\n\ + </tr>\n\ + <tr>\n\ + <td> </td>\n\ + <td align=\"right\"><input type=\"submit\" value=\"Login\"></td>\n\ + </tr>\n\ + </table>\n\ + </form>\n\ + <td> </td>\n\ + </tr>\n\ +</table>\n"; + + return content; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminFile : public NetAdminServlet +{ +public: + NetAdminFile() { } + virtual ~NetAdminFile() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + if (!CheckUser(request, response)) + return true; + + Text content; + Text path = request.GetParam("path"); + Text name = request.GetParam("name"); + + if (name.length()) { + BYTE* buffer = 0; + DataLoader* loader = DataLoader::GetLoader(); + + if (loader) { + bool use_file_system = loader->IsFileSystemEnabled(); + + loader->UseFileSystem(true); + loader->SetDataPath(path); + int len = loader->LoadBuffer(name, buffer); + + if (len) { + content = Text((const char*) buffer, len); + } + + loader->ReleaseBuffer(buffer); + loader->SetDataPath(0); + loader->UseFileSystem(use_file_system); + } + } + + response.SetStatus(HttpResponse::SC_OK); + response.AddHeader("MIME-Version", "1.0"); + response.AddHeader("Cache-Control", "no-cache"); + response.AddHeader("Expires", "-1"); + response.AddHeader("Content-Type", "text/plain"); + response.SetContent(content); + + return true; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminUserList : public NetAdminServlet +{ +public: + NetAdminUserList() { } + virtual ~NetAdminUserList() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + if (CheckUser(request, response)) { + response.SetStatus(HttpResponse::SC_OK); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + + response.SetContent(GetHead("User List") + + GetTitleBar() + + GetContent() + + GetBodyClose()); + } + + return true; + } + + virtual Text GetContent() { + Text content = + "<script LANGUAGE=\"JavaScript\">\n\ +<!--\n\ +function doConfirm() {\n\ +return confirm(\"Are you sure you want to ban this player?\");\n\ +}\n\ +// -->\n\ +</script>\n\ +<div class=\"content\">\n\ +<table border=\"0\" width=\"95%\">\n\ + <tr class=\"heading\">\n\ + <td nowrap valign=\"middle\" align=\"left\">\n\ + <span class=\"heading\"> User List</span>\n\ + </td>\n\ + </tr>\n\ +</table>\n\n"; + + content += + " <table border=\"0\" width=\"95%\" class=\"std\">\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"20%\" valign=\"middle\" align=\"left\"><b>Name</b></td>\n\ + <td nowrap width=\"10%\" valign=\"middle\" align=\"left\"><b>Address</b></td>\n\ + <td nowrap width=\"10%\" valign=\"middle\" align=\"center\"><b>Is Host</b></td>\n\ + <td nowrap width=\"20%\" valign=\"middle\" align=\"left\"><b>Squadron</b></td>\n\ + <td nowrap width=\"20%\" valign=\"middle\" align=\"center\"><b>Stats</b></td>\n\ + <td nowrap width=\"19%\" valign=\"middle\" align=\"center\"><b>Ban</b></td>\n\ + <td></td>\n\ +</tr>\n"; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) { + ListIter<NetUser> u_iter = lobby->GetUsers(); + while (++u_iter) { + NetUser* u = u_iter.value(); + NetAddr a = u->GetAddress(); + + char addr_dotted[32]; + char addr_hex[16]; + char user_stats[16]; + + sprintf_s(addr_dotted, "%d.%d.%d.%d", a.B1(), a.B2(), a.B3(), a.B4()); + sprintf_s(addr_hex, "%08x", a.IPAddr()); + sprintf_s(user_stats, "%d / %d / %d", u->Missions(), u->Kills(), u->Losses()); + + content += "<tr>\n<td nowrap width=\"1%\"> </td>\n\ + <td nowrap valign=\"middle\" align=\"left\">"; + content += u->Name(); + content += "</td><td nowrap valign=\"middle\" align=\"left\">"; + content += addr_dotted; + content += "</td><td nowrap valign=\"middle\" align=\"center\">"; + content += u->IsHost() ? "*" : " "; + content += "</td><td nowrap valign=\"middle\" align=\"left\">"; + content += u->Squadron(); + content += "</td><td nowrap valign=\"middle\" align=\"center\">"; + content += user_stats; + content += "</td><td nowrap valign=\"middle\" align=\"center\">"; + content += "<a onclick=\"return doConfirm()\" href=\"/ban?name="; + content += HttpRequest::EncodeParam(u->Name()); + content += "&addr="; + content += addr_hex; + content += "\">BAN</a></td></tr>\n"; + } + } + + content += " </table>\n\n"; + + content += "</div>\n\n"; + content += GetCopyright(); + return content; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class NetAdminBanUser : public NetAdminServlet +{ +public: + NetAdminBanUser() { } + virtual ~NetAdminBanUser() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response) { + if (CheckUser(request, response)) { + Text name = request.GetParam("name"); + bool completed = false; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) { + ListIter<NetUser> u_iter = lobby->GetUsers(); + while (++u_iter && !completed) { + NetUser* u = u_iter.value(); + + if (u->Name() == name) { + NetLobbyServer* nls = NetLobbyServer::GetInstance(); + + if (nls) { + nls->BanUser(u); + completed = true; + } + } + } + } + + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/users"); + + response.SetContent(GetHead("User List") + + GetTitleBar() + + "<div class=\"content\">User Banned.<br></div>" + + GetBodyClose()); + } + + return true; + } +}; + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +static NetAdminServer* net_Admin_server = 0; + +NetAdminServer* +NetAdminServer::GetInstance(WORD port) +{ + if (!net_Admin_server && port > 0) + net_Admin_server = new NetAdminServer(port); + + return net_Admin_server; +} + +NetAdminServer::NetAdminServer(WORD port) +: HttpServletExec(port) +{ + http_server_name = Text("Starshatter NetAdminServer ") + versionInfo; +} + +NetAdminServer::~NetAdminServer() +{ + if (net_Admin_server == this) + net_Admin_server = 0; +} + +// +--------------------------------------------------------------------+ + +HttpServlet* +NetAdminServer::GetServlet(HttpRequest& request) +{ + Text path = request.URI(); + path.setSensitive(false); + + if (path.indexOf("/login") == 0) + return new NetAdminLogin; + + if (path.indexOf("/chat") == 0) + return new NetAdminChat; + + if (path.indexOf("/file") == 0) + return new NetAdminFile; + + if (path.indexOf("/user") == 0) + return new NetAdminUserList; + + if (path.indexOf("/ban") == 0) + return new NetAdminBanUser; + + return new NetAdminServlet; +} + +// +-------------------------------------------------------------------+ + +void +NetAdminServer::AddChat(NetUser* user, const char* msg) +{ + if (user && msg && *msg) { + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) + lobby->AddChat(user, msg); + } +} + +ListIter<NetChatEntry> +NetAdminServer::GetChat() +{ + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) + return lobby->GetChat(); + + static List<NetChatEntry> idle_chatter; + return idle_chatter; +} + +// +-------------------------------------------------------------------+ + +void +NetAdminServer::AddUser(NetUser* user) +{ + if (user && !admin_users.contains(user)) + admin_users.append(user); +} + +void +NetAdminServer::DelUser(NetUser* user) +{ + if (user) { + admin_users.remove(user); + delete user; + } +} + +int +NetAdminServer::NumUsers() +{ + return admin_users.size(); +} + + +List<NetUser>& +NetAdminServer::GetUsers() +{ + return admin_users; +} + +bool +NetAdminServer::HasHost() +{ + bool result = false; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + + if (lobby) + result = lobby->HasHost(); + + return result; +} + +NetUser* +NetAdminServer::FindUserBySession(Text id) +{ + ListIter<NetUser> iter = admin_users; + while (++iter) { + NetUser* u = iter.value(); + if (u->GetSessionID() == id) + return u; + } + + return 0; +} + +void +NetAdminServer::DoSyncedCheck() +{ + ListIter<NetUser> iter = admin_users; + while (++iter) { + NetUser* u = iter.value(); + + bool found = false; + + ListIter<HttpSession> s_iter = sessions; + while (++s_iter && !found) { + HttpSession* s = s_iter.value(); + + if (s->GetID() == u->GetSessionID()) + found = true; + } + + if (!found) + delete iter.removeItem(); + } +} + + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +NetAdminServlet::NetAdminServlet() +{ + admin = NetAdminServer::GetInstance(); + user = 0; +} + +// +-------------------------------------------------------------------+ + +bool +NetAdminServlet::DoGet(HttpRequest& request, HttpResponse& response) +{ + if (CheckUser(request, response)) { + + if (request.URI() == "/home") + response.SetStatus(HttpResponse::SC_OK); + else + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/html"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/home"); + + response.SetContent(GetHead() + + GetTitleBar(GetStatLine()) + + GetContent() + + GetBodyClose()); + } + + return true; +} + +// +-------------------------------------------------------------------+ + +bool +NetAdminServlet::CheckUser(HttpRequest& request, HttpResponse& response) +{ + if (!user) { + if (session) + user = admin->FindUserBySession(session->GetID()); + + if (!user) { + response.SetStatus(HttpResponse::SC_TEMPORARY_REDIRECT); + response.SetHeader("MIME-Version", "1.0"); + response.SetHeader("Content-Type", "text/plain"); + response.SetHeader("Cache-Control", "no-cache"); + response.SetHeader("Expires", "-1"); + response.SetHeader("Location", "/login"); + response.SetContent("You are not logged in."); + } + } + + return user != 0; +} + +// +-------------------------------------------------------------------+ + +Text +NetAdminServlet::GetCSS() +{ + return + + "body { font-family:arial,helvetica,sans-serif; color:black; background-color:white }\n\ +a:link { text-decoration:none; font-weight:normal; font-size:10pt; color:black }\n\ +a:visited { text-decoration:none; font-weight:normal; font-size:10pt; color:black }\n\ +a:hover { text-decoration:underline; font-weight:normal; font-size:10pt; color:black }\n\ +.std { font-size:10pt }\n\ +.tiny { font-size:8pt }\n\ +.heading { font-size:14pt; font-weight:bold; background-color:#99BBEE }\n\ +.subhead { font-size:11pt; font-weight:bold }\n\ +.status { font-size:10pt; color:white }\n\ +.content { padding-right: 4pt; padding-left: 4pt; padding-bottom: 4pt; padding-top: 4pt; margin: 4pt; }\n\ +.copy { font-size:8pt; }\n\ +.top-bar { color: white; background-color: #336699 }\n\ +.top-line { color: yellow; background-color: black }\n\ +.topbarbig { line-height:24px; color:white; font-size:18px; font-weight:bold; }\n\ +.topbarsmall { line-height:18px; color:white; font-size:14px; }\n"; +} + +Text +NetAdminServlet::GetHead(const char* title) +{ + Text head = "<html>\n<head>\n<title>Starshatter Server"; + + if (title && *title) { + head += " - "; + head += title; + } + + head += "</title>\n<style type=\"text/css\" media=\"screen\">\n"; + head += GetCSS(); + head += "</style>\n</head>\n"; + + return head; +} + +Text +NetAdminServlet::GetBody() +{ + return GetTitleBar(GetStatLine()) + + GetContent() + + GetBodyClose(); +} + +Text +NetAdminServlet::GetTitleBar(const char* statline, const char* onload) +{ + Text bar = "<body "; + + if (onload && *onload) + bar += onload; + + bar += " leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\n\ +<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\" class=\"top-bar\">\n\ + <tr height=\"50\">\n\ + <td> </td>\n\ + <td valign=\"middle\" align=\"left\">\n\ + <span class=\"topbarsmall\">Administration Console</span><br>\n"; + + if (statline) { + bar += "<a href=\"/home\">"; + } + + bar += "<span class=\"topbarbig\">Starshatter Server "; + bar += versionInfo; + bar += "</span>"; + + if (statline) { + bar += "</a>"; + } + + bar += "\n\ + </td>\n\ + </tr>\n\ + <tr class=\"top-line\">\n\ + <td colspan=\"2\">"; + + if (statline && *statline) + bar += statline; + else + bar += " "; + + bar += "</td>\n\ + </tr>\n\ +</table>\n\n"; + + return bar; +} + +Text +NetAdminServlet::GetStatLine() +{ + NetServerConfig* config = NetServerConfig::GetInstance(); + + Text line = + " <table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" border=\"0\">\n\ + <tr>\n\ + <td nowrap width=\"33%\" class=\"top-line\" align=\"left\">\n\ + <span class=\"status\"> Connected to <b>"; + + char buffer[256]; + sprintf_s(buffer, "%s:%d", config->Name().data(), config->GetAdminPort()); + line += buffer; + + line += "</b></span>\n\ + </td>\n\ + <td nowrap width=\"34%\" class=\"top-line\" align=\"center\">\n\ + <span class=\"status\">Server Mode: <b>"; + + NetLobbyServer* lobby = NetLobbyServer::GetInstance(); + if (lobby) { + switch (lobby->GetStatus()) { + default: + case NetServerInfo::OFFLINE: line += "Offline"; break; + case NetServerInfo::LOBBY: line += "Lobby"; break; + case NetServerInfo::BRIEFING: line += "Briefing"; break; + case NetServerInfo::ACTIVE: line += "Active"; break; + case NetServerInfo::DEBRIEFING: line += "Debriefing"; break; + case NetServerInfo::PERSISTENT: line += "PERSISTENT"; break; + } + } + else { + line += "Unknown"; + } + + line += "</b></span>\n\ + </td>\n\ + <td nowrap width=\"33%\" class=\"top-line\" align=\"right\">\n\ + <span class=\"status\">"; + + line += FormatTimeString(); + + line += " </span>\n\ + </td>\n\ + </tr>\n\ + </table>\n"; + + return line; +} + +Text +NetAdminServlet::GetContent() +{ + Text content = + "<script LANGUAGE=\"JavaScript\">\n\ +<!--\n\ +function doConfirm() {\n\ +return confirm(\"Are you sure you want to do this?\");\n\ +}\n\ +// -->\n\ +</script>\n\ +<div class=\"content\">\n\ +<table border=\"0\" width=\"95%\">\n\ + <tr class=\"heading\">\n\ + <td nowrap valign=\"middle\" align=\"left\">\n\ + <span class=\"heading\"> Game Admin Functions</span>\n\ + </td>\n\ + </tr>\n\ +</table>\n\n\ +<table border=\"0\" width=\"95%\">\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/chat\">Lobby Chat</a>\n\ + </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/home\">Mission List</a>\n\ + </td>\n\ + <td></td>\n\ + </tr>\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/file?name=errlog.txt\">View Error Log</a>\n\ + </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/users\">Player List</a>\n\ + </td>\n\ + <td></td>\n\ + </tr>\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/file?name=serverlog.txt\">View Server Log</a>\n\ + </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\">\n\ + <a href=\"/home\">Ban List</a>\n\ + </td>\n\ + <td></td>\n\ + </tr>\n\ + <tr>\n\ + <td nowrap width=\"1%\"> </td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\"></td>\n\ + <td nowrap width=\"33%\" valign=\"middle\" align=\"left\"></td>\n\ + <td></td>\n\ +</tr>\n\ +</table>\n\n"; + + content += "</div>\n\n"; + content += GetCopyright(); + return content; +} + +Text +NetAdminServlet::GetBodyClose() +{ + return "\n\n</body>\n</html>\n"; +} + +Text +NetAdminServlet::GetCopyright() +{ + return "<br><span class=\"copy\"> Copyright © 1997-2004 Destroyer Studios. All rights reserved.</span><br>"; +} diff --git a/Starserver/NetAdminServer.h b/Starserver/NetAdminServer.h new file mode 100644 index 0000000..804d482 --- /dev/null +++ b/Starserver/NetAdminServer.h @@ -0,0 +1,90 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet Engine for Multiplayer Admin +*/ + + +#ifndef NetAdminServer_h +#define NetAdminServer_h + +#include "HttpServletExec.h" +#include "HttpServlet.h" + +// +-------------------------------------------------------------------+ + +class Mission; +class MissionElement; +class NetChatEntry; +class NetUser; + +// +-------------------------------------------------------------------+ + +class NetAdminServer : public HttpServletExec +{ +public: + virtual ~NetAdminServer(); + + int operator == (const NetAdminServer& s) const { return this == &s; } + + virtual HttpServlet* GetServlet(HttpRequest& request); + + virtual void AddUser(NetUser* user); + virtual void DelUser(NetUser* user); + virtual int NumUsers(); + virtual bool HasHost(); + virtual List<NetUser>& GetUsers(); + + virtual NetUser* FindUserBySession(Text id); + + virtual void AddChat(NetUser* user, const char* msg); + ListIter<NetChatEntry> GetChat(); + DWORD GetStartTime() const { return start_time; } + + virtual void GameOn() { } + virtual void GameOff() { } + + // singleton locator: + static NetAdminServer* GetInstance(WORD port=0); + +protected: + NetAdminServer(WORD port); + virtual void DoSyncedCheck(); + + DWORD start_time; + List<NetUser> admin_users; +}; + +// +-------------------------------------------------------------------+ + +class NetAdminServlet : public HttpServlet +{ +public: + NetAdminServlet(); + virtual ~NetAdminServlet() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response); + virtual bool CheckUser(HttpRequest& request, HttpResponse& response); + + virtual Text GetCSS(); + virtual Text GetHead(const char* title=0); + virtual Text GetBody(); + virtual Text GetTitleBar(const char* statline=0, const char* onload=0); + virtual Text GetStatLine(); + virtual Text GetCopyright(); + virtual Text GetContent(); + virtual Text GetBodyClose(); + +protected: + NetAdminServer* admin; + NetUser* user; +}; + +#endif // NetAdminServer_h
\ No newline at end of file diff --git a/Starserver/NetFileServlet.cpp b/Starserver/NetFileServlet.cpp new file mode 100644 index 0000000..6b23d9d --- /dev/null +++ b/Starserver/NetFileServlet.cpp @@ -0,0 +1,117 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet for File Transfer +*/ + + +#include "NetFileServlet.h" +#include "NetAdminServer.h" +#include "NetLayer.h" + +#include "DataLoader.h" + +// +-------------------------------------------------------------------+ + +bool +NetFileServlet::DoGet(HttpRequest& request, HttpResponse& response) +{ + if (!CheckUser(request, response)) + return true; + + Text content; + Text path = request.GetParam("path"); + Text name = request.GetParam("name"); + + if (name.length()) { + BYTE* buffer = 0; + DataLoader* loader = DataLoader::GetLoader(); + + if (loader) { + loader->SetDataPath(path); + int len = loader->LoadBuffer(name, buffer); + + if (len) { + content = Text((const char*) buffer, len); + } + + loader->ReleaseBuffer(buffer); + loader->SetDataPath(0); + } + } + + response.SetStatus(HttpResponse::SC_OK); + response.AddHeader("MIME-Version", "1.0"); + response.AddHeader("Cache-Control", "no-cache"); + response.AddHeader("Expires", "-1"); + response.AddHeader("Content-Type", "text/plain"); + response.SetContent(content); + + return true; +} + +// +-------------------------------------------------------------------+ + +bool +NetWebServlet::DoGet(HttpRequest& request, HttpResponse& response) +{ + Text content; + Text name = request.URI(); + bool found = false; + + if (name.length() > 4) { + char filename[256]; + strcpy_s(filename, name.data() + 1); // skip leading '/' + + FILE* f; + ::fopen_s(&f, filename, "rb"); + + if (f) { + ::fseek(f, 0, SEEK_END); + int len = ftell(f); + ::fseek(f, 0, SEEK_SET); + + BYTE* buf = new BYTE[len]; + + ::fread(buf, len, 1, f); + ::fclose(f); + + content = Text((const char*) buf, len); + delete [] buf; + + found = true; + ::Print("weblog: 200 OK %s %d bytes\n", name.data(), len); + } + else { + ::Print("weblog: 404 Not Found %s\n", name.data()); + } + } + + if (found) { + Text content_type = "text/plain"; + + if (name.contains(".gif")) + content_type = "image/gif"; + else if (name.contains(".jpg")) + content_type = "image/jpeg"; + else if (name.contains(".htm")) + content_type = "text/html"; + + response.SetStatus(HttpResponse::SC_OK); + response.AddHeader("MIME-Version", "1.0"); + response.AddHeader("Content-Type", content_type); + response.SetContent(content); + } + else { + response.SetStatus(HttpResponse::SC_NOT_FOUND); + } + + return true; +} diff --git a/Starserver/NetFileServlet.h b/Starserver/NetFileServlet.h new file mode 100644 index 0000000..7de3443 --- /dev/null +++ b/Starserver/NetFileServlet.h @@ -0,0 +1,49 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + HTTP Servlet for File Transfer +*/ + + +#ifndef NetFileServlet_h +#define NetFileServlet_h + +#include "Types.h" +#include "NetAdminServer.h" +#include "NetUser.h" + +// +-------------------------------------------------------------------+ + +class Campaign; +class File; + +// +-------------------------------------------------------------------+ + +class NetFileServlet : public NetAdminServlet +{ +public: + NetFileServlet() { } + virtual ~NetFileServlet() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response); +}; + +// +-------------------------------------------------------------------+ + +class NetWebServlet : public NetAdminServlet +{ +public: + NetWebServlet() { } + virtual ~NetWebServlet() { } + + virtual bool DoGet(HttpRequest& request, HttpResponse& response); +}; + +#endif // NetFileServlet_h
\ No newline at end of file diff --git a/Starserver/StarServer.cpp b/Starserver/StarServer.cpp new file mode 100644 index 0000000..8d76f38 --- /dev/null +++ b/Starserver/StarServer.cpp @@ -0,0 +1,309 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + +*/ + +#include "StarServer.h" + +#include <stdlib.h> + +#include <chrono> +#include <iostream> +#include <thread> + +#include "Campaign.h" +#include "Clock.h" +#include "CombatRoster.h" +#include "DataLoader.h" +#include "Drive.h" +#include "Explosion.h" +#include "FlightDeck.h" +#include "Galaxy.h" +#include "Game.h" +#include "ModConfig.h" +#include "NetAdminServer.h" +#include "NetGame.cpp" +#include "NetLobby.h" +#include "NetLobbyServer.h" +#include "NetServerConfig.h" +#include "RadioTraffic.h" +#include "Random.h" +#include "Ship.h" +#include "Shot.h" +#include "Sim.h" +#include "SystemDesign.h" +#include "Types.h" +#include "Utils.h" +#include "WeaponDesign.h" + + +StarServer* StarServer::instance {nullptr}; + + +StarServer* +StarServer::GetInstance() +{ + return instance; +} + + +StarServer::StarServer() : + world {nullptr}, + current_mission {nullptr}, + admin_server {nullptr}, + lobby_server {nullptr} +{ + if (instance != nullptr) + throw "StarServer may have only one instance"; + instance = this; + + DataLoader::Initialize(); + auto loader = DataLoader::GetLoader(); + if (!loader) throw "Could not get DataLoader instance"; + + int loadstat = loader->EnableDatafile("shatter.dat"); + if (loadstat != DataLoader::DATAFILE_OK) { + if (loadstat == DataLoader::DATAFILE_INVALID) { + throw "The file 'shatter.dat' appears to have been damaged."; + } + else { + throw "Starshatter cannot open the file 'shatter.dat'. Please check current directory."; + } + } + + if (loader->FindFile("start.dat")) + loader->EnableDatafile("start.dat"); + + loader->EnableMedia(false); +} + + +StarServer::~StarServer() +{ + delete admin_server; + delete lobby_server; + + admin_server = nullptr; + lobby_server = nullptr; + + // delete all the ships and stuff + // BEFORE getting rid of the system + // and weapons catalogs! + if (world) delete world; + world = nullptr; + + Drive::Close(); + Explosion::Close(); + FlightDeck::Close(); + Campaign::Close(); + CombatRoster::Close(); + Galaxy::Close(); + RadioTraffic::Close(); + Ship::Close(); + WeaponDesign::Close(); + SystemDesign::Close(); + DataLoader::Close(); + NetServerConfig::Close(); + ModConfig::Close(); + + if (instance == this) + instance = nullptr; +} + + +bool +StarServer::Init(HINSTANCE hi, HINSTANCE hpi, LPSTR cmdline, int nCmdShow) +{ + if (auto loader = DataLoader::GetLoader()) + loader->UseFileSystem(false); + return Game::Init(hi, hpi, cmdline, nCmdShow); +} + + +bool +StarServer::InitGame() +{ + if (!Game::InitGame()) + return false; + + RandomInit(); + ModConfig::Initialize(); + NetServerConfig::Initialize(); + SystemDesign::Initialize("sys.def"); + WeaponDesign::Initialize("wep.def"); + Ship::Initialize(); + Galaxy::Initialize(); + CombatRoster::Initialize(); + Campaign::Initialize(); + + Drive::Initialize(); + Explosion::Initialize(); + FlightDeck::Initialize(); + Ship::Initialize(); + Shot::Initialize(); + RadioTraffic::Initialize(); + + NetServerConfig* server_config = NetServerConfig::GetInstance(); + if (!server_config) + return false; + + ::Print("\n\n\nStarshatter Server Init\n"); + ::Print("-----------------------\n"); + ::Print("Server Name: %s\n", (const char*) server_config->Name()); + ::Print("Server Type: %d\n", server_config->GetGameType()); + + if (server_config->GetMission().length() > 0) + ::Print("Server Mission: %s\n", (const char*) server_config->GetMission()); + + ::Print("Lobby Server Port: %d\n", server_config->GetLobbyPort()); + ::Print("Admin Server Port: %d\n", server_config->GetAdminPort()); + ::Print("-----------------------\n"); + + NetLobbyServer* nls = new NetLobbyServer; + NetAdminServer* nas = NetAdminServer::GetInstance(server_config->GetAdminPort()); + nas->SetServerName(server_config->Name()); + + lobby_server = nls; + admin_server = nas; + + std::cout << "Started server listening on port " << server_config->GetLobbyPort() << std::endl; + + return true; +} + + +void +StarServer::SetGameMode(int m) +{ + if (game_mode == m) + return; + + if (m == LOAD_MODE) { + Print(" game_mode = LOAD_MODE\n"); + paused = true; + } + + else if (m == PLAY_MODE) { + Print(" game_mode = PLAY_MODE\n"); + + if (!world) { + CreateWorld(); + InstantiateMission(); + } + + // stand alone server should wait for players to connect + // before unpausing the simulation... + Clock::GetInstance()->SetTimeCompression(1.0); + Pause(true); + } + + else if (m == MENU_MODE) { + Print(" game_mode = MENU_MODE\n"); + paused = true; + + if (auto sim = dynamic_cast<Sim*>(world)) + sim->UnloadMission(); + } + + game_mode = m; +} + + +void +StarServer::CreateWorld() +{ + RadioTraffic::Initialize(); + + // create world + if (!world) { + world = new Sim(nullptr); + Print(" World Created.\n"); + } +} + + +void +StarServer::InstantiateMission() +{ + current_mission = nullptr; + + if (Campaign::GetCampaign()) { + current_mission = Campaign::GetCampaign()->GetMission(); + } + + if (auto sim = dynamic_cast<Sim*>(world)) { + sim->UnloadMission(); + + if (current_mission) { + sim->LoadMission(current_mission); + sim->ExecMission(); + sim->SetTestMode(false); + + Print(" Mission Instantiated.\n"); + std::cout << "Loaded mission: " << current_mission->Name() << std::endl; + } + + else { + Print(" *** WARNING: StarServer::InstantiateMission() - no mission selected ***\n"); + } + } +} + + +void +StarServer::UpdateWorld() +{ + Galaxy* galaxy = Galaxy::GetInstance(); + if (galaxy) galaxy->ExecFrame(); + + Campaign* campaign = Campaign::GetCampaign(); + if (campaign) campaign->ExecFrame(); + + if (paused) { + if (world) + world->ExecFrame(0); + } + + else { + Drive::StartFrame(); + + if (world) + world->ExecFrame(Clock::GetInstance()->Delta()); + } +} + + +void +StarServer::GameState() +{ + if (lobby_server) { + lobby_server->ExecFrame(); + + if (lobby_server->GetStatus() == NetServerInfo::PERSISTENT) + paused = NetGame::NumPlayers() < 1; + } + + if (game_mode == MENU_MODE) { + std::this_thread::sleep_for(std::chrono::milliseconds(30)); + } + else if (game_mode == LOAD_MODE) { + CreateWorld(); + InstantiateMission(); + + SetGameMode(PLAY_MODE); + } + else if (game_mode == PLAY_MODE) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + + +bool +StarServer::Server() const +{ + return true; +} diff --git a/Starserver/StarServer.h b/Starserver/StarServer.h new file mode 100644 index 0000000..0bcab06 --- /dev/null +++ b/Starserver/StarServer.h @@ -0,0 +1,54 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + +*/ + +#ifndef StarServer_h +#define StarServer_h + +#include "Game.h" +#include "NetLobbyServer.h" +#include "NetServer.h" +#include "Mission.h" +#include "Types.h" +#include "Universe.h" + + +class StarServer : public Game +{ +public: + static StarServer* GetInstance(); + + StarServer(); + virtual ~StarServer(); + + virtual bool Init(HINSTANCE hi, HINSTANCE hpi, LPSTR cmdline, int nCmdShow); + virtual bool InitGame(); + + virtual void UpdateWorld(); + virtual void GameState(); + + bool Server() const override; + void SetGameMode(int mode) override; + + void CreateWorld(); + +protected: + virtual void InstantiateMission(); + + Universe* world; + Mission* current_mission; + + NetServer* admin_server; + NetLobbyServer* lobby_server; + +private: + static StarServer* instance; +}; + + +#endif // StarServer_h |