net7/trunk/Net7Proxy/ServerManager.cpp
2014-05-11 16:54:16 -04:00

453 lines
No EOL
11 KiB
C++

// ServerManager.cpp
#include "Net7.h"
#include "ServerManager.h"
#include "SSL_Listener.h"
#include "TcpListener.h"
#include "MessageQueue.h"
#include "Connection.h"
#include "openssl/ssl.h"
// Constructor
ServerManager::ServerManager(bool is_master_server, unsigned long ip_address, short port, short max_sectors, bool standalone, unsigned long internal_ip_address)
:
m_IsMasterServer(is_master_server),
m_IpAddress(ip_address),
m_IpAddressInternal(internal_ip_address),
m_Port(port),
m_MaxSectors(max_sectors),
m_IsStandaloneServer(standalone)
{
m_LogFileTimer = 0;
m_LogFile = NULL;
m_ChatFileTimer = 0;
m_ChatFile = NULL;
m_AllowCreate = false;
m_DumpXML = false;
m_GlobalConnection = (0);
m_SectorConnection = (0);
m_ConnectionCount = 0;
}
// Destructor
ServerManager::~ServerManager()
{
}
// This is the entry point for running the server
void ServerManager::RunServer()
{
g_ServerMgr = this;
RunMasterServer();
}
void ServerManager::RunMasterServer()
{
SSL_Listener *ssl_listener = 0;
TcpListener *global_server_listener = 0;
if (g_LocalCert)
{
// Instantiate the SSL Listener object
ssl_listener = new SSL_Listener(m_IpAddressInternal, ssl_port, *this);
RegisterSectorServer(SECTOR_SERVER_PORT, m_MaxSectors);
// Instantiate the TCP Listener object for the Global Server
global_server_listener = new TcpListener(m_IpAddressInternal, GLOBAL_SERVER_PORT, *this, CONNECTION_TYPE_CLIENT_TO_GLOBAL_SERVER);
}
// Instantiate the TCP Listener object for the Master (galaxy) Server
TcpListener master_tcp_listener(m_IpAddressInternal, MASTER_SERVER_PORT, *this, CONNECTION_TYPE_CLIENT_TO_MASTER_SERVER);
//give ourselves 1 port for sector serving.
TcpListener sector_comms(m_IpAddressInternal, SECTOR_SERVER_PORT, *this, CONNECTION_TYPE_CLIENT_TO_SECTOR_SERVER);
MainLoop();
sector_comms.Shutdown();
if (g_LocalCert)
{
ssl_listener->Shutdown();
global_server_listener->Shutdown();
}
master_tcp_listener.Shutdown();
}
FILE *OpenLogFile(FILE *logfile, char *name)
{
// We have at least one message in the queue
if (!logfile)
{
// If the log file is not open, then open it
// Create log filename with the current date
SYSTEMTIME systime;
GetSystemTime(&systime);
char filename[MAX_PATH];
sprintf(filename, "%s_%04d_%02d_%02d.log", name, systime.wYear, systime.wMonth, systime.wDay);
logfile = fopen(filename, "a+");
}
return logfile;
}
void ServerManager::ServerCheck()
{
// called by the Main thread in MainLoop
// Kill any connections that have closed
m_ConnectionMgr.CheckConnections();
//m_ConnectionMgr.CheckSslConnections();
//===========================================
// Check for messages in the Server Log queue
//===========================================
if (m_LogFileTimer)
{
// if the log file has been idle for 2 seconds, close it
m_Mutex.Lock();
m_LogFileTimer--;
if (m_LogFileTimer == 0 && m_LogFile != NULL)
{
fclose(m_LogFile); // close the log file
m_LogFile = NULL; // forget the file handle
}
m_Mutex.Unlock();
}
//===========================================
// Check for messages in the Chat Msg queue
//===========================================
if (m_ChatFileTimer)
{
// if the chat file has been idle for 2 seconds, close it
m_Mutex.Lock();
m_ChatFileTimer--;
if (m_ChatFileTimer == 0 && m_ChatFile != NULL)
{
fclose(m_ChatFile); // close the chat file
m_ChatFile = NULL; // forget the file handle
}
m_Mutex.Unlock();
}
}
void ServerManager::MainLoop()
{
//LogMessage("Entering MainLoop\n");
while (!g_ServerShutdown)
{
// Loop 20x per second
Sleep(50);
ServerCheck();
}
if (m_LogFile)
{
fclose(m_LogFile);
m_LogFile = NULL;
}
// TODO: Use event notification to make this safe
// Wait for clean shutdown
Sleep(5000);
}
// This function formats a message and adds it to the message queue
void LogChatMsg(char *format, ...)
{
char buffer[8192];
char timestr[20];
time_t rawtime;
struct tm * timeinfo;
va_list args;
va_start(args, format);
_vsnprintf(buffer, 8192, format, args);
va_end(args);
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime(timestr, 18, "%d/%m/%y %H:%M:%S",timeinfo);
if (g_ServerMgr)
{
g_ServerMgr->ResetChatFileTimer(); //m_ChatFileTimer = 40;
g_ServerMgr->m_ChatFile = OpenLogFile(g_ServerMgr->m_ChatFile, g_LogFilename);
fprintf(g_ServerMgr->m_ChatFile, "%s %s", timestr , buffer);
}
}
void ServerManager::ResetChatFileTimer()
{
m_Mutex.Lock();
m_ChatFileTimer = 40;
m_Mutex.Unlock();
}
void ServerManager::ResetLogFileTimer()
{
m_Mutex.Lock();
m_LogFileTimer = 40;
m_Mutex.Unlock();
}
// This function formats a message and adds it to the message queue
void LogMessage(char *format, ...)
{
char buffer[8192];
char timestr[20];
time_t rawtime;
struct tm * timeinfo;
if (g_ServerShutdown) return;
va_list args;
va_start(args, format);
_vsnprintf(buffer, 8192, format, args);
va_end(args);
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime(timestr, 18, "%d/%m/%y %H:%M:%S",timeinfo);
//print and store - why do we try to buffer this anyway?
if (g_ServerMgr)
{
g_ServerMgr->ResetLogFileTimer();//m_LogFileTimer = 40;
g_ServerMgr->m_LogFile = OpenLogFile(g_ServerMgr->m_LogFile, g_LogFilename);
fprintf(g_ServerMgr->m_LogFile, "%s %s", timestr, buffer);
}
fprintf(stdout, "%s %s", timestr, buffer); //TODO: put this on a 'verbose' switch
}
void LogDebug(char *format, ...)
{
if (!g_Debug) return;
char buffer[8192];
char timestr[20];
time_t rawtime;
struct tm * timeinfo;
if (g_ServerShutdown) return;
va_list args;
va_start(args, format);
_vsnprintf(buffer, 8192, format, args);
va_end(args);
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime(timestr, 18, "%d/%m/%y %H:%M:%S",timeinfo);
if (g_ServerMgr)
{
g_ServerMgr->m_LogFile = OpenLogFile(g_ServerMgr->m_LogFile, g_LogFilename);
g_ServerMgr->m_LogFileTimer = 40;
fprintf(g_ServerMgr->m_LogFile, "%s %s", timestr , buffer);
}
}
void DumpBuffer(unsigned char *buffer, int length)
{
char line[128];
line[0] = 0;
for (int i = 0; i < length; i++)
{
//sprintf_s(line + strlen(line), 128, "%02X ", buffer[i]);
_snprintf(line + strlen(line), 128, "%02X ", buffer[i]);
if ((i % 16) == 15)
{
LogMessage("%s\n",line);
line[0] = 0;
}
}
if (line[0])
{
LogMessage("%s\n",line);
}
}
void DumpBufferToFile(unsigned char *buffer, int length, char *filename, bool rawData)
{
FILE *f = fopen(filename, "wb");
if (f)
{
if (rawData)
{
fwrite(buffer,1,length,f);
}
else
{
char line[128];
line[0] = 0;
for (int i = 0; i < length; i++)
{
_snprintf(line + strlen(line), 128, "%02X ", buffer[i]);
if ((i % 16) == 15)
{
fprintf(f, "%s\n", line);
line[0] = 0;
}
}
if (line[0])
{
fprintf(f, "%s\n", line);
}
}
LogMessage("Data written to %s\n",filename);
fclose(f);
}
else
{
LogMessage("Could not open %s\n",filename);
}
}
void ServerManager::SetUDPConnections(UDPClient *connection, UDPClient *send)
{
m_UDPConnection = send;
m_UDPClient = connection;
}
// This is called only for ONE instance of the sector manager
bool ServerManager::RegisterSectorServer(short first_port, short max_sectors)
{
char buffer[4096];
SSL_METHOD * ssl_client_method;
SSL_CTX * ssl_context;
SSL * ssl;
SSLeay_add_ssl_algorithms();
ssl_client_method = SSLv2_client_method();
SSL_load_error_strings();
ssl_context = SSL_CTX_new(ssl_client_method);
if (!ssl_context)
{
LogMessage("SSL_CTX_new failed\n");
return false;
}
// Establish a SSL connection to the Authentication Server
// Create a socket
SOCKET ssl_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ssl_socket == INVALID_SOCKET)
{
LogMessage("Unable to create outgoing SSL socket\n");
return false;
}
unsigned long ip_address = 0x0100007f;
//if (strstr(g_DomainName, "local") == 0)
//{
struct hostent * host;
if (strlen(g_InternalIP)==0)
host = gethostbyname(g_DomainName);
else
host = gethostbyname(g_InternalIP);
if (!host)
{
LogMessage("Unable to resolve IP address for %s\n", g_DomainName);
return false;
}
ip_address = *((unsigned long *) host->h_addr_list[0]);
//}
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = ip_address;
address.sin_port = htons(ssl_port);
unsigned char * ip = (unsigned char *) &ip_address;
LogMessage("Connecting to Authentication Server on %d.%d.%d.%d:%d\n",
ip[0], ip[1], ip[2], ip[3], ssl_port);
if (connect(ssl_socket, (struct sockaddr*) &address, sizeof(address)))
{
LogMessage("Unable to connect to Authentication Server on port %d\n", ssl_port);
return false;
}
//LogMessage("SSL Connected!\n");
ssl = SSL_new(ssl_context);
if (!ssl)
{
LogMessage("SSL_new failed\n");
return false;
}
SSL_set_fd(ssl, ssl_socket);
if (!SSL_connect(ssl))
{
LogMessage("SSL_connect failed\n");
return false;
}
// TODO: change this from a hard-coded username something that is set on the command line
// or a data file.
_snprintf(buffer, 128,
"GET /sectorserver.cgi?username=VectoR&port=%d&max_sectors=%d&version=%d.%d HTTP/1.1\r\n"
"User-Agent: AuthLogin\r\n"
"Host: %s\r\n"
"Connection: Keep-Alive\r\n"
"Cache-Control: no-cache\r\n"
"\r\n",
first_port,
max_sectors,
SECTOR_SERVER_MAJOR_VERSION,
SECTOR_SERVER_MINOR_VERSION,
g_DomainName);
//printf("------\n", buffer);
//printf("%s", buffer);
//printf("------\n", buffer);
//LogMessage("SectorManager calling SSL_write (%d bytes)\n", strlen(buffer) + 1);
if (SSL_write(ssl, buffer, strlen(buffer) + 1) == -1)
{
LogMessage("SSL_write failed\n");
return false;
}
//LogMessage("SectorManager calling SSL_read\n");
int bytes = SSL_read(ssl, buffer, sizeof(buffer) - 1);
if (bytes == -1)
{
LogMessage("SSL_read failed\n");
return false;
}
buffer[bytes] = 0;
/* Clean up. */
//LogMessage("SectorManager calling closesocket\n");
closesocket(ssl_socket);
//LogMessage("SectorManager calling SSL_free\n");
SSL_free(ssl);
//LogMessage("SectorManager calling SSL_CTX_free\n");
SSL_CTX_free(ssl_context);
if (strstr(buffer, "Success=TRUE") == 0)
{
LogMessage("Attempt to register the Sector Server failed\n");
LogMessage("SSL Response:%s\n", buffer);
return false;
}
//else
//{
// LogMessage("Successfully registered the Sector Server!\n");
//}
return true;
}