mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
TCP cleanup, added basis of web interface
This commit is contained in:
parent
08e72bbbdd
commit
124728e0c7
@ -16,8 +16,6 @@ SET(common_sources
|
||||
emu_legacy.cpp
|
||||
emu_limits.cpp
|
||||
emu_opcodes.cpp
|
||||
emu_tcp_connection.cpp
|
||||
emu_tcp_server.cpp
|
||||
emu_versions.cpp
|
||||
eqdb.cpp
|
||||
eqdb_res.cpp
|
||||
@ -67,12 +65,9 @@ SET(common_sources
|
||||
spdat.cpp
|
||||
string_util.cpp
|
||||
struct_strategy.cpp
|
||||
tcp_connection.cpp
|
||||
tcp_server.cpp
|
||||
textures.cpp
|
||||
timer.cpp
|
||||
unix.cpp
|
||||
worldconn.cpp
|
||||
xml_parser.cpp
|
||||
platform.cpp
|
||||
event/event_loop.cpp
|
||||
@ -100,17 +95,6 @@ SET(common_sources
|
||||
patches/titanium_limits.cpp
|
||||
patches/uf.cpp
|
||||
patches/uf_limits.cpp
|
||||
SocketLib/Base64.cpp
|
||||
SocketLib/File.cpp
|
||||
SocketLib/HttpdCookies.cpp
|
||||
SocketLib/HttpdForm.cpp
|
||||
SocketLib/HttpdSocket.cpp
|
||||
SocketLib/HTTPSocket.cpp
|
||||
SocketLib/MemFile.cpp
|
||||
SocketLib/Mime.cpp
|
||||
SocketLib/Parse.cpp
|
||||
SocketLib/socket_include.cpp
|
||||
SocketLib/Utility.cpp
|
||||
StackWalker/StackWalker.cpp
|
||||
tinyxml/tinystr.cpp
|
||||
tinyxml/tinyxml.cpp
|
||||
@ -138,8 +122,6 @@ SET(common_headers
|
||||
emu_limits.h
|
||||
emu_opcodes.h
|
||||
emu_oplist.h
|
||||
emu_tcp_connection.h
|
||||
emu_tcp_server.h
|
||||
emu_versions.h
|
||||
eq_constants.h
|
||||
eq_packet_structs.h
|
||||
@ -210,16 +192,12 @@ SET(common_headers
|
||||
spdat.h
|
||||
string_util.h
|
||||
struct_strategy.h
|
||||
tcp_basic_server.h
|
||||
tcp_connection.h
|
||||
tcp_server.h
|
||||
textures.h
|
||||
timer.h
|
||||
types.h
|
||||
unix.h
|
||||
useperl.h
|
||||
version.h
|
||||
worldconn.h
|
||||
xml_parser.h
|
||||
zone_numbers.h
|
||||
event/background_task.h
|
||||
@ -269,18 +247,6 @@ SET(common_headers
|
||||
patches/uf_limits.h
|
||||
patches/uf_ops.h
|
||||
patches/uf_structs.h
|
||||
SocketLib/Base64.h
|
||||
SocketLib/File.h
|
||||
SocketLib/HttpdCookies.h
|
||||
SocketLib/HttpdForm.h
|
||||
SocketLib/HttpdSocket.h
|
||||
SocketLib/HTTPSocket.h
|
||||
SocketLib/IFile.h
|
||||
SocketLib/MemFile.h
|
||||
SocketLib/Mime.h
|
||||
SocketLib/Parse.h
|
||||
SocketLib/socket_include.h
|
||||
SocketLib/Utility.h
|
||||
StackWalker/StackWalker.h
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
@ -374,32 +340,6 @@ SOURCE_GROUP(Patches FILES
|
||||
patches/uf_limits.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(SocketLib FILES
|
||||
SocketLib/Base64.h
|
||||
SocketLib/File.h
|
||||
SocketLib/HttpdCookies.h
|
||||
SocketLib/HttpdForm.h
|
||||
SocketLib/HttpdSocket.h
|
||||
SocketLib/HTTPSocket.h
|
||||
SocketLib/IFile.h
|
||||
SocketLib/MemFile.h
|
||||
SocketLib/Mime.h
|
||||
SocketLib/Parse.h
|
||||
SocketLib/socket_include.h
|
||||
SocketLib/Utility.h
|
||||
SocketLib/Base64.cpp
|
||||
SocketLib/File.cpp
|
||||
SocketLib/HttpdCookies.cpp
|
||||
SocketLib/HttpdForm.cpp
|
||||
SocketLib/HttpdSocket.cpp
|
||||
SocketLib/HTTPSocket.cpp
|
||||
SocketLib/MemFile.cpp
|
||||
SocketLib/Mime.cpp
|
||||
SocketLib/Parse.cpp
|
||||
SocketLib/socket_include.cpp
|
||||
SocketLib/Utility.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(StackWalker FILES
|
||||
StackWalker/StackWalker.h
|
||||
StackWalker/StackWalker.cpp
|
||||
|
||||
@ -1,818 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
There are really two or three different objects shoe-hored into this
|
||||
connection object. Sombody really needs to factor out the relay link
|
||||
crap into its own subclass of this object, it will clean things up
|
||||
tremendously.
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
#include "emu_tcp_connection.h"
|
||||
#include "emu_tcp_server.h"
|
||||
#include "../common/servertalk.h"
|
||||
|
||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
#define TCPN_DEBUG 0
|
||||
#define TCPN_DEBUG_Console 0
|
||||
#define TCPN_DEBUG_Memory 0
|
||||
#define TCPN_LOG_PACKETS 0
|
||||
#define TCPN_LOG_RAW_DATA_OUT 0
|
||||
#define TCPN_LOG_RAW_DATA_IN 0
|
||||
|
||||
|
||||
//server side case
|
||||
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET in_socket, uint32 irIP, uint16 irPort, bool iOldFormat)
|
||||
: TCPConnection(ID, in_socket, irIP, irPort),
|
||||
keepalive_timer(SERVER_TIMEOUT),
|
||||
timeout_timer(SERVER_TIMEOUT * 2)
|
||||
{
|
||||
id = 0;
|
||||
Server = nullptr;
|
||||
pOldFormat = iOldFormat;
|
||||
#ifdef MINILOGIN
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeLogin;
|
||||
#else
|
||||
if (pOldFormat)
|
||||
TCPMode = modePacket;
|
||||
else
|
||||
TCPMode = modeConsole;
|
||||
PacketMode = packetModeZone;
|
||||
#endif
|
||||
RelayLink = 0;
|
||||
RelayServer = false;
|
||||
RelayCount = 0;
|
||||
RemoteID = 0;
|
||||
|
||||
}
|
||||
|
||||
//client outgoing connection case (and client side relay)
|
||||
EmuTCPConnection::EmuTCPConnection(bool iOldFormat, EmuTCPServer* iRelayServer, eTCPMode iMode)
|
||||
: TCPConnection(),
|
||||
keepalive_timer(SERVER_TIMEOUT),
|
||||
timeout_timer(SERVER_TIMEOUT * 2)
|
||||
{
|
||||
Server = iRelayServer;
|
||||
if (Server)
|
||||
RelayServer = true;
|
||||
else
|
||||
RelayServer = false;
|
||||
RelayLink = 0;
|
||||
RelayCount = 0;
|
||||
RemoteID = 0;
|
||||
pOldFormat = iOldFormat;
|
||||
TCPMode = iMode;
|
||||
PacketMode = packetModeZone;
|
||||
#if TCPN_DEBUG_Memory >= 7
|
||||
std::cout << "Constructor #1 on outgoing TCP# " << GetID() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
//server side relay case
|
||||
EmuTCPConnection::EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort)
|
||||
: TCPConnection(ID, 0, irIP, irPort),
|
||||
keepalive_timer(SERVER_TIMEOUT),
|
||||
timeout_timer(SERVER_TIMEOUT * 2)
|
||||
{
|
||||
Server = iServer;
|
||||
RelayLink = iRelayLink;
|
||||
RelayServer = true;
|
||||
RelayCount = 0;
|
||||
RemoteID = iRemoteID;
|
||||
pOldFormat = false;
|
||||
ConnectionType = Incoming;
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeZone;
|
||||
#if TCPN_DEBUG_Memory >= 7
|
||||
std::cout << "Constructor #3 on outgoing TCP# " << GetID() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
EmuTCPConnection::~EmuTCPConnection() {
|
||||
//the queues free their content right now I believe.
|
||||
}
|
||||
|
||||
EmuTCPNetPacket_Struct* EmuTCPConnection::MakePacket(ServerPacket* pack, uint32 iDestination) {
|
||||
int32 size = sizeof(EmuTCPNetPacket_Struct) + pack->size;
|
||||
if (pack->compressed) {
|
||||
size += 4;
|
||||
}
|
||||
if (iDestination) {
|
||||
size += 4;
|
||||
}
|
||||
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) new uchar[size];
|
||||
tnps->size = size;
|
||||
tnps->opcode = pack->opcode;
|
||||
*((uint8*) &tnps->flags) = 0;
|
||||
uchar* buffer = tnps->buffer;
|
||||
if (pack->compressed) {
|
||||
tnps->flags.compressed = 1;
|
||||
*((int32*) buffer) = pack->InflatedSize;
|
||||
buffer += 4;
|
||||
}
|
||||
if (iDestination) {
|
||||
tnps->flags.destination = 1;
|
||||
*((int32*) buffer) = iDestination;
|
||||
buffer += 4;
|
||||
}
|
||||
memcpy(buffer, pack->pBuffer, pack->size);
|
||||
return tnps;
|
||||
}
|
||||
|
||||
SPackSendQueue* EmuTCPConnection::MakeOldPacket(ServerPacket* pack) {
|
||||
SPackSendQueue* spsq = (SPackSendQueue*) new uchar[sizeof(SPackSendQueue) + pack->size + 4];
|
||||
if (pack->pBuffer != 0 && pack->size != 0)
|
||||
memcpy((char *) &spsq->buffer[4], (char *) pack->pBuffer, pack->size);
|
||||
memcpy((char *) &spsq->buffer[0], (char *) &pack->opcode, 2);
|
||||
spsq->size = pack->size+4;
|
||||
memcpy((char *) &spsq->buffer[2], (char *) &spsq->size, 2);
|
||||
return spsq;
|
||||
}
|
||||
|
||||
bool EmuTCPConnection::SendPacket(ServerPacket* pack, uint32 iDestination) {
|
||||
if (!Connected())
|
||||
return false;
|
||||
eTCPMode tmp = GetMode();
|
||||
if (tmp != modePacket && tmp != modeTransition)
|
||||
return false;
|
||||
LockMutex lock(&MState);
|
||||
if (RemoteID)
|
||||
return RelayLink->SendPacket(pack, RemoteID);
|
||||
else if (pOldFormat) {
|
||||
#if TCPN_LOG_PACKETS >= 1
|
||||
if (pack && pack->opcode != 0) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Logging outgoing TCP OldPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
||||
#if TCPN_LOG_PACKETS == 2
|
||||
if (pack->size >= 32)
|
||||
DumpPacket(pack->pBuffer, 32);
|
||||
else
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
#if TCPN_LOG_PACKETS >= 3
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
SPackSendQueue* spsq = MakeOldPacket(pack);
|
||||
ServerSendQueuePushEnd(spsq->buffer, spsq->size);
|
||||
safe_delete_array(spsq);
|
||||
}
|
||||
else {
|
||||
EmuTCPNetPacket_Struct* tnps = MakePacket(pack, iDestination);
|
||||
if (tmp == modeTransition) {
|
||||
InModeQueuePush(tnps);
|
||||
}
|
||||
else {
|
||||
#if TCPN_LOG_PACKETS >= 1
|
||||
if (pack && pack->opcode != 0) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Logging outgoing TCP packet. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
||||
#if TCPN_LOG_PACKETS == 2
|
||||
if (pack->size >= 32)
|
||||
DumpPacket(pack->pBuffer, 32);
|
||||
else
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
#if TCPN_LOG_PACKETS >= 3
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
ServerSendQueuePushEnd((uchar**) &tnps, tnps->size);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmuTCPConnection::SendPacket(EmuTCPNetPacket_Struct* tnps) {
|
||||
if (RemoteID)
|
||||
return false;
|
||||
if (!Connected())
|
||||
return false;
|
||||
if (GetMode() != modePacket)
|
||||
return false;
|
||||
|
||||
LockMutex lock(&MState);
|
||||
eTCPMode tmp = GetMode();
|
||||
if (tmp == modeTransition) {
|
||||
EmuTCPNetPacket_Struct* tnps2 = (EmuTCPNetPacket_Struct*) new uchar[tnps->size];
|
||||
memcpy(tnps2, tnps, tnps->size);
|
||||
InModeQueuePush(tnps2);
|
||||
return true;
|
||||
}
|
||||
#if TCPN_LOG_PACKETS >= 1
|
||||
if (tnps && tnps->opcode != 0) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << tnps->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort();
|
||||
if (pOldFormat)
|
||||
std::cout << " (OldFormat)";
|
||||
std::cout << std::endl;
|
||||
#if TCPN_LOG_PACKETS == 2
|
||||
if (tnps->size >= 32)
|
||||
DumpPacket((uchar*) tnps, 32);
|
||||
else
|
||||
DumpPacket((uchar*) tnps, tnps->size);
|
||||
#endif
|
||||
#if TCPN_LOG_PACKETS >= 3
|
||||
DumpPacket((uchar*) tnps, tnps->size);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
ServerSendQueuePushEnd((const uchar*) tnps, tnps->size);
|
||||
return true;
|
||||
}
|
||||
|
||||
ServerPacket* EmuTCPConnection::PopPacket() {
|
||||
ServerPacket* ret;
|
||||
if (!MOutQueueLock.trylock())
|
||||
return nullptr;
|
||||
ret = OutQueue.pop();
|
||||
MOutQueueLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EmuTCPConnection::InModeQueuePush(EmuTCPNetPacket_Struct* tnps) {
|
||||
MSendQueue.lock();
|
||||
InModeQueue.push(tnps);
|
||||
MSendQueue.unlock();
|
||||
}
|
||||
|
||||
void EmuTCPConnection::OutQueuePush(ServerPacket* pack) {
|
||||
MOutQueueLock.lock();
|
||||
OutQueue.push(pack);
|
||||
MOutQueueLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
bool EmuTCPConnection::LineOutQueuePush(char* line) {
|
||||
#if defined(GOTFRAGS) && 0
|
||||
if (strcmp(line, "**CRASHME**") == 0) {
|
||||
int i = 0;
|
||||
std::cout << (5 / i) << std::endl;
|
||||
}
|
||||
#endif
|
||||
if(line[0] == '*') {
|
||||
if (strcmp(line, "**PACKETMODE**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODE**\r", 16);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeLogin;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
if (strcmp(line, "**PACKETMODEZONE**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODEZONE**\r", 20);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeZone;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
if (strcmp(line, "**PACKETMODELAUNCHER**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODELAUNCHER**\r", 24);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeLauncher;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
if (strcmp(line, "**PACKETMODEUCS**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODEUCS**\r", 19);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeUCS;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
if (strcmp(line, "**PACKETMODEQS**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODEQS**\r", 18);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeQueryServ;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(TCPConnection::LineOutQueuePush(line));
|
||||
}
|
||||
|
||||
void EmuTCPConnection::Disconnect(bool iSendRelayDisconnect) {
|
||||
TCPConnection::Disconnect();
|
||||
|
||||
if (RelayLink) {
|
||||
RelayLink->RemoveRelay(this, iSendRelayDisconnect);
|
||||
RelayLink = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) {
|
||||
if(!TCPConnection::ConnectIP(irIP, irPort, errbuf))
|
||||
return(false);
|
||||
|
||||
MSendQueue.lock();
|
||||
#ifdef MINILOGIN
|
||||
TCPMode = modePacket;
|
||||
#else
|
||||
if (pOldFormat) {
|
||||
TCPMode = modePacket;
|
||||
}
|
||||
else if (TCPMode == modePacket || TCPMode == modeTransition) {
|
||||
TCPMode = modeTransition;
|
||||
if(PacketMode == packetModeLauncher) {
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 24;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODELAUNCHER**\r", sendbuf_size);
|
||||
} else if(PacketMode == packetModeLogin) {
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 16;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODE**\r", sendbuf_size);
|
||||
} else if(PacketMode == packetModeUCS) {
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 19;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEUCS**\r", sendbuf_size);
|
||||
}
|
||||
else if(PacketMode == packetModeQueryServ) {
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 18;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size);
|
||||
}
|
||||
else {
|
||||
//default: packetModeZone
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 20;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEZONE**\r", sendbuf_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
MSendQueue.unlock();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void EmuTCPConnection::ClearBuffers() {
|
||||
TCPConnection::ClearBuffers();
|
||||
|
||||
LockMutex lock2(&MOutQueueLock);
|
||||
ServerPacket* pack = 0;
|
||||
while ((pack = OutQueue.pop()))
|
||||
safe_delete(pack);
|
||||
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop()))
|
||||
safe_delete(tnps);
|
||||
|
||||
keepalive_timer.Start();
|
||||
timeout_timer.Start();
|
||||
}
|
||||
|
||||
void EmuTCPConnection::SendNetErrorPacket(const char* reason) {
|
||||
#if TCPC_DEBUG >= 1
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
std::cout "NetError: '";
|
||||
if (reason)
|
||||
std::cout << reason;
|
||||
std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
|
||||
#endif
|
||||
auto pack = new ServerPacket(0);
|
||||
pack->size = 1;
|
||||
if (reason)
|
||||
pack->size += strlen(reason) + 1;
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
memset(pack->pBuffer, 0, pack->size);
|
||||
pack->pBuffer[0] = 255;
|
||||
strcpy((char *)&pack->pBuffer[1], reason);
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void EmuTCPConnection::RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect) {
|
||||
if (iSendRelayDisconnect) {
|
||||
auto pack = new ServerPacket(0, 5);
|
||||
pack->pBuffer[0] = 3;
|
||||
*((uint32*) &pack->pBuffer[1]) = relay->GetRemoteID();
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
RelayCount--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool EmuTCPConnection::ProcessReceivedData(char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
timeout_timer.Start();
|
||||
if (!recvbuf)
|
||||
return true;
|
||||
if (TCPMode == modePacket) {
|
||||
if (pOldFormat)
|
||||
return ProcessReceivedDataAsOldPackets(errbuf);
|
||||
else
|
||||
return ProcessReceivedDataAsPackets(errbuf);
|
||||
}
|
||||
//else, use the base class's text processing.
|
||||
bool ret = TCPConnection::ProcessReceivedData(errbuf);
|
||||
//see if we made the transition to packet mode...
|
||||
if(ret && TCPMode == modePacket) {
|
||||
return ProcessReceivedDataAsPackets(errbuf);
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool EmuTCPConnection::ProcessReceivedDataAsPackets(char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
int32 base = 0;
|
||||
int32 size = 7;
|
||||
uchar* buffer;
|
||||
ServerPacket* pack = 0;
|
||||
while ((recvbuf_used - base) >= size) {
|
||||
EmuTCPNetPacket_Struct* tnps = (EmuTCPNetPacket_Struct*) &recvbuf[base];
|
||||
buffer = tnps->buffer;
|
||||
size = tnps->size;
|
||||
if (size >= MaxTCPReceiveBuffferSize) {
|
||||
#if TCPN_DEBUG_Memory >= 1
|
||||
std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl;
|
||||
DumpPacket(&recvbuf[base], 16);
|
||||
#endif
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize");
|
||||
return false;
|
||||
}
|
||||
if ((recvbuf_used - base) >= size) {
|
||||
// ok, we got enough data to make this packet!
|
||||
pack = new ServerPacket;
|
||||
pack->size = size - sizeof(EmuTCPNetPacket_Struct);
|
||||
// read headers
|
||||
pack->opcode = tnps->opcode;
|
||||
if (tnps->flags.compressed) {
|
||||
pack->compressed = true;
|
||||
pack->InflatedSize = *((int32*)buffer);
|
||||
pack->size -= 4;
|
||||
buffer += 4;
|
||||
}
|
||||
if (tnps->flags.destination) {
|
||||
pack->destination = *((int32*)buffer);
|
||||
pack->size -= 4;
|
||||
buffer += 4;
|
||||
}
|
||||
// end read headers
|
||||
if (pack->size > 0) {
|
||||
if (tnps->flags.compressed) {
|
||||
// Lets decompress the packet here
|
||||
pack->compressed = false;
|
||||
pack->pBuffer = new uchar[pack->InflatedSize];
|
||||
pack->size = InflatePacket(buffer, pack->size, pack->pBuffer, pack->InflatedSize);
|
||||
}
|
||||
else {
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
memcpy(pack->pBuffer, buffer, pack->size);
|
||||
}
|
||||
}
|
||||
if (pack->opcode == 0) {
|
||||
if (pack->size) {
|
||||
#if TCPN_DEBUG >= 2
|
||||
std::cout << "Received TCP Network layer packet" << std::endl;
|
||||
#endif
|
||||
ProcessNetworkLayerPacket(pack);
|
||||
}
|
||||
#if TCPN_DEBUG >= 5
|
||||
else {
|
||||
std::cout << "Received TCP keepalive packet. (opcode=0)" << std::endl;
|
||||
}
|
||||
#endif
|
||||
// keepalive, no need to process
|
||||
safe_delete(pack);
|
||||
}
|
||||
else {
|
||||
#if TCPN_LOG_PACKETS >= 1
|
||||
if (pack && pack->opcode != 0) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Logging incoming TCP packet. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
||||
#if TCPN_LOG_PACKETS == 2
|
||||
if (pack->size >= 32)
|
||||
DumpPacket(pack->pBuffer, 32);
|
||||
else
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
#if TCPN_LOG_PACKETS >= 3
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (RelayServer && Server && pack->destination) {
|
||||
EmuTCPConnection* con = Server->FindConnection(pack->destination);
|
||||
if (!con) {
|
||||
#if TCPN_DEBUG >= 1
|
||||
std::cout << "Error relaying packet: con = 0" << std::endl;
|
||||
#endif
|
||||
safe_delete(pack);
|
||||
}
|
||||
else
|
||||
con->OutQueuePush(pack);
|
||||
}
|
||||
else
|
||||
OutQueuePush(pack);
|
||||
}
|
||||
base += size;
|
||||
size = 7;
|
||||
}
|
||||
}
|
||||
if (base != 0) {
|
||||
if (base >= recvbuf_used) {
|
||||
safe_delete_array(recvbuf);
|
||||
} else {
|
||||
auto tmpbuf = new uchar[recvbuf_size - base];
|
||||
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
|
||||
safe_delete_array(recvbuf);
|
||||
recvbuf = tmpbuf;
|
||||
recvbuf_used -= base;
|
||||
recvbuf_size -= base;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmuTCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) {
|
||||
int32 base = 0;
|
||||
int32 size = 4;
|
||||
uchar* buffer;
|
||||
ServerPacket* pack = 0;
|
||||
while ((recvbuf_used - base) >= size) {
|
||||
buffer = &recvbuf[base];
|
||||
memcpy(&size, &buffer[2], 2);
|
||||
if (size >= MaxTCPReceiveBuffferSize) {
|
||||
#if TCPN_DEBUG_Memory >= 1
|
||||
std::cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBuffferSize" << std::endl;
|
||||
#endif
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "EmuTCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBuffferSize");
|
||||
return false;
|
||||
}
|
||||
if ((recvbuf_used - base) >= size) {
|
||||
// ok, we got enough data to make this packet!
|
||||
pack = new ServerPacket;
|
||||
memcpy(&pack->opcode, &buffer[0], 2);
|
||||
pack->size = size - 4;
|
||||
/* if () { // TODO: Checksum or size check or something similar
|
||||
// Datastream corruption, get the hell outta here!
|
||||
delete pack;
|
||||
return false;
|
||||
}*/
|
||||
if (pack->size > 0) {
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
memcpy(pack->pBuffer, &buffer[4], pack->size);
|
||||
}
|
||||
if (pack->opcode == 0) {
|
||||
// keepalive, no need to process
|
||||
safe_delete(pack);
|
||||
}
|
||||
else {
|
||||
#if TCPN_LOG_PACKETS >= 1
|
||||
if (pack && pack->opcode != 0) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Logging incoming TCP OldPacket. OPCode: 0x" << std::hex << std::setw(4) << std::setfill('0') << pack->opcode << std::dec << ", size: " << std::setw(5) << std::setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << std::endl;
|
||||
#if TCPN_LOG_PACKETS == 2
|
||||
if (pack->size >= 32)
|
||||
DumpPacket(pack->pBuffer, 32);
|
||||
else
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
#if TCPN_LOG_PACKETS >= 3
|
||||
DumpPacket(pack);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
OutQueuePush(pack);
|
||||
}
|
||||
base += size;
|
||||
size = 4;
|
||||
}
|
||||
}
|
||||
if (base != 0) {
|
||||
if (base >= recvbuf_used) {
|
||||
safe_delete_array(recvbuf);
|
||||
}
|
||||
else {
|
||||
auto tmpbuf = new uchar[recvbuf_size - base];
|
||||
memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base);
|
||||
safe_delete_array(recvbuf);
|
||||
recvbuf = tmpbuf;
|
||||
recvbuf_used -= base;
|
||||
recvbuf_size -= base;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EmuTCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) {
|
||||
uint8 opcode = pack->pBuffer[0];
|
||||
uint8* data = &pack->pBuffer[1];
|
||||
switch (opcode) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: { // Switch to RelayServer mode
|
||||
if (pack->size != 1) {
|
||||
SendNetErrorPacket("New RelayClient: wrong size, expected 1");
|
||||
break;
|
||||
}
|
||||
if (RelayServer) {
|
||||
SendNetErrorPacket("Switch to RelayServer mode when already in RelayServer mode");
|
||||
break;
|
||||
}
|
||||
if (RemoteID) {
|
||||
SendNetErrorPacket("Switch to RelayServer mode by a Relay Client");
|
||||
break;
|
||||
}
|
||||
if (ConnectionType != Incoming) {
|
||||
SendNetErrorPacket("Switch to RelayServer mode on outgoing connection");
|
||||
break;
|
||||
}
|
||||
#if TCPC_DEBUG >= 3
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
std::cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << std::endl;
|
||||
#endif
|
||||
RelayServer = true;
|
||||
break;
|
||||
}
|
||||
case 2: { // New Relay Client
|
||||
if (!RelayServer) {
|
||||
SendNetErrorPacket("New RelayClient when not in RelayServer mode");
|
||||
break;
|
||||
}
|
||||
if (pack->size != 11) {
|
||||
SendNetErrorPacket("New RelayClient: wrong size, expected 11");
|
||||
break;
|
||||
}
|
||||
if (ConnectionType != Incoming) {
|
||||
SendNetErrorPacket("New RelayClient: illegal on outgoing connection");
|
||||
break;
|
||||
}
|
||||
auto con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32 *)data),
|
||||
*((uint32 *)&data[4]), *((uint16 *)&data[8]));
|
||||
Server->AddConnection(con);
|
||||
RelayCount++;
|
||||
break;
|
||||
}
|
||||
case 3: { // Delete Relay Client
|
||||
if (!RelayServer) {
|
||||
SendNetErrorPacket("Delete RelayClient when not in RelayServer mode");
|
||||
break;
|
||||
}
|
||||
if (pack->size != 5) {
|
||||
SendNetErrorPacket("Delete RelayClient: wrong size, expected 5");
|
||||
break;
|
||||
}
|
||||
EmuTCPConnection* con = Server->FindConnection(*((uint32*)data));
|
||||
if (con) {
|
||||
if (ConnectionType == Incoming) {
|
||||
if (con->GetRelayLink() != this) {
|
||||
SendNetErrorPacket("Delete RelayClient: RelayLink != this");
|
||||
break;
|
||||
}
|
||||
}
|
||||
con->Disconnect(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 255: {
|
||||
#if TCPC_DEBUG >= 1
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
std::cout "Received NetError: '";
|
||||
if (pack->size > 1)
|
||||
std::cout << (char*) data;
|
||||
std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EmuTCPConnection::SendData(bool &sent_something, char* errbuf) {
|
||||
sent_something = false;
|
||||
if(!TCPConnection::SendData(sent_something, errbuf))
|
||||
return(false);
|
||||
|
||||
if(sent_something)
|
||||
keepalive_timer.Start();
|
||||
else if (TCPMode == modePacket && keepalive_timer.Check()) {
|
||||
auto pack = new ServerPacket(0, 0);
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
#if TCPN_DEBUG >= 5
|
||||
std::cout << "Sending TCP keepalive packet. (timeout=" << timeout_timer.GetRemainingTime() << " remaining)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool EmuTCPConnection::RecvData(char* errbuf) {
|
||||
if(!TCPConnection::RecvData(errbuf)) {
|
||||
if (OutQueue.count())
|
||||
return(true);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
if ((TCPMode == modePacket || TCPMode == modeTransition) && timeout_timer.Check()) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
#ifndef EmuTCPCONNECTION_H_
|
||||
#define EmuTCPCONNECTION_H_
|
||||
|
||||
#include "tcp_connection.h"
|
||||
#include "timer.h"
|
||||
|
||||
//moved out of TCPConnection:: to be more exportable
|
||||
#pragma pack(1)
|
||||
struct EmuTCPNetPacket_Struct {
|
||||
uint32 size;
|
||||
struct {
|
||||
uint8
|
||||
compressed : 1,
|
||||
destination : 1,
|
||||
flag3 : 1,
|
||||
flag4 : 1,
|
||||
flag5 : 1,
|
||||
flag6 : 1,
|
||||
flag7 : 1,
|
||||
flag8 : 1;
|
||||
} flags;
|
||||
uint16 opcode;
|
||||
uchar buffer[0];
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
struct SPackSendQueue;
|
||||
class EmuTCPServer;
|
||||
class ServerPacket;
|
||||
|
||||
class EmuTCPConnection : public TCPConnection {
|
||||
public:
|
||||
enum eTCPMode { modeConsole, modeTransition, modePacket };
|
||||
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ };
|
||||
|
||||
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false);
|
||||
EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
|
||||
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, EmuTCPConnection* iRelayLink, uint32 iRemoteID, uint32 irIP, uint16 irPort); // for relay connections
|
||||
virtual ~EmuTCPConnection();
|
||||
|
||||
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
|
||||
virtual void Disconnect(bool iSendRelayDisconnect = true);
|
||||
|
||||
static EmuTCPNetPacket_Struct* MakePacket(ServerPacket* pack, uint32 iDestination = 0);
|
||||
static SPackSendQueue* MakeOldPacket(ServerPacket* pack);
|
||||
|
||||
virtual bool SendPacket(ServerPacket* pack, uint32 iDestination = 0);
|
||||
virtual bool SendPacket(EmuTCPNetPacket_Struct* tnps);
|
||||
ServerPacket* PopPacket(); // OutQueuePop()
|
||||
void SetPacketMode(ePacketMode mode) { PacketMode = mode; }
|
||||
|
||||
eTCPMode GetMode() const { return TCPMode; }
|
||||
ePacketMode GetPacketMode() const { return(PacketMode); }
|
||||
|
||||
//relay crap:
|
||||
inline bool IsRelayServer() const { return RelayServer; }
|
||||
inline TCPConnection* GetRelayLink() const { return RelayLink; }
|
||||
inline uint32 GetRemoteID() const { return RemoteID; }
|
||||
|
||||
protected:
|
||||
void OutQueuePush(ServerPacket* pack);
|
||||
void RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect);
|
||||
|
||||
void SendNetErrorPacket(const char* reason = 0);
|
||||
|
||||
virtual bool SendData(bool &sent_something, char* errbuf = 0);
|
||||
virtual bool RecvData(char* errbuf = 0);
|
||||
|
||||
virtual bool ProcessReceivedData(char* errbuf = 0);
|
||||
bool ProcessReceivedDataAsPackets(char* errbuf = 0);
|
||||
bool ProcessReceivedDataAsOldPackets(char* errbuf = 0);
|
||||
void ProcessNetworkLayerPacket(ServerPacket* pack);
|
||||
|
||||
virtual bool LineOutQueuePush(char* line);
|
||||
virtual void ClearBuffers();
|
||||
|
||||
EmuTCPServer* Server;
|
||||
|
||||
eTCPMode TCPMode;
|
||||
ePacketMode PacketMode;
|
||||
bool pOldFormat;
|
||||
|
||||
Timer keepalive_timer;
|
||||
Timer timeout_timer;
|
||||
|
||||
//relay crap:
|
||||
EmuTCPConnection* RelayLink;
|
||||
int32 RelayCount;
|
||||
bool RelayServer;
|
||||
uint32 RemoteID;
|
||||
|
||||
//input queue...
|
||||
void InModeQueuePush(EmuTCPNetPacket_Struct* tnps);
|
||||
MyQueue<EmuTCPNetPacket_Struct> InModeQueue;
|
||||
|
||||
//output queue...
|
||||
MyQueue<ServerPacket> OutQueue;
|
||||
Mutex MOutQueueLock;
|
||||
};
|
||||
|
||||
#endif /*EmuTCPCONNECTION_H_*/
|
||||
|
||||
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
#include "global_define.h"
|
||||
#include "emu_tcp_server.h"
|
||||
#include "emu_tcp_connection.h"
|
||||
|
||||
EmuTCPServer::EmuTCPServer(uint16 iPort, bool iOldFormat)
|
||||
: TCPServer<EmuTCPConnection>(iPort),
|
||||
pOldFormat(iOldFormat)
|
||||
{
|
||||
}
|
||||
|
||||
EmuTCPServer::~EmuTCPServer() {
|
||||
MInQueue.lock();
|
||||
while(!m_InQueue.empty()) {
|
||||
delete m_InQueue.front();
|
||||
m_InQueue.pop();
|
||||
}
|
||||
MInQueue.unlock();
|
||||
}
|
||||
|
||||
void EmuTCPServer::Process() {
|
||||
CheckInQueue();
|
||||
TCPServer<EmuTCPConnection>::Process();
|
||||
}
|
||||
|
||||
void EmuTCPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
||||
{
|
||||
auto conn = new EmuTCPConnection(ID, this, in_socket, irIP, irPort, pOldFormat);
|
||||
AddConnection(conn);
|
||||
}
|
||||
|
||||
|
||||
void EmuTCPServer::SendPacket(ServerPacket* pack) {
|
||||
EmuTCPNetPacket_Struct* tnps = EmuTCPConnection::MakePacket(pack);
|
||||
SendPacket(&tnps);
|
||||
}
|
||||
|
||||
void EmuTCPServer::SendPacket(EmuTCPNetPacket_Struct** tnps) {
|
||||
MInQueue.lock();
|
||||
m_InQueue.push(*tnps);
|
||||
MInQueue.unlock();
|
||||
tnps = nullptr;
|
||||
}
|
||||
|
||||
void EmuTCPServer::CheckInQueue() {
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
|
||||
while (( tnps = InQueuePop() )) {
|
||||
vitr cur, end;
|
||||
cur = m_list.begin();
|
||||
end = m_list.end();
|
||||
for(; cur != end; cur++) {
|
||||
if ((*cur)->GetMode() != EmuTCPConnection::modeConsole && (*cur)->GetRemoteID() == 0)
|
||||
(*cur)->SendPacket(tnps);
|
||||
}
|
||||
safe_delete(tnps);
|
||||
}
|
||||
}
|
||||
|
||||
EmuTCPNetPacket_Struct* EmuTCPServer::InQueuePop() {
|
||||
EmuTCPNetPacket_Struct* ret = nullptr;
|
||||
MInQueue.lock();
|
||||
if(!m_InQueue.empty()) {
|
||||
ret = m_InQueue.front();
|
||||
m_InQueue.pop();
|
||||
}
|
||||
MInQueue.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
EmuTCPConnection *EmuTCPServer::FindConnection(uint32 iID) {
|
||||
vitr cur, end;
|
||||
cur = m_list.begin();
|
||||
end = m_list.end();
|
||||
for(; cur != end; cur++) {
|
||||
if ((*cur)->GetID() == iID)
|
||||
return *cur;
|
||||
}
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
#ifndef EmuTCPSERVER_H_
|
||||
#define EmuTCPSERVER_H_
|
||||
|
||||
#include "tcp_server.h"
|
||||
|
||||
class EmuTCPConnection;
|
||||
struct EmuTCPNetPacket_Struct;
|
||||
class ServerPacket;
|
||||
|
||||
class EmuTCPServer : public TCPServer<EmuTCPConnection> {
|
||||
public:
|
||||
EmuTCPServer(uint16 iPort = 0, bool iOldFormat = false);
|
||||
virtual ~EmuTCPServer();
|
||||
|
||||
//packet broadcast routines.
|
||||
void SendPacket(ServerPacket* pack);
|
||||
void SendPacket(EmuTCPNetPacket_Struct** tnps);
|
||||
|
||||
//special crap for relay management
|
||||
EmuTCPConnection *FindConnection(uint32 iID);
|
||||
|
||||
//exposed for some crap we pull. Do not call from outside this object.
|
||||
using TCPServer<EmuTCPConnection>::AddConnection;
|
||||
|
||||
protected:
|
||||
virtual void Process();
|
||||
|
||||
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
|
||||
|
||||
bool pOldFormat;
|
||||
|
||||
//broadcast packet queue..
|
||||
void CheckInQueue();
|
||||
Mutex MInQueue;
|
||||
EmuTCPNetPacket_Struct* InQueuePop(); //returns ownership
|
||||
std::queue<EmuTCPNetPacket_Struct *> m_InQueue;
|
||||
};
|
||||
#endif /*EmuTCPSERVER_H_*/
|
||||
@ -32,7 +32,6 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
|
||||
out.PutUInt16(4, opcode);
|
||||
|
||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
||||
|
||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
||||
@ -218,6 +217,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
Log.OutF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
|
||||
@ -235,7 +235,6 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
}
|
||||
}
|
||||
@ -293,6 +292,7 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_encrypted) {
|
||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
Log.OutF(Logs::General, Logs::Error, "Error decrypting message from client");
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
#define ServerOP_ItemStatus 0x002C
|
||||
#define ServerOP_OOCMute 0x002D
|
||||
#define ServerOP_Revoke 0x002E
|
||||
//#define 0x002F
|
||||
#define ServerOP_WebInterfaceCall 0x002F
|
||||
#define ServerOP_GroupIDReq 0x0030
|
||||
#define ServerOP_GroupIDReply 0x0031
|
||||
#define ServerOP_GroupLeave 0x0032 // for disbanding out of zone folks
|
||||
@ -227,7 +227,7 @@ public:
|
||||
|
||||
ServerPacket(uint16 in_opcode, const EQ::Net::Packet &p) {
|
||||
this->compressed = false;
|
||||
size = p.Length();
|
||||
size = (uint32)p.Length();
|
||||
opcode = in_opcode;
|
||||
if (size == 0) {
|
||||
pBuffer = 0;
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
#ifndef TCPBASICSERVER_H_
|
||||
#define TCPBASICSERVER_H_
|
||||
|
||||
#include "tcp_server.h"
|
||||
#include "tcp_connection.h"
|
||||
|
||||
class TCPBasicServer : public TCPServer<TCPConnection> {
|
||||
public:
|
||||
inline TCPBasicServer(uint16 iPort = 0) : TCPServer<TCPConnection>(iPort) { }
|
||||
inline virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) {
|
||||
TCPConnection *conn = new TCPConnection(ID, in_socket, irIP, irPort);
|
||||
AddConnection(conn);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*TCPBASICSERVER_H_*/
|
||||
|
||||
@ -1,942 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <iomanip>
|
||||
|
||||
#include "tcp_connection.h"
|
||||
|
||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
#ifdef DARWIN
|
||||
#define MSG_NOSIGNAL SO_NOSIGPIPE // Corysia Taware - Sept. 27, 2013
|
||||
// See http://lists.apple.com/archives/macnetworkprog/2002/Dec/msg00091.html
|
||||
#endif // DARWIN
|
||||
|
||||
#ifdef _WINDOWS
|
||||
InitWinsock winsock;
|
||||
#endif
|
||||
|
||||
#define LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
|
||||
|
||||
#define TCPN_DEBUG 0
|
||||
#define TCPN_DEBUG_Console 0
|
||||
#define TCPN_DEBUG_Memory 0
|
||||
#define TCPN_LOG_RAW_DATA_OUT 0 //1 = info, 2 = length limited dump, 3 = full dump
|
||||
#define TCPN_LOG_RAW_DATA_IN 0 //1 = info, 2 = length limited dump, 3 = full dump
|
||||
|
||||
//client version
|
||||
TCPConnection::TCPConnection()
|
||||
: ConnectionType(Outgoing),
|
||||
connection_socket(0),
|
||||
id(0),
|
||||
rIP(0),
|
||||
rPort(0)
|
||||
{
|
||||
pState = TCPS_Ready;
|
||||
pFree = false;
|
||||
pEcho = false;
|
||||
recvbuf = nullptr;
|
||||
sendbuf = nullptr;
|
||||
pRunLoop = false;
|
||||
charAsyncConnect = 0;
|
||||
pAsyncConnect = false;
|
||||
m_previousLineEnd = false;
|
||||
#if TCPN_DEBUG_Memory >= 7
|
||||
std::cout << "Constructor #2 on outgoing TCP# " << GetID() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
//server version
|
||||
TCPConnection::TCPConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
||||
: ConnectionType(Incoming),
|
||||
connection_socket(in_socket),
|
||||
id(ID),
|
||||
rIP(irIP),
|
||||
rPort(irPort)
|
||||
{
|
||||
pState = TCPS_Connected;
|
||||
pFree = false;
|
||||
pEcho = false;
|
||||
recvbuf = nullptr;
|
||||
sendbuf = nullptr;
|
||||
pRunLoop = false;
|
||||
charAsyncConnect = 0;
|
||||
pAsyncConnect = false;
|
||||
m_previousLineEnd = false;
|
||||
#if TCPN_DEBUG_Memory >= 7
|
||||
std::cout << "Constructor #2 on incoming TCP# " << GetID() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
TCPConnection::~TCPConnection() {
|
||||
FinishDisconnect();
|
||||
ClearBuffers();
|
||||
if (ConnectionType == Outgoing) {
|
||||
MRunLoop.lock();
|
||||
pRunLoop = false;
|
||||
MRunLoop.unlock();
|
||||
MLoopRunning.lock();
|
||||
MLoopRunning.unlock();
|
||||
#if TCPN_DEBUG_Memory >= 6
|
||||
std::cout << "Deconstructor on outgoing TCP# " << GetID() << std::endl;
|
||||
#endif
|
||||
}
|
||||
#if TCPN_DEBUG_Memory >= 5
|
||||
else {
|
||||
std::cout << "Deconstructor on incoming TCP# " << GetID() << std::endl;
|
||||
}
|
||||
#endif
|
||||
safe_delete_array(recvbuf);
|
||||
safe_delete_array(sendbuf);
|
||||
safe_delete_array(charAsyncConnect);
|
||||
}
|
||||
|
||||
void TCPConnection::SetState(State_t in_state) {
|
||||
MState.lock();
|
||||
pState = in_state;
|
||||
MState.unlock();
|
||||
}
|
||||
|
||||
TCPConnection::State_t TCPConnection::GetState() const {
|
||||
State_t ret;
|
||||
MState.lock();
|
||||
ret = pState;
|
||||
MState.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TCPConnection::GetSockName(char *host, uint16 *port)
|
||||
{
|
||||
bool result=false;
|
||||
LockMutex lock(&MState);
|
||||
if (!Connected())
|
||||
return false;
|
||||
|
||||
struct sockaddr_in local;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
int addrlen;
|
||||
#else
|
||||
#ifdef FREEBSD
|
||||
socklen_t addrlen;
|
||||
#else
|
||||
size_t addrlen;
|
||||
#endif
|
||||
#endif
|
||||
addrlen=sizeof(struct sockaddr_in);
|
||||
#ifdef _WINDOWS
|
||||
if (!getsockname(connection_socket,(struct sockaddr *)&local,&addrlen)) {
|
||||
#else
|
||||
if (!getsockname(connection_socket,(struct sockaddr *)&local,(socklen_t *)&addrlen)) {
|
||||
#endif
|
||||
unsigned long ip=local.sin_addr.s_addr;
|
||||
sprintf(host,"%d.%d.%d.%d",
|
||||
*(unsigned char *)&ip,
|
||||
*((unsigned char *)&ip+1),
|
||||
*((unsigned char *)&ip+2),
|
||||
*((unsigned char *)&ip+3));
|
||||
*port=ntohs(local.sin_port);
|
||||
|
||||
result=true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TCPConnection::Free() {
|
||||
Disconnect();
|
||||
pFree = true;
|
||||
}
|
||||
|
||||
bool TCPConnection::Send(const uchar* data, int32 size) {
|
||||
if (!Connected())
|
||||
return false;
|
||||
if (!size)
|
||||
return true;
|
||||
ServerSendQueuePushEnd(data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPConnection::ServerSendQueuePushEnd(const uchar* data, int32 size) {
|
||||
MSendQueue.lock();
|
||||
if (sendbuf == nullptr) {
|
||||
sendbuf = new uchar[size];
|
||||
sendbuf_size = size;
|
||||
sendbuf_used = 0;
|
||||
}
|
||||
else if (size > (sendbuf_size - sendbuf_used)) {
|
||||
sendbuf_size += size + 1024;
|
||||
auto tmp = new uchar[sendbuf_size];
|
||||
memcpy(tmp, sendbuf, sendbuf_used);
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf = tmp;
|
||||
}
|
||||
memcpy(&sendbuf[sendbuf_used], data, size);
|
||||
sendbuf_used += size;
|
||||
MSendQueue.unlock();
|
||||
}
|
||||
|
||||
void TCPConnection::ServerSendQueuePushEnd(uchar** data, int32 size) {
|
||||
MSendQueue.lock();
|
||||
if (sendbuf == 0) {
|
||||
sendbuf = *data;
|
||||
sendbuf_size = size;
|
||||
sendbuf_used = size;
|
||||
MSendQueue.unlock();
|
||||
*data = 0;
|
||||
return;
|
||||
}
|
||||
if (size > (sendbuf_size - sendbuf_used)) {
|
||||
sendbuf_size += size;
|
||||
auto tmp = new uchar[sendbuf_size];
|
||||
memcpy(tmp, sendbuf, sendbuf_used);
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf = tmp;
|
||||
}
|
||||
memcpy(&sendbuf[sendbuf_used], *data, size);
|
||||
sendbuf_used += size;
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(*data);
|
||||
}
|
||||
|
||||
void TCPConnection::ServerSendQueuePushFront(uchar* data, int32 size) {
|
||||
MSendQueue.lock();
|
||||
if (sendbuf == 0) {
|
||||
sendbuf = new uchar[size];
|
||||
sendbuf_size = size;
|
||||
sendbuf_used = 0;
|
||||
}
|
||||
else if (size > (sendbuf_size - sendbuf_used)) {
|
||||
sendbuf_size += size;
|
||||
auto tmp = new uchar[sendbuf_size];
|
||||
memcpy(&tmp[size], sendbuf, sendbuf_used);
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf = tmp;
|
||||
}
|
||||
memcpy(sendbuf, data, size);
|
||||
sendbuf_used += size;
|
||||
MSendQueue.unlock();
|
||||
}
|
||||
|
||||
bool TCPConnection::ServerSendQueuePop(uchar** data, int32* size) {
|
||||
bool ret;
|
||||
if (!MSendQueue.trylock())
|
||||
return false;
|
||||
if (sendbuf) {
|
||||
*data = sendbuf;
|
||||
*size = sendbuf_used;
|
||||
sendbuf = 0;
|
||||
ret = true;
|
||||
}
|
||||
else {
|
||||
ret = false;
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TCPConnection::ServerSendQueuePopForce(uchar** data, int32* size) {
|
||||
bool ret;
|
||||
MSendQueue.lock();
|
||||
if (sendbuf) {
|
||||
*data = sendbuf;
|
||||
*size = sendbuf_used;
|
||||
sendbuf = 0;
|
||||
ret = true;
|
||||
}
|
||||
else {
|
||||
ret = false;
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* TCPConnection::PopLine() {
|
||||
char* ret;
|
||||
if (!MLineOutQueue.trylock())
|
||||
return 0;
|
||||
ret = (char*) LineOutQueue.pop();
|
||||
MLineOutQueue.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TCPConnection::LineOutQueuePush(char* line) {
|
||||
MLineOutQueue.lock();
|
||||
LineOutQueue.push(line);
|
||||
MLineOutQueue.unlock();
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
void TCPConnection::FinishDisconnect() {
|
||||
MState.lock();
|
||||
if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
|
||||
if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) {
|
||||
bool sent_something = false;
|
||||
SendData(sent_something);
|
||||
}
|
||||
pState = TCPS_Closing;
|
||||
shutdown(connection_socket, 0x01);
|
||||
shutdown(connection_socket, 0x00);
|
||||
#ifdef _WINDOWS
|
||||
closesocket(connection_socket);
|
||||
#else
|
||||
close(connection_socket);
|
||||
#endif
|
||||
connection_socket = 0;
|
||||
rIP = 0;
|
||||
rPort = 0;
|
||||
ClearBuffers();
|
||||
}
|
||||
pState = TCPS_Disconnected;
|
||||
MState.unlock();
|
||||
}
|
||||
|
||||
void TCPConnection::Disconnect() {
|
||||
MState.lock();
|
||||
if(pState == TCPS_Connected || pState == TCPS_Connecting) {
|
||||
pState = TCPS_Disconnecting;
|
||||
}
|
||||
MState.unlock();
|
||||
}
|
||||
|
||||
bool TCPConnection::GetAsyncConnect() {
|
||||
bool ret;
|
||||
MAsyncConnect.lock();
|
||||
ret = pAsyncConnect;
|
||||
MAsyncConnect.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TCPConnection::SetAsyncConnect(bool iValue) {
|
||||
bool ret;
|
||||
MAsyncConnect.lock();
|
||||
ret = pAsyncConnect;
|
||||
pAsyncConnect = iValue;
|
||||
MAsyncConnect.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TCPConnection::ConnectReady() const {
|
||||
State_t s = GetState();
|
||||
if (s != TCPS_Ready && s != TCPS_Disconnected)
|
||||
return(false);
|
||||
return(ConnectionType == Outgoing);
|
||||
}
|
||||
|
||||
void TCPConnection::AsyncConnect(const char* irAddress, uint16 irPort) {
|
||||
safe_delete_array(charAsyncConnect);
|
||||
charAsyncConnect = new char[strlen(irAddress) + 1];
|
||||
strcpy(charAsyncConnect, irAddress);
|
||||
AsyncConnect((uint32) 0, irPort);
|
||||
}
|
||||
|
||||
void TCPConnection::AsyncConnect(uint32 irIP, uint16 irPort) {
|
||||
if (ConnectionType != Outgoing) {
|
||||
// If this code runs, we got serious problems
|
||||
// Crash and burn.
|
||||
return;
|
||||
}
|
||||
if(!ConnectReady()) {
|
||||
#if TCPN_DEBUG > 0
|
||||
printf("Trying to do async connect in invalid state %s\n", GetState());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
MAsyncConnect.lock();
|
||||
if (pAsyncConnect) {
|
||||
MAsyncConnect.unlock();
|
||||
#if TCPN_DEBUG > 0
|
||||
printf("Trying to do async connect when already doing one.\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#if TCPN_DEBUG > 0
|
||||
printf("Start async connect.\n");
|
||||
#endif
|
||||
pAsyncConnect = true;
|
||||
if(irIP != 0)
|
||||
safe_delete_array(charAsyncConnect);
|
||||
rIP = irIP;
|
||||
rPort = irPort;
|
||||
MAsyncConnect.unlock();
|
||||
if (!pRunLoop) {
|
||||
pRunLoop = true;
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(TCPConnectionLoop, 0, this);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, TCPConnectionLoop, this);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool TCPConnection::Connect(const char* irAddress, uint16 irPort, char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
uint32 tmpIP = ResolveIP(irAddress);
|
||||
if (!tmpIP) {
|
||||
if (errbuf) {
|
||||
#ifdef _WINDOWS
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
|
||||
#else
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return ConnectIP(tmpIP, irPort, errbuf);
|
||||
}
|
||||
|
||||
bool TCPConnection::ConnectIP(uint32 in_ip, uint16 in_port, char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
if (ConnectionType != Outgoing) {
|
||||
// If this code runs, we got serious problems
|
||||
// Crash and burn.
|
||||
return false;
|
||||
}
|
||||
MState.lock();
|
||||
if (ConnectReady()) {
|
||||
pState = TCPS_Connecting;
|
||||
} else {
|
||||
MState.unlock();
|
||||
SetAsyncConnect(false);
|
||||
return false;
|
||||
}
|
||||
MState.unlock();
|
||||
if (!pRunLoop) {
|
||||
pRunLoop = true;
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(TCPConnectionLoop, 0, this);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, TCPConnectionLoop, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
connection_socket = INVALID_SOCKET;
|
||||
struct sockaddr_in server_sin;
|
||||
//struct in_addr in;
|
||||
|
||||
if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
|
||||
#ifdef _WINDOWS
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
|
||||
#else
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
|
||||
#endif
|
||||
SetState(TCPS_Ready);
|
||||
SetAsyncConnect(false);
|
||||
return false;
|
||||
}
|
||||
server_sin.sin_family = AF_INET;
|
||||
server_sin.sin_addr.s_addr = in_ip;
|
||||
server_sin.sin_port = htons(in_port);
|
||||
|
||||
// Establish a connection to the server socket.
|
||||
#ifdef _WINDOWS
|
||||
if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
|
||||
closesocket(connection_socket);
|
||||
connection_socket = 0;
|
||||
SetState(TCPS_Ready);
|
||||
SetAsyncConnect(false);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
|
||||
close(connection_socket);
|
||||
connection_socket = 0;
|
||||
SetState(TCPS_Ready);
|
||||
SetAsyncConnect(false);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
|
||||
setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
||||
#ifdef _WINDOWS
|
||||
unsigned long nonblocking = 1;
|
||||
ioctlsocket(connection_socket, FIONBIO, &nonblocking);
|
||||
#else
|
||||
fcntl(connection_socket, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
SetEcho(false);
|
||||
ClearBuffers();
|
||||
|
||||
rIP = in_ip;
|
||||
rPort = in_port;
|
||||
SetState(TCPS_Connected);
|
||||
SetAsyncConnect(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPConnection::ClearBuffers() {
|
||||
LockMutex lock1(&MSendQueue);
|
||||
LockMutex lock3(&MRunLoop);
|
||||
LockMutex lock4(&MState);
|
||||
safe_delete_array(recvbuf);
|
||||
safe_delete_array(sendbuf);
|
||||
|
||||
char* line = 0;
|
||||
while ((line = LineOutQueue.pop()))
|
||||
safe_delete_array(line);
|
||||
}
|
||||
|
||||
bool TCPConnection::CheckNetActive() {
|
||||
MState.lock();
|
||||
if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
|
||||
MState.unlock();
|
||||
return true;
|
||||
}
|
||||
MState.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This is always called from an IO thread. Either the server socket's thread, or a
|
||||
* special thread we create when we make an outbound connection. */
|
||||
bool TCPConnection::Process() {
|
||||
char errbuf[TCPConnection_ErrorBufferSize];
|
||||
switch(GetState()) {
|
||||
case TCPS_Ready:
|
||||
case TCPS_Connecting:
|
||||
if (ConnectionType == Outgoing) {
|
||||
if (GetAsyncConnect()) {
|
||||
if (charAsyncConnect)
|
||||
rIP = ResolveIP(charAsyncConnect);
|
||||
ConnectIP(rIP, rPort);
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
|
||||
case TCPS_Connected:
|
||||
// only receive data in the connected state, no others...
|
||||
if (!RecvData(errbuf)) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
return false;
|
||||
}
|
||||
/* we break to do the send */
|
||||
break;
|
||||
|
||||
case TCPS_Disconnecting: {
|
||||
//waiting for any sending data to go out...
|
||||
MSendQueue.lock();
|
||||
if(sendbuf) {
|
||||
if(sendbuf_used > 0) {
|
||||
//something left to send, keep processing...
|
||||
MSendQueue.unlock();
|
||||
break;
|
||||
}
|
||||
//else, send buffer is empty.
|
||||
safe_delete_array(sendbuf);
|
||||
} //else, no send buffer, we are done.
|
||||
MSendQueue.unlock();
|
||||
}
|
||||
/* Fallthrough */
|
||||
|
||||
case TCPS_Disconnected:
|
||||
FinishDisconnect();
|
||||
MRunLoop.lock();
|
||||
pRunLoop = false;
|
||||
MRunLoop.unlock();
|
||||
// SetState(TCPS_Ready); //reset the state in case they want to use it again...
|
||||
return(false);
|
||||
|
||||
case TCPS_Closing:
|
||||
//I dont understand this state...
|
||||
|
||||
case TCPS_Error:
|
||||
MRunLoop.lock();
|
||||
pRunLoop = false;
|
||||
MRunLoop.unlock();
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* we get here in connected or disconnecting with more data to send */
|
||||
|
||||
bool sent_something = false;
|
||||
if (!SendData(sent_something, errbuf)) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
std::cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPConnection::RecvData(char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
if (!Connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
if (recvbuf == 0) {
|
||||
recvbuf = new uchar[5120];
|
||||
recvbuf_size = 5120;
|
||||
recvbuf_used = 0;
|
||||
recvbuf_echo = 0;
|
||||
}
|
||||
else if ((recvbuf_size - recvbuf_used) < 2048) {
|
||||
auto tmpbuf = new uchar[recvbuf_size + 5120];
|
||||
memcpy(tmpbuf, recvbuf, recvbuf_used);
|
||||
recvbuf_size += 5120;
|
||||
safe_delete_array(recvbuf);
|
||||
recvbuf = tmpbuf;
|
||||
if (recvbuf_size >= MaxTCPReceiveBuffferSize) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0);
|
||||
|
||||
if (status >= 1) {
|
||||
#if TCPN_LOG_RAW_DATA_IN >= 1
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
|
||||
std::cout << std::endl;
|
||||
#if TCPN_LOG_RAW_DATA_IN == 2
|
||||
int32 tmp = status;
|
||||
if (tmp > 32)
|
||||
tmp = 32;
|
||||
DumpPacket(&recvbuf[recvbuf_used], status);
|
||||
#elif TCPN_LOG_RAW_DATA_IN >= 3
|
||||
DumpPacket(&recvbuf[recvbuf_used], status);
|
||||
#endif
|
||||
#endif
|
||||
recvbuf_used += status;
|
||||
if (!ProcessReceivedData(errbuf))
|
||||
return false;
|
||||
}
|
||||
else if (status == SOCKET_ERROR) {
|
||||
#ifdef _WINDOWS
|
||||
if (!(WSAGetLastError() == WSAEWOULDBLOCK)) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (!(errno == EWOULDBLOCK)) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
} else if (status == 0) {
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool TCPConnection::GetEcho() {
|
||||
bool ret;
|
||||
ret = pEcho;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TCPConnection::SetEcho(bool iValue) {
|
||||
pEcho = iValue;
|
||||
}
|
||||
|
||||
bool TCPConnection::ProcessReceivedData(char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
if (!recvbuf)
|
||||
return true;
|
||||
#if TCPN_DEBUG_Console >= 4
|
||||
if (recvbuf_used) {
|
||||
std::cout << "Starting Processing: recvbuf=" << recvbuf_used << std::endl;
|
||||
DumpPacket(recvbuf, recvbuf_used);
|
||||
}
|
||||
#endif
|
||||
for (int i=0; i < recvbuf_used; i++) {
|
||||
if (GetEcho() && i >= recvbuf_echo) {
|
||||
Send(&recvbuf[i], 1);
|
||||
recvbuf_echo = i + 1;
|
||||
}
|
||||
switch(recvbuf[i]) {
|
||||
case 0: { // 0 is the code for clear buffer
|
||||
if (i==0) {
|
||||
recvbuf_used--;
|
||||
recvbuf_echo--;
|
||||
memmove(recvbuf, &recvbuf[1], recvbuf_used);
|
||||
i = -1;
|
||||
} else {
|
||||
if (i == recvbuf_used) {
|
||||
safe_delete_array(recvbuf);
|
||||
i = -1;
|
||||
}
|
||||
else {
|
||||
uchar* tmpdel = recvbuf;
|
||||
recvbuf = new uchar[recvbuf_size];
|
||||
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
|
||||
recvbuf_used -= i + 1;
|
||||
recvbuf_echo -= i + 1;
|
||||
safe_delete_array(tmpdel);
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
#if TCPN_DEBUG_Console >= 5
|
||||
std::cout << "Removed 0x00" << std::endl;
|
||||
if (recvbuf_used) {
|
||||
std::cout << "recvbuf left: " << recvbuf_used << std::endl;
|
||||
DumpPacket(recvbuf, recvbuf_used);
|
||||
}
|
||||
else
|
||||
std::cout << "recbuf left: None" << std::endl;
|
||||
#endif
|
||||
m_previousLineEnd = false;
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
case 13: // newline marker
|
||||
{
|
||||
char *line = nullptr;
|
||||
if (i==0) { // empty line
|
||||
if(!m_previousLineEnd) {
|
||||
//char right before this was NOT a CR, report the empty line.
|
||||
line = new char[1];
|
||||
line[0] = '\0';
|
||||
m_previousLineEnd = true;
|
||||
} else {
|
||||
m_previousLineEnd = false;
|
||||
}
|
||||
recvbuf_used--;
|
||||
recvbuf_echo--;
|
||||
memcpy(recvbuf, &recvbuf[1], recvbuf_used);
|
||||
i = -1;
|
||||
} else {
|
||||
line = new char[i+1];
|
||||
memset(line, 0, i+1);
|
||||
memcpy(line, recvbuf, i);
|
||||
#if TCPN_DEBUG_Console >= 3
|
||||
std::cout << "Line Out: " << std::endl;
|
||||
DumpPacket((uchar*) line, i);
|
||||
#endif
|
||||
//line[i] = 0;
|
||||
uchar* tmpdel = recvbuf;
|
||||
recvbuf = new uchar[recvbuf_size];
|
||||
recvbuf_used -= i+1;
|
||||
recvbuf_echo -= i+1;
|
||||
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
|
||||
#if TCPN_DEBUG_Console >= 5
|
||||
std::cout << "i+1=" << i+1 << std::endl;
|
||||
if (recvbuf_used) {
|
||||
std::cout << "recvbuf left: " << recvbuf_used << std::endl;
|
||||
DumpPacket(recvbuf, recvbuf_used);
|
||||
}
|
||||
else
|
||||
std::cout << "recbuf left: None" << std::endl;
|
||||
#endif
|
||||
safe_delete_array(tmpdel);
|
||||
i = -1;
|
||||
m_previousLineEnd = true;
|
||||
}
|
||||
|
||||
|
||||
if(line != nullptr) {
|
||||
bool finish_proc = false;
|
||||
finish_proc = LineOutQueuePush(line);
|
||||
if(finish_proc)
|
||||
return(true); //break early as requested by LineOutQueuePush
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: // backspace
|
||||
{
|
||||
if (i==0) { // nothin to backspace
|
||||
recvbuf_used--;
|
||||
recvbuf_echo--;
|
||||
memmove(recvbuf, &recvbuf[1], recvbuf_used);
|
||||
i = -1;
|
||||
} else {
|
||||
uchar* tmpdel = recvbuf;
|
||||
recvbuf = new uchar[recvbuf_size];
|
||||
memcpy(recvbuf, tmpdel, i-1);
|
||||
memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
|
||||
recvbuf_used -= 2;
|
||||
recvbuf_echo -= 2;
|
||||
safe_delete_array(tmpdel);
|
||||
i -= 2;
|
||||
}
|
||||
break;
|
||||
m_previousLineEnd = false;
|
||||
}
|
||||
default:
|
||||
m_previousLineEnd = false;
|
||||
}
|
||||
}
|
||||
if (recvbuf_used < 0)
|
||||
safe_delete_array(recvbuf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPConnection::SendData(bool &sent_something, char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
/************ Get first send packet on queue and send it! ************/
|
||||
uchar* data = 0;
|
||||
int32 size = 0;
|
||||
int status = 0;
|
||||
if (ServerSendQueuePop(&data, &size)) {
|
||||
#ifdef _WINDOWS
|
||||
status = send(connection_socket, (const char *) data, size, 0);
|
||||
#else
|
||||
status = send(connection_socket, data, size, MSG_NOSIGNAL);
|
||||
if(errno==EPIPE) status = SOCKET_ERROR;
|
||||
#endif
|
||||
if (status >= 1) {
|
||||
#if TCPN_LOG_RAW_DATA_OUT >= 1
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
|
||||
std::cout << std::endl;
|
||||
#if TCPN_LOG_RAW_DATA_OUT == 2
|
||||
int32 tmp = status;
|
||||
if (tmp > 32)
|
||||
tmp = 32;
|
||||
DumpPacket(data, status);
|
||||
#elif TCPN_LOG_RAW_DATA_OUT >= 3
|
||||
DumpPacket(data, status);
|
||||
#endif
|
||||
#endif
|
||||
sent_something = true;
|
||||
if (status < (signed)size) {
|
||||
#if TCPN_LOG_RAW_DATA_OUT >= 1
|
||||
struct in_addr in;
|
||||
in.s_addr = GetrIP();
|
||||
CoutTimestamp(true);
|
||||
std::cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
// If there's network congestion, the number of bytes sent can be less than
|
||||
// what we tried to give it... Push the extra back on the queue for later
|
||||
ServerSendQueuePushFront(&data[status], size - status);
|
||||
}
|
||||
else if (status > (signed)size) {
|
||||
return false;
|
||||
}
|
||||
// else if (status == size) {}
|
||||
}
|
||||
else {
|
||||
ServerSendQueuePushFront(data, size);
|
||||
}
|
||||
|
||||
safe_delete_array(data);
|
||||
if (status == SOCKET_ERROR) {
|
||||
#ifdef _WINDOWS
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (errno != EWOULDBLOCK)
|
||||
#endif
|
||||
{
|
||||
if (errbuf) {
|
||||
#ifdef _WINDOWS
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
|
||||
#else
|
||||
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
//if we get an error while disconnecting, just jump to disconnected
|
||||
MState.lock();
|
||||
if(pState == TCPS_Disconnecting)
|
||||
pState = TCPS_Disconnected;
|
||||
MState.unlock();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadReturnType TCPConnection::TCPConnectionLoop(void* tmp) {
|
||||
#ifdef _WINDOWS
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
#endif
|
||||
if (tmp == 0) {
|
||||
THREAD_RETURN(nullptr);
|
||||
}
|
||||
TCPConnection* tcpc = (TCPConnection*) tmp;
|
||||
#ifndef WIN32
|
||||
Log.Out(Logs::Detail, Logs::TCP_Connection, "%s Starting TCPConnectionLoop with thread ID %d", __FUNCTION__, pthread_self());
|
||||
#endif
|
||||
tcpc->MLoopRunning.lock();
|
||||
while (tcpc->RunLoop()) {
|
||||
Sleep(LOOP_GRANULARITY);
|
||||
if (!tcpc->ConnectReady()) {
|
||||
if (!tcpc->Process()) {
|
||||
//the processing loop has detecting an error..
|
||||
//we want to drop the link immediately, so we clear buffers too.
|
||||
tcpc->ClearBuffers();
|
||||
tcpc->Disconnect();
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
else if (tcpc->GetAsyncConnect()) {
|
||||
if (tcpc->charAsyncConnect)
|
||||
tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
|
||||
else
|
||||
tcpc->ConnectIP(tcpc->GetrIP(), tcpc->GetrPort());
|
||||
tcpc->SetAsyncConnect(false);
|
||||
}
|
||||
else
|
||||
Sleep(10); //nothing to do.
|
||||
}
|
||||
tcpc->MLoopRunning.unlock();
|
||||
|
||||
#ifndef WIN32
|
||||
Log.Out(Logs::Detail, Logs::TCP_Connection, "%s Ending TCPConnectionLoop with thread ID %d", __FUNCTION__, pthread_self());
|
||||
#endif
|
||||
|
||||
THREAD_RETURN(nullptr);
|
||||
}
|
||||
|
||||
bool TCPConnection::RunLoop() {
|
||||
bool ret;
|
||||
MRunLoop.lock();
|
||||
ret = pRunLoop;
|
||||
MRunLoop.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1,176 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef TCP_CONNECTION_H
|
||||
#define TCP_CONNECTION_H
|
||||
/*
|
||||
Parent classes for interserver TCP Communication.
|
||||
-Quagmire
|
||||
*/
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900))
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
#include "unix.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "mutex.h"
|
||||
#include "queue.h"
|
||||
#include "misc_functions.h"
|
||||
|
||||
|
||||
#define TCPConnection_ErrorBufferSize 1024
|
||||
#define MaxTCPReceiveBuffferSize 524288
|
||||
|
||||
|
||||
#ifndef DEF_eConnectionType
|
||||
#define DEF_eConnectionType
|
||||
enum eConnectionType {Incoming, Outgoing};
|
||||
#endif
|
||||
|
||||
|
||||
class TCPConnection {
|
||||
protected:
|
||||
typedef enum {
|
||||
TCPS_Ready = 0,
|
||||
TCPS_Connecting = 1,
|
||||
TCPS_Connected = 100,
|
||||
TCPS_Disconnecting = 200, //I do not know the difference between Disconnecting and Closing
|
||||
TCPS_Disconnected = 201,
|
||||
TCPS_Closing = 250,
|
||||
TCPS_Error = 255
|
||||
} State_t;
|
||||
|
||||
public:
|
||||
//socket created by a server (incoming)
|
||||
TCPConnection(uint32 ID, SOCKET iSock, uint32 irIP, uint16 irPort);
|
||||
//socket created to connect to a server (outgoing)
|
||||
TCPConnection(); // for outgoing connections
|
||||
|
||||
virtual ~TCPConnection();
|
||||
|
||||
// Functions for outgoing connections
|
||||
bool Connect(const char* irAddress, uint16 irPort, char* errbuf = 0);
|
||||
virtual bool ConnectIP(uint32 irIP, uint16 irPort, char* errbuf = 0);
|
||||
void AsyncConnect(const char* irAddress, uint16 irPort);
|
||||
void AsyncConnect(uint32 irIP, uint16 irPort);
|
||||
virtual void Disconnect();
|
||||
|
||||
bool Send(const uchar* data, int32 size);
|
||||
|
||||
char* PopLine(); //returns ownership of allocated byte array
|
||||
inline uint32 GetrIP() const { return rIP; }
|
||||
inline uint16 GetrPort() const { return rPort; }
|
||||
virtual State_t GetState() const;
|
||||
inline bool Connected() const { return (GetState() == TCPS_Connected); }
|
||||
bool ConnectReady() const;
|
||||
void Free(); // Inform TCPServer that this connection object is no longer referanced
|
||||
|
||||
inline uint32 GetID() const { return id; }
|
||||
|
||||
bool GetEcho();
|
||||
void SetEcho(bool iValue);
|
||||
bool GetSockName(char *host, uint16 *port);
|
||||
|
||||
//should only be used by TCPServer<T>:
|
||||
bool CheckNetActive();
|
||||
inline bool IsFree() const { return pFree; }
|
||||
virtual bool Process();
|
||||
|
||||
protected:
|
||||
friend class BaseTCPServer;
|
||||
void SetState(State_t iState);
|
||||
|
||||
static ThreadReturnType TCPConnectionLoop(void* tmp);
|
||||
// SOCKET sock;
|
||||
bool RunLoop();
|
||||
Mutex MLoopRunning;
|
||||
Mutex MAsyncConnect;
|
||||
bool GetAsyncConnect();
|
||||
bool SetAsyncConnect(bool iValue);
|
||||
char* charAsyncConnect;
|
||||
bool pAsyncConnect; //this flag should really be turned into a state instead.
|
||||
|
||||
virtual bool ProcessReceivedData(char* errbuf = 0);
|
||||
virtual bool SendData(bool &sent_something, char* errbuf = 0);
|
||||
virtual bool RecvData(char* errbuf = 0);
|
||||
|
||||
virtual void ClearBuffers();
|
||||
|
||||
|
||||
bool m_previousLineEnd;
|
||||
|
||||
eConnectionType ConnectionType;
|
||||
Mutex MRunLoop;
|
||||
bool pRunLoop;
|
||||
|
||||
SOCKET connection_socket;
|
||||
uint32 id;
|
||||
uint32 rIP;
|
||||
uint16 rPort; // host byte order
|
||||
bool pFree;
|
||||
|
||||
mutable Mutex MState;
|
||||
State_t pState;
|
||||
|
||||
//text based line out queue.
|
||||
Mutex MLineOutQueue;
|
||||
virtual bool LineOutQueuePush(char* line); //this is really kinda a hack for the transition to packet mode. Returns true to stop processing the output.
|
||||
MyQueue<char> LineOutQueue;
|
||||
|
||||
uchar* recvbuf;
|
||||
int32 recvbuf_size;
|
||||
int32 recvbuf_used;
|
||||
|
||||
int32 recvbuf_echo;
|
||||
volatile bool pEcho;
|
||||
|
||||
Mutex MSendQueue;
|
||||
uchar* sendbuf;
|
||||
int32 sendbuf_size;
|
||||
int32 sendbuf_used;
|
||||
bool ServerSendQueuePop(uchar** data, int32* size);
|
||||
bool ServerSendQueuePopForce(uchar** data, int32* size); //does a lock() instead of a trylock()
|
||||
void ServerSendQueuePushEnd(const uchar* data, int32 size);
|
||||
void ServerSendQueuePushEnd(uchar** data, int32 size);
|
||||
void ServerSendQueuePushFront(uchar* data, int32 size);
|
||||
|
||||
private:
|
||||
void FinishDisconnect();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,231 +0,0 @@
|
||||
#include "global_define.h"
|
||||
#include "tcp_server.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
|
||||
#define SERVER_LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
|
||||
|
||||
BaseTCPServer::BaseTCPServer(uint16 in_port) {
|
||||
NextID = 1;
|
||||
pPort = in_port;
|
||||
sock = 0;
|
||||
pRunLoop = true;
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(BaseTCPServer::TCPServerLoop, 0, this);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, &BaseTCPServer::TCPServerLoop, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
BaseTCPServer::~BaseTCPServer() {
|
||||
StopLoopAndWait();
|
||||
}
|
||||
|
||||
void BaseTCPServer::StopLoopAndWait() {
|
||||
MRunLoop.lock();
|
||||
if(pRunLoop) {
|
||||
pRunLoop = false;
|
||||
MRunLoop.unlock();
|
||||
//wait for loop to stop.
|
||||
MLoopRunning.lock();
|
||||
MLoopRunning.unlock();
|
||||
} else {
|
||||
MRunLoop.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseTCPServer::RunLoop() {
|
||||
bool ret;
|
||||
MRunLoop.lock();
|
||||
ret = pRunLoop;
|
||||
MRunLoop.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ThreadReturnType BaseTCPServer::TCPServerLoop(void* tmp) {
|
||||
#ifdef _WINDOWS
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
#endif
|
||||
if (tmp == 0) {
|
||||
THREAD_RETURN(nullptr);
|
||||
}
|
||||
BaseTCPServer* tcps = (BaseTCPServer*) tmp;
|
||||
|
||||
#ifndef WIN32
|
||||
Log.Out(Logs::Detail, Logs::None, "Starting TCPServerLoop with thread ID %d", pthread_self());
|
||||
#endif
|
||||
|
||||
tcps->MLoopRunning.lock();
|
||||
while (tcps->RunLoop()) {
|
||||
Sleep(SERVER_LOOP_GRANULARITY);
|
||||
tcps->Process();
|
||||
}
|
||||
tcps->MLoopRunning.unlock();
|
||||
|
||||
#ifndef WIN32
|
||||
Log.Out(Logs::Detail, Logs::None, "Ending TCPServerLoop with thread ID %d", pthread_self());
|
||||
#endif
|
||||
|
||||
THREAD_RETURN(nullptr);
|
||||
}
|
||||
|
||||
void BaseTCPServer::Process() {
|
||||
ListenNewConnections();
|
||||
}
|
||||
|
||||
void BaseTCPServer::ListenNewConnections() {
|
||||
SOCKET tmpsock;
|
||||
struct sockaddr_in from;
|
||||
struct in_addr in;
|
||||
unsigned int fromlen;
|
||||
unsigned short port;
|
||||
|
||||
from.sin_family = AF_INET;
|
||||
fromlen = sizeof(from);
|
||||
LockMutex lock(&MSock);
|
||||
#ifndef DARWIN // Corysia - On OSX, 0 is a valid fd.
|
||||
if (!sock)
|
||||
return;
|
||||
#else
|
||||
if (sock == -1) return;
|
||||
#endif
|
||||
|
||||
// Check for pending connects
|
||||
#ifdef _WINDOWS
|
||||
unsigned long nonblocking = 1;
|
||||
while ((tmpsock = accept(sock, (struct sockaddr*) &from, (int *) &fromlen)) != INVALID_SOCKET) {
|
||||
ioctlsocket (tmpsock, FIONBIO, &nonblocking);
|
||||
#else
|
||||
#ifdef __CYGWIN__
|
||||
while ((tmpsock = accept(sock, (struct sockaddr *) &from, (int *) &fromlen)) != INVALID_SOCKET) {
|
||||
#else
|
||||
while ((tmpsock = accept(sock, (struct sockaddr*) &from, &fromlen)) != INVALID_SOCKET) {
|
||||
#endif
|
||||
fcntl(tmpsock, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
|
||||
setsockopt(tmpsock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
||||
port = from.sin_port;
|
||||
in.s_addr = from.sin_addr.s_addr;
|
||||
|
||||
// New TCP connection, this must consume the socket.
|
||||
CreateNewConnection(GetNextID(), tmpsock, in.s_addr, ntohs(from.sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseTCPServer::Open(uint16 in_port, char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
LockMutex lock(&MSock);
|
||||
if (sock != 0) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "Listening socket already open");
|
||||
return false;
|
||||
}
|
||||
if (in_port != 0) {
|
||||
pPort = in_port;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS
|
||||
SOCKADDR_IN address;
|
||||
unsigned long nonblocking = 1;
|
||||
#else
|
||||
struct sockaddr_in address;
|
||||
#endif
|
||||
int reuse_addr = 1;
|
||||
|
||||
// Setup internet address information.
|
||||
// This is used with the bind() call
|
||||
memset((char *) &address, 0, sizeof(address));
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(pPort);
|
||||
address.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
// Setting up TCP port for new TCP connections
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "socket(): INVALID_SOCKET");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Quag: dont think following is good stuff for TCP, good for UDP
|
||||
// Mis: SO_REUSEADDR shouldn't be a problem for tcp--allows you to restart
|
||||
// without waiting for conns in TIME_WAIT to die
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr));
|
||||
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
|
||||
#ifdef _WINDOWS
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
sock = 0;
|
||||
if (errbuf)
|
||||
sprintf(errbuf, "bind(): <0");
|
||||
return false;
|
||||
}
|
||||
|
||||
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
|
||||
#ifdef _WINDOWS
|
||||
ioctlsocket (sock, FIONBIO, &nonblocking);
|
||||
#else
|
||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
|
||||
#ifdef _WINDOWS
|
||||
closesocket(sock);
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %d", WSAGetLastError());
|
||||
#else
|
||||
close(sock);
|
||||
if (errbuf)
|
||||
snprintf(errbuf, TCPServer_ErrorBufferSize, "listen() failed, Error: %s", strerror(errno));
|
||||
#endif
|
||||
sock = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseTCPServer::Close() {
|
||||
StopLoopAndWait();
|
||||
|
||||
LockMutex lock(&MSock);
|
||||
if (sock) {
|
||||
#ifdef _WINDOWS
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
}
|
||||
sock = 0;
|
||||
}
|
||||
|
||||
bool BaseTCPServer::IsOpen() {
|
||||
MSock.lock();
|
||||
bool ret = (bool) (sock != 0);
|
||||
MSock.unlock();
|
||||
return ret;
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
#ifndef TCPSERVER_H_
|
||||
#define TCPSERVER_H_
|
||||
|
||||
#include "types.h"
|
||||
#include "mutex.h"
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#define TCPServer_ErrorBufferSize 1024
|
||||
|
||||
//this is the non-connection type specific server.
|
||||
class BaseTCPServer {
|
||||
public:
|
||||
BaseTCPServer(uint16 iPort = 0);
|
||||
virtual ~BaseTCPServer();
|
||||
|
||||
bool Open(uint16 iPort = 0, char* errbuf = 0); // opens the port
|
||||
void Close(); // closes the port
|
||||
bool IsOpen();
|
||||
inline uint16 GetPort() { return pPort; }
|
||||
inline uint32 GetNextID() { return NextID++; }
|
||||
|
||||
protected:
|
||||
static ThreadReturnType TCPServerLoop(void* tmp);
|
||||
|
||||
//factory method:
|
||||
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) = 0;
|
||||
|
||||
|
||||
virtual void Process();
|
||||
bool RunLoop();
|
||||
Mutex MLoopRunning;
|
||||
|
||||
void StopLoopAndWait();
|
||||
|
||||
void ListenNewConnections();
|
||||
|
||||
uint32 NextID;
|
||||
|
||||
Mutex MRunLoop;
|
||||
bool pRunLoop;
|
||||
|
||||
Mutex MSock;
|
||||
SOCKET sock;
|
||||
uint16 pPort;
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class TCPServer : public BaseTCPServer {
|
||||
protected:
|
||||
typedef typename std::vector<T *> vstore;
|
||||
typedef typename std::vector<T *>::iterator vitr;
|
||||
public:
|
||||
TCPServer(uint16 iPort = 0)
|
||||
: BaseTCPServer(iPort) {
|
||||
}
|
||||
|
||||
virtual ~TCPServer() {
|
||||
StopLoopAndWait();
|
||||
|
||||
//im not sure what the right thing to do here is...
|
||||
//we are freeing a connection which somebody likely has a pointer to..
|
||||
//but, we really shouldent ever get called anyhow..
|
||||
vitr cur, end;
|
||||
cur = m_list.begin();
|
||||
end = m_list.end();
|
||||
for(; cur != end; ++cur) {
|
||||
delete *cur;
|
||||
}
|
||||
}
|
||||
|
||||
T * NewQueuePop() {
|
||||
T * ret = nullptr;
|
||||
MNewQueue.lock();
|
||||
if(!m_NewQueue.empty()) {
|
||||
ret = m_NewQueue.front();
|
||||
m_NewQueue.pop();
|
||||
}
|
||||
MNewQueue.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Process() {
|
||||
BaseTCPServer::Process();
|
||||
|
||||
vitr cur;
|
||||
cur = m_list.begin();
|
||||
while(cur != m_list.end()) {
|
||||
T *data = *cur;
|
||||
if (data->IsFree() && (!data->CheckNetActive())) {
|
||||
#if EQN_DEBUG >= 4
|
||||
std::cout << "TCPConnection Connection deleted." << std::endl;
|
||||
#endif
|
||||
delete data;
|
||||
cur = m_list.erase(cur);
|
||||
} else {
|
||||
if (!data->Process())
|
||||
data->Disconnect();
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddConnection(T *con) {
|
||||
m_list.push_back(con);
|
||||
MNewQueue.lock();
|
||||
m_NewQueue.push(con);
|
||||
MNewQueue.unlock();
|
||||
}
|
||||
|
||||
//queue of new connections, for the app to pull from
|
||||
Mutex MNewQueue;
|
||||
std::queue<T *> m_NewQueue;
|
||||
|
||||
vstore m_list;
|
||||
};
|
||||
|
||||
|
||||
#endif /*TCPSERVER_H_*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,87 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include <iomanip>
|
||||
|
||||
#include "worldconn.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "md5.h"
|
||||
#include "servertalk.h"
|
||||
|
||||
WorldConnection::WorldConnection(EmuTCPConnection::ePacketMode mode, const char *password)
|
||||
: m_password(password)
|
||||
{
|
||||
tcpc.SetPacketMode(mode);
|
||||
pTryReconnect = true;
|
||||
pConnected = false;
|
||||
}
|
||||
|
||||
WorldConnection::~WorldConnection() {
|
||||
}
|
||||
|
||||
bool WorldConnection::SendPacket(ServerPacket* pack) {
|
||||
if (!Connected())
|
||||
return false;
|
||||
return tcpc.SendPacket(pack);
|
||||
}
|
||||
|
||||
void WorldConnection::OnConnected() {
|
||||
const EQEmuConfig *Config=EQEmuConfig::get();
|
||||
Log.Out(Logs::General, Logs::Netcode, "[WORLD] Connected to World: %s:%d", Config->WorldIP.c_str(), Config->WorldTCPPort);
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_ZAAuth, 16);
|
||||
MD5::Generate((const uchar*) m_password.c_str(), m_password.length(), pack->pBuffer);
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void WorldConnection::Process() {
|
||||
//persistent connection....
|
||||
if (!Connected()) {
|
||||
pConnected = tcpc.Connected();
|
||||
if (pConnected) {
|
||||
OnConnected();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WorldConnection::AsyncConnect() {
|
||||
const EQEmuConfig *Config=EQEmuConfig::get();
|
||||
tcpc.AsyncConnect(Config->WorldIP.c_str(), Config->WorldTCPPort);
|
||||
}
|
||||
|
||||
bool WorldConnection::Connect() {
|
||||
const EQEmuConfig *Config=EQEmuConfig::get();
|
||||
char errbuf[TCPConnection_ErrorBufferSize];
|
||||
if (tcpc.Connect(Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf)) {
|
||||
return true;
|
||||
} else {
|
||||
Log.Out(Logs::General, Logs::Netcode, "[WORLD] WorldConnection connect: Connecting to the server %s:%d failed: %s", Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WorldConnection::Disconnect() {
|
||||
tcpc.Disconnect();
|
||||
}
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef WORLDCONNECTION_H
|
||||
#define WORLDCONNECTION_H
|
||||
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include <string>
|
||||
|
||||
class ServerPacket;
|
||||
|
||||
/*
|
||||
* This object is an arbitrary connection to world.
|
||||
*/
|
||||
class WorldConnection {
|
||||
public:
|
||||
WorldConnection(EmuTCPConnection::ePacketMode mode, const char *password = "");
|
||||
virtual ~WorldConnection();
|
||||
|
||||
virtual void Process();
|
||||
bool SendPacket(ServerPacket* pack);
|
||||
|
||||
uint32 GetIP() const { return tcpc.GetrIP(); }
|
||||
uint16 GetPort() const { return tcpc.GetrPort(); }
|
||||
bool Connected() const { return (pConnected && tcpc.Connected()); }
|
||||
|
||||
void SetPassword(const char *password) { m_password = password; }
|
||||
bool Connect();
|
||||
void AsyncConnect();
|
||||
void Disconnect();
|
||||
inline bool TryReconnect() const { return pTryReconnect; }
|
||||
|
||||
protected:
|
||||
virtual void OnConnected();
|
||||
|
||||
std::string m_password;
|
||||
EmuTCPConnection tcpc;
|
||||
bool pTryReconnect;
|
||||
bool pConnected;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -20,13 +20,12 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/misc_functions.h"
|
||||
|
||||
#include "clientlist.h"
|
||||
#include "database.h"
|
||||
#include "chatchannel.h"
|
||||
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "../common/emu_tcp_server.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
47
wi/.gitignore
vendored
Normal file
47
wi/.gitignore
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
33
wi/index.js
Normal file
33
wi/index.js
Normal file
@ -0,0 +1,33 @@
|
||||
var servertalk = require('./servertalk_client.js');
|
||||
var fs = require('fs');
|
||||
var settings = JSON.parse(fs.readFileSync('settings.json', 'utf8'));
|
||||
|
||||
var client = new servertalk.client();
|
||||
|
||||
client.Init(settings.addr, settings.port, false, 'WebInterface', settings.key);
|
||||
|
||||
client.on('connecting', function(){
|
||||
console.log('Connecting...');
|
||||
});
|
||||
|
||||
client.on('connect', function(){
|
||||
console.log('Connected...');
|
||||
|
||||
this.Send(47, Buffer.from(JSON.stringify({ method: 'IsLocked', params: [], id: '12345' })));
|
||||
this.Send(47, Buffer.from(JSON.stringify({ method: 'Lock', params: [] })));
|
||||
this.Send(47, Buffer.from(JSON.stringify({ method: 'IsLocked', params: [], id: '12346' })));
|
||||
this.Send(47, Buffer.from(JSON.stringify({ method: 'Unlock', params: [] })));
|
||||
this.Send(47, Buffer.from(JSON.stringify({ method: 'IsLocked', params: [], id: '12347' })));
|
||||
});
|
||||
|
||||
client.on('close', function(){
|
||||
console.log('Closed');
|
||||
});
|
||||
|
||||
client.on('error', function(err){
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
client.on('message', function(opcode, packet) {
|
||||
console.log(Buffer.from(packet).toString('utf8'));
|
||||
});
|
||||
15
wi/package.json
Normal file
15
wi/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "wi",
|
||||
"version": "1.0.0",
|
||||
"description": "Web interface connection for EQEmu",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "KimLS",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"libsodium": "^0.4.8",
|
||||
"libsodium-wrappers": "^0.4.8"
|
||||
}
|
||||
}
|
||||
299
wi/servertalk_client.js
Normal file
299
wi/servertalk_client.js
Normal file
@ -0,0 +1,299 @@
|
||||
var net = require('net');
|
||||
var sodium = require('libsodium-wrappers');
|
||||
const EventEmitter = require('events');
|
||||
|
||||
var ServertalkPacketType =
|
||||
{
|
||||
ServertalkClientHello: 1,
|
||||
ServertalkServerHello: 2,
|
||||
ServertalkClientHandshake: 3,
|
||||
ServertalkClientDowngradeSecurityHandshake: 4,
|
||||
ServertalkMessage: 5,
|
||||
};
|
||||
|
||||
class ServertalkClient extends EventEmitter
|
||||
{
|
||||
Init(addr, port, ipv6, identifier, credentials) {
|
||||
this.m_addr = addr;
|
||||
this.m_identifier = identifier;
|
||||
this.m_credentials = credentials;
|
||||
this.m_connecting = false;
|
||||
this.m_port = port;
|
||||
this.m_ipv6 = ipv6;
|
||||
this.m_encrypted = false;
|
||||
this.m_connection = null;
|
||||
this.m_buffer = Buffer.alloc(0);
|
||||
this.m_public_key_ours = null;
|
||||
this.m_private_key_ours = null;
|
||||
this.m_nonce_ours = null;
|
||||
this.m_public_key_theirs = null;
|
||||
this.m_nonce_theirs = null;
|
||||
this.m_shared_key = null;
|
||||
|
||||
var self = this;
|
||||
setInterval(function() { self.Connect(); }, 100);
|
||||
}
|
||||
|
||||
Send(opcode, p) {
|
||||
try {
|
||||
var out;
|
||||
if(this.m_encrypted) {
|
||||
if(p.length == 0) {
|
||||
p = Buffer.alloc(1);
|
||||
}
|
||||
|
||||
out = Buffer.alloc(6);
|
||||
out.writeUInt32LE(p.length + sodium.crypto_secretbox_MACBYTES, 0);
|
||||
out.writeUInt16LE(opcode, 4);
|
||||
|
||||
var cipher = sodium.crypto_box_easy_afternm(p, this.m_nonce_ours, this.m_shared_key);
|
||||
this.IncrementUint64(this.m_nonce_ours);
|
||||
|
||||
out = Buffer.concat([out, Buffer.from(cipher)], out.length + cipher.length);
|
||||
} else {
|
||||
out = Buffer.alloc(6);
|
||||
out.writeUInt32LE(p.length, 0);
|
||||
out.writeUInt16LE(opcode, 4);
|
||||
out = Buffer.concat([out, p], out.length + p.length);
|
||||
}
|
||||
|
||||
this.InternalSend(ServertalkPacketType.ServertalkMessage, out);
|
||||
} catch(ex) {
|
||||
this.emit('error', new Error(ex));
|
||||
}
|
||||
}
|
||||
|
||||
Connected() {
|
||||
return this.m_connection && !this.m_connecting;
|
||||
}
|
||||
|
||||
Connect() {
|
||||
if (this.m_port == 0 || this.m_connection || this.m_connecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.m_connecting = true;
|
||||
|
||||
this.emit('connecting');
|
||||
|
||||
var self = this;
|
||||
this.m_connection = net.connect({port: this.m_port, host: this.m_addr}, function() {
|
||||
self.m_connection.on('close', function(had_error) {
|
||||
self.emit('close');
|
||||
self.m_connection = null;
|
||||
self.m_encrypted = false;
|
||||
});
|
||||
|
||||
self.m_connection.on('data', function(buffer) {
|
||||
self.ProcessData(buffer);
|
||||
});
|
||||
|
||||
self.SendHello();
|
||||
self.m_connecting = false;
|
||||
});
|
||||
|
||||
this.m_connection.on('error', function() {
|
||||
self.emit('close');
|
||||
self.m_connection = null;
|
||||
self.m_connecting = false;
|
||||
});
|
||||
}
|
||||
|
||||
ProcessData(buffer) {
|
||||
this.m_buffer = Buffer.concat([this.m_buffer, buffer], this.m_buffer.length + buffer.length);
|
||||
this.ProcessReadBuffer();
|
||||
}
|
||||
|
||||
SendHello() {
|
||||
var p = Buffer.alloc(0);
|
||||
this.InternalSend(ServertalkPacketType.ServertalkClientHello, p);
|
||||
}
|
||||
|
||||
InternalSend(type, p) {
|
||||
if(!this.m_connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
var out = Buffer.alloc(5);
|
||||
out.writeUInt32LE(p.length, 0);
|
||||
out.writeUInt8(type, 4);
|
||||
|
||||
if (p.length > 0) {
|
||||
out = Buffer.concat([out, p], out.length + p.length);
|
||||
}
|
||||
|
||||
this.m_connection.write(out);
|
||||
}
|
||||
|
||||
ProcessReadBuffer() {
|
||||
var current = 0;
|
||||
var total = this.m_buffer.length;
|
||||
|
||||
while (current < total) {
|
||||
var left = total - current;
|
||||
|
||||
var length = 0;
|
||||
var type = 0;
|
||||
if (left < 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
length = this.m_buffer.readUInt32LE(current);
|
||||
type = this.m_buffer.readUInt8(current + 4);
|
||||
|
||||
if (current + 5 + length > total) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
var p = Buffer.alloc(0);
|
||||
switch (type) {
|
||||
case ServertalkPacketType.ServertalkServerHello:
|
||||
this.ProcessHello(p);
|
||||
break;
|
||||
case ServertalkPacketType.ServertalkMessage:
|
||||
this.ProcessMessage(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var p = this.m_buffer.slice(current + 5, current + 5 + length);
|
||||
switch (type) {
|
||||
case ServertalkPacketType.ServertalkServerHello:
|
||||
this.ProcessHello(p);
|
||||
break;
|
||||
case ServertalkPacketType.ServertalkMessage:
|
||||
this.ProcessMessage(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current += length + 5;
|
||||
}
|
||||
|
||||
if (current == total) {
|
||||
this.m_buffer = Buffer.alloc(0);
|
||||
}
|
||||
else {
|
||||
this.m_buffer = this.m_buffer.slice(current);
|
||||
}
|
||||
}
|
||||
|
||||
ProcessHello(p) {
|
||||
this.m_encrypted = false;
|
||||
this.m_public_key_ours = null;
|
||||
this.m_public_key_theirs = null;
|
||||
this.m_private_key_ours = null;
|
||||
this.m_nonce_ours = null;
|
||||
this.m_nonce_theirs = null;
|
||||
this.m_shared_key = null;
|
||||
|
||||
try {
|
||||
var enc = p.readUInt8(0) == 1 ? true : false;
|
||||
if (enc) {
|
||||
if (p.length == (1 + sodium.crypto_box_PUBLICKEYBYTES + sodium.crypto_box_NONCEBYTES)) {
|
||||
this.m_public_key_theirs = p.slice(1, 1 + sodium.crypto_box_PUBLICKEYBYTES);
|
||||
this.m_nonce_theirs = p.slice(1 + sodium.crypto_box_PUBLICKEYBYTES, 1 + sodium.crypto_box_PUBLICKEYBYTES + sodium.crypto_box_NONCEBYTES);
|
||||
this.m_encrypted = true;
|
||||
this.SendHandshake(false);
|
||||
|
||||
this.emit('connect');
|
||||
}
|
||||
else {
|
||||
this.emit('error', new Error('Could not process hello, size !=', 1 + sodium.crypto_box_PUBLICKEYBYTES + sodium.crypto_box_NONCEBYTES));
|
||||
}
|
||||
} else {
|
||||
this.SendHandshake(false);
|
||||
|
||||
this.emit('connect');
|
||||
}
|
||||
} catch(ex) {
|
||||
this.emit('error', new Error(ex));
|
||||
}
|
||||
}
|
||||
|
||||
ProcessMessage(p) {
|
||||
try {
|
||||
var length = this.m_buffer.readUInt32LE(0);
|
||||
var opcode = this.m_buffer.readUInt16LE(4);
|
||||
if(length > 0) {
|
||||
var data = p.slice(6);
|
||||
|
||||
if(this.m_encrypted) {
|
||||
var message_len = length - sodium.crypto_secretbox_MACBYTES;
|
||||
|
||||
var decrypted = sodium.crypto_box_open_easy_afternm(data, this.m_nonce_theirs, this.m_shared_key);
|
||||
|
||||
this.IncrementUint64(this.m_nonce_theirs);
|
||||
|
||||
this.emit('message', opcode, decrypted);
|
||||
} else {
|
||||
this.emit('message', opcode, data);
|
||||
}
|
||||
} else {
|
||||
this.emit('message', opcode, Buffer.alloc(0));
|
||||
}
|
||||
} catch(ex) {
|
||||
this.emit('error', new Error(ex));
|
||||
}
|
||||
}
|
||||
|
||||
SendHandshake() {
|
||||
var handshake;
|
||||
|
||||
if(this.m_encrypted) {
|
||||
var keypair = sodium.crypto_box_keypair();
|
||||
this.m_public_key_ours = keypair.publicKey;
|
||||
this.m_private_key_ours = keypair.privateKey;
|
||||
this.m_nonce_ours = Buffer.from(sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES));
|
||||
this.m_shared_key = sodium.crypto_box_beforenm(this.m_public_key_theirs, this.m_private_key_ours);
|
||||
|
||||
this.m_public_key_theirs = null;
|
||||
this.m_private_key_ours = null;
|
||||
|
||||
var message = Buffer.alloc(this.m_identifier.length + this.m_credentials.length + 2);
|
||||
message.write(this.m_identifier, 0);
|
||||
message.write(this.m_credentials, this.m_identifier.length + 1);
|
||||
|
||||
var ciphertext = sodium.crypto_box_easy_afternm(message, this.m_nonce_ours, this.m_shared_key);
|
||||
|
||||
handshake = Buffer.concat([Buffer.from(this.m_public_key_ours), Buffer.from(this.m_nonce_ours), Buffer.from(ciphertext)], sodium.crypto_box_PUBLICKEYBYTES + sodium.crypto_box_NONCEBYTES + ciphertext.length);
|
||||
this.IncrementUint64(this.m_nonce_ours);
|
||||
|
||||
this.m_public_key_ours = null;
|
||||
} else {
|
||||
handshake = Buffer.alloc(this.m_identifier.length + this.m_credentials.length + 2);
|
||||
handshake.write(this.m_identifier, 0);
|
||||
handshake.write(this.m_credentials, this.m_identifier.length() + 1);
|
||||
}
|
||||
|
||||
this.InternalSend(ServertalkPacketType.ServertalkClientHandshake, handshake);
|
||||
}
|
||||
|
||||
IncrementUint64(value) {
|
||||
var bytes = [];
|
||||
for(var i = 0; i < 8; ++i) {
|
||||
bytes[i] = value[i];
|
||||
}
|
||||
|
||||
bytes[0] += 1;
|
||||
for(i = 0; i < 7; ++i) {
|
||||
if(bytes[i] >= 0x100) {
|
||||
bytes[0] = 0;
|
||||
bytes[i + 1] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(bytes[7] >= 0x100) {
|
||||
bytes[7] = 0;
|
||||
}
|
||||
|
||||
for(var i = 0; i < 8; ++i) {
|
||||
value[i] = bytes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'client': ServertalkClient
|
||||
}
|
||||
5
wi/settings.json
Normal file
5
wi/settings.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"addr": "localhost",
|
||||
"port": "9101",
|
||||
"key": "ujwn2isnal1987scanb"
|
||||
}
|
||||
@ -6,23 +6,17 @@ SET(world_sources
|
||||
client.cpp
|
||||
cliententry.cpp
|
||||
clientlist.cpp
|
||||
CMakeLists.txt
|
||||
eql_config.cpp
|
||||
eqw.cpp
|
||||
eqw_http_handler.cpp
|
||||
eqw_parser.cpp
|
||||
http_request.cpp
|
||||
launcher_link.cpp
|
||||
launcher_list.cpp
|
||||
lfplist.cpp
|
||||
login_server.cpp
|
||||
login_server_list.cpp
|
||||
net.cpp
|
||||
perl_eql_config.cpp
|
||||
perl_eqw.cpp
|
||||
perl_http_request.cpp
|
||||
queryserv.cpp
|
||||
ucs.cpp
|
||||
web_interface.cpp
|
||||
web_interface_eqw.cpp
|
||||
wguild_mgr.cpp
|
||||
world_config.cpp
|
||||
worlddb.cpp
|
||||
@ -37,12 +31,7 @@ SET(world_headers
|
||||
client.h
|
||||
cliententry.h
|
||||
clientlist.h
|
||||
CMakeLists.txt
|
||||
eql_config.h
|
||||
eqw.h
|
||||
eqw_http_handler.h
|
||||
eqw_parser.h
|
||||
http_request.h
|
||||
launcher_link.h
|
||||
launcher_list.h
|
||||
lfplist.h
|
||||
@ -52,10 +41,11 @@ SET(world_headers
|
||||
queryserv.h
|
||||
sof_char_create_data.h
|
||||
ucs.h
|
||||
web_interface.h
|
||||
web_interface_eqw.h
|
||||
wguild_mgr.h
|
||||
world_config.h
|
||||
worlddb.h
|
||||
world_tcp_connection.h
|
||||
zonelist.h
|
||||
zoneserver.h
|
||||
)
|
||||
|
||||
@ -21,15 +21,15 @@
|
||||
#include "zoneserver.h"
|
||||
#include "zonelist.h"
|
||||
#include "client.h"
|
||||
#include "console.h"
|
||||
#include "worlddb.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/races.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "wguild_mgr.h"
|
||||
#include "../common/misc.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "wguild_mgr.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
|
||||
@ -1,854 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/global_define.h"
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "../common/version.h"
|
||||
#include "console.h"
|
||||
#include "zoneserver.h"
|
||||
#include "worlddb.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/seperator.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/eq_packet.h"
|
||||
#include "login_server.h"
|
||||
#include "login_server_list.h"
|
||||
#include "../common/serverinfo.h"
|
||||
#include "../common/md5.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/ruletypes.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "world_config.h"
|
||||
#include "zoneserver.h"
|
||||
#include "zonelist.h"
|
||||
#include "clientlist.h"
|
||||
#include "launcher_list.h"
|
||||
#include "ucs.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
extern ZSList zoneserver_list;
|
||||
extern uint32 numzones;
|
||||
extern LoginServerList loginserverlist;
|
||||
extern ClientList client_list;
|
||||
extern LauncherList launcher_list;
|
||||
extern UCSConnection UCSLink;
|
||||
extern QueryServConnection QSLink;
|
||||
extern volatile bool RunLoops;
|
||||
|
||||
ConsoleList console_list;
|
||||
void CatchSignal(int sig_num);
|
||||
|
||||
Console::Console(EmuTCPConnection* itcpc)
|
||||
: WorldTCPConnection(),
|
||||
timeout_timer(RuleI(Console, SessionTimeOut)),
|
||||
prompt_timer(1000)
|
||||
{
|
||||
tcpc = itcpc;
|
||||
tcpc->SetEcho(true);
|
||||
state = 0;
|
||||
paccountid = 0;
|
||||
memset(paccountname, 0, sizeof(paccountname));
|
||||
admin = 0;
|
||||
pAcceptMessages = false;
|
||||
}
|
||||
|
||||
Console::~Console() {
|
||||
if (tcpc)
|
||||
tcpc->Free();
|
||||
}
|
||||
|
||||
void Console::Die() {
|
||||
state = CONSOLE_STATE_CLOSED;
|
||||
struct in_addr in;
|
||||
in.s_addr = GetIP();
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Removing console from %s:%d",inet_ntoa(in),GetPort());
|
||||
tcpc->Disconnect();
|
||||
}
|
||||
|
||||
bool Console::SendChannelMessage(const ServerChannelMessage_Struct* scm) {
|
||||
if (!pAcceptMessages)
|
||||
return false;
|
||||
switch (scm->chan_num) {
|
||||
if(RuleB(Chat, ServerWideAuction)){
|
||||
case 4: {
|
||||
SendMessage(1, "%s auctions, '%s'", scm->from, scm->message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(RuleB(Chat, ServerWideOOC)){
|
||||
case 5: {
|
||||
SendMessage(1, "%s says ooc, '%s'", scm->from, scm->message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 6: {
|
||||
SendMessage(1, "%s BROADCASTS, '%s'", scm->from, scm->message);
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
SendMessage(1, "[%s] tells you, '%s'", scm->from, scm->message);
|
||||
auto pack = new ServerPacket(ServerOP_ChannelMessage,
|
||||
sizeof(ServerChannelMessage_Struct) + strlen(scm->message) + 1);
|
||||
memcpy(pack->pBuffer, scm, pack->size);
|
||||
ServerChannelMessage_Struct* scm2 = (ServerChannelMessage_Struct*) pack->pBuffer;
|
||||
strcpy(scm2->deliverto, scm2->from);
|
||||
scm2->noreply = true;
|
||||
client_list.SendPacket(scm->from, pack);
|
||||
safe_delete(pack);
|
||||
break;
|
||||
}
|
||||
case 11: {
|
||||
SendMessage(1, "%s GMSAYS, '%s'", scm->from, scm->message);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::SendEmoteMessage(uint32 type, const char* message, ...) {
|
||||
if (!message)
|
||||
return false;
|
||||
if (!pAcceptMessages)
|
||||
return false;
|
||||
va_list argptr;
|
||||
char buffer[1024];
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, sizeof(buffer), message, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
SendMessage(1, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::SendEmoteMessageRaw(uint32 type, const char* message) {
|
||||
if (!message)
|
||||
return false;
|
||||
if (!pAcceptMessages)
|
||||
return false;
|
||||
SendMessage(1, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Console::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...) {
|
||||
if (!message)
|
||||
return;
|
||||
if (to_guilddbid != 0 || to_minstatus > Admin())
|
||||
return;
|
||||
va_list argptr;
|
||||
char buffer[1024];
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, sizeof(buffer), message, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
|
||||
}
|
||||
|
||||
void Console::SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message) {
|
||||
if (!message)
|
||||
return;
|
||||
if (to_guilddbid != 0 || to_minstatus > Admin())
|
||||
return;
|
||||
SendMessage(1, message);
|
||||
}
|
||||
|
||||
void Console::SendMessage(uint8 newline, const char* message, ...) {
|
||||
if (!message)
|
||||
return;
|
||||
char* buffer = 0;
|
||||
uint32 bufsize = 1500;
|
||||
if (message)
|
||||
bufsize += strlen(message);
|
||||
buffer = new char[bufsize];
|
||||
memset(buffer, 0, bufsize);
|
||||
if (message != 0) {
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, bufsize - 512, message, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
if (newline) {
|
||||
char outbuf[3];
|
||||
outbuf[0] = 13;
|
||||
outbuf[1] = 10;
|
||||
outbuf[2] = 0;
|
||||
for (int i=0; i < newline; i++)
|
||||
strcat(buffer, outbuf);
|
||||
}
|
||||
tcpc->Send((uchar*) buffer, strlen(buffer));
|
||||
safe_delete_array(buffer);
|
||||
}
|
||||
|
||||
bool Console::Process() {
|
||||
if (state == CONSOLE_STATE_CLOSED)
|
||||
return false;
|
||||
|
||||
if (!tcpc->Connected()) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetIP();
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Removing console (!tcpc->Connected) from %s:%d",inet_ntoa(in),GetPort());
|
||||
return false;
|
||||
}
|
||||
//if we have not gotten the special markers after this timer, send login prompt
|
||||
if(prompt_timer.Check()) {
|
||||
prompt_timer.Disable();
|
||||
if(tcpc->GetMode() == EmuTCPConnection::modeConsole)
|
||||
tcpc->Send((const uchar*) "Username: ", strlen("Username: "));
|
||||
}
|
||||
|
||||
if (timeout_timer.Check()) {
|
||||
SendMessage(1, 0);
|
||||
SendMessage(1, "Timeout, disconnecting...");
|
||||
struct in_addr in;
|
||||
in.s_addr = GetIP();
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"TCP connection timeout from %s:%d",inet_ntoa(in),GetPort());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tcpc->GetMode() == EmuTCPConnection::modePacket) {
|
||||
struct in_addr in;
|
||||
in.s_addr = GetIP();
|
||||
//if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeZone) {
|
||||
// auto zs = new ZoneServer(tcpc);
|
||||
// Log.Out(Logs::Detail, Logs::World_Server,"New zoneserver #%d from %s:%d", zs->GetID(), inet_ntoa(in), GetPort());
|
||||
// zoneserver_list.Add(zs);
|
||||
// numzones++;
|
||||
// tcpc = 0;
|
||||
//} else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeLauncher) {
|
||||
// Log.Out(Logs::Detail, Logs::World_Server,"New launcher from %s:%d", inet_ntoa(in), GetPort());
|
||||
// launcher_list.Add(tcpc);
|
||||
// tcpc = 0;
|
||||
//}
|
||||
//else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS)
|
||||
//{
|
||||
// Log.Out(Logs::Detail, Logs::World_Server,"New UCS Connection from %s:%d", inet_ntoa(in), GetPort());
|
||||
// UCSLink.SetConnection(tcpc);
|
||||
// tcpc = 0;
|
||||
//}
|
||||
//else {
|
||||
// Log.Out(Logs::Detail, Logs::World_Server,"Unsupported packet mode from %s:%d", inet_ntoa(in), GetPort());
|
||||
//}
|
||||
return false;
|
||||
}
|
||||
char* command = 0;
|
||||
while ((command = tcpc->PopLine())) {
|
||||
timeout_timer.Start();
|
||||
ProcessCommand(command);
|
||||
delete command;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConsoleList::Add(Console* con) {
|
||||
list.Insert(con);
|
||||
}
|
||||
|
||||
void ConsoleList::Process() {
|
||||
LinkedListIterator<Console*> iterator(list);
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
if (!iterator.GetData()->Process())
|
||||
iterator.RemoveCurrent();
|
||||
else
|
||||
iterator.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleList::KillAll() {
|
||||
LinkedListIterator<Console*> iterator(list);
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
iterator.GetData()->Die();
|
||||
iterator.RemoveCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleList::SendConsoleWho(WorldTCPConnection* connection, const char* to, int16 admin, char** output, uint32* outsize, uint32* outlen) {
|
||||
LinkedListIterator<Console*> iterator(list);
|
||||
iterator.Reset();
|
||||
struct in_addr in;
|
||||
int x = 0;
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
in.s_addr = iterator.GetData()->GetIP();
|
||||
if (admin >= iterator.GetData()->Admin())
|
||||
AppendAnyLenString(output, outsize, outlen, " Console: %s:%i AccID: %i AccName: %s", inet_ntoa(in), iterator.GetData()->GetPort(), iterator.GetData()->AccountID(), iterator.GetData()->AccountName());
|
||||
else
|
||||
AppendAnyLenString(output, outsize, outlen, " Console: AccID: %i AccName: %s", iterator.GetData()->AccountID(), iterator.GetData()->AccountName());
|
||||
if (*outlen >= 3584) {
|
||||
connection->SendEmoteMessageRaw(to, 0, 0, 10, *output);
|
||||
safe_delete(*output);
|
||||
*outsize = 0;
|
||||
*outlen = 0;
|
||||
}
|
||||
else {
|
||||
if (connection->IsConsole())
|
||||
AppendAnyLenString(output, outsize, outlen, "\r\n");
|
||||
else
|
||||
AppendAnyLenString(output, outsize, outlen, "\n");
|
||||
}
|
||||
x++;
|
||||
iterator.Advance();
|
||||
}
|
||||
AppendAnyLenString(output, outsize, outlen, "%i consoles connected", x);
|
||||
}
|
||||
|
||||
void ConsoleList::SendChannelMessage(const ServerChannelMessage_Struct* scm) {
|
||||
LinkedListIterator<Console*> iterator(list);
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
iterator.GetData()->SendChannelMessage(scm);
|
||||
iterator.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleList::SendEmoteMessage(uint32 type, const char* message, ...) {
|
||||
va_list argptr;
|
||||
char buffer[1024];
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, sizeof(buffer), message, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
SendEmoteMessageRaw(type, buffer);
|
||||
}
|
||||
|
||||
void ConsoleList::SendEmoteMessageRaw(uint32 type, const char* message) {
|
||||
LinkedListIterator<Console*> iterator(list);
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
iterator.GetData()->SendEmoteMessageRaw(type, message);
|
||||
iterator.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
Console* ConsoleList::FindByAccountName(const char* accname) {
|
||||
LinkedListIterator<Console*> iterator(list);
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
if (strcasecmp(iterator.GetData()->AccountName(), accname) == 0)
|
||||
return iterator.GetData();
|
||||
|
||||
iterator.Advance();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Console::ProcessCommand(const char* command) {
|
||||
switch(state)
|
||||
{
|
||||
case CONSOLE_STATE_USERNAME:
|
||||
{
|
||||
if (strlen(command) >= 16) {
|
||||
SendMessage(1, 0);
|
||||
SendMessage(2, "Username buffer overflow.");
|
||||
SendMessage(1, "Bye Bye.");
|
||||
state = CONSOLE_STATE_CLOSED;
|
||||
return;
|
||||
}
|
||||
strcpy(paccountname, command);
|
||||
state = CONSOLE_STATE_PASSWORD;
|
||||
SendMessage(0, "Password: ");
|
||||
tcpc->SetEcho(false);
|
||||
break;
|
||||
}
|
||||
case CONSOLE_STATE_PASSWORD:
|
||||
{
|
||||
if (strlen(command) >= 16) {
|
||||
SendMessage(1, 0);
|
||||
SendMessage(2, "Password buffer overflow.");
|
||||
SendMessage(1, "Bye Bye.");
|
||||
state = CONSOLE_STATE_CLOSED;
|
||||
return;
|
||||
}
|
||||
paccountid = database.CheckLogin(paccountname ,command);
|
||||
if (paccountid == 0) {
|
||||
SendMessage(1, 0);
|
||||
SendMessage(2, "Login failed.");
|
||||
SendMessage(1, "Bye Bye.");
|
||||
state = CONSOLE_STATE_CLOSED;
|
||||
return;
|
||||
}
|
||||
database.GetAccountName(paccountid, paccountname); // fixes case and stuff
|
||||
admin = database.CheckStatus(paccountid);
|
||||
if (!(admin >= consoleLoginStatus)) {
|
||||
SendMessage(1, 0);
|
||||
SendMessage(2, "Access denied.");
|
||||
SendMessage(1, "Bye Bye.");
|
||||
state = CONSOLE_STATE_CLOSED;
|
||||
return;
|
||||
}
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"TCP console authenticated: Username=%s, Admin=%d",paccountname,admin);
|
||||
SendMessage(1, 0);
|
||||
SendMessage(2, "Login accepted.");
|
||||
state = CONSOLE_STATE_CONNECTED;
|
||||
tcpc->SetEcho(true);
|
||||
SendPrompt();
|
||||
break;
|
||||
}
|
||||
case CONSOLE_STATE_CONNECTED: {
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"TCP command: %s: \"%s\"",paccountname ,command);
|
||||
Seperator sep(command);
|
||||
if (strcasecmp(sep.arg[0], "help") == 0 || strcmp(sep.arg[0], "?") == 0) {
|
||||
SendMessage(1, " whoami");
|
||||
SendMessage(1, " who");
|
||||
SendMessage(1, " zonestatus");
|
||||
SendMessage(1, " uptime [zoneID#]");
|
||||
SendMessage(1, " emote [zonename or charname or world] [type] [message]");
|
||||
SendMessage(1, " echo [on/off]");
|
||||
SendMessage(1, " acceptmessages [on/off]");
|
||||
SendMessage(1, " tell [name] [message]");
|
||||
SendMessage(1, " broadcast [message]");
|
||||
SendMessage(1, " gmsay [message]");
|
||||
SendMessage(1, " ooc [message]");
|
||||
SendMessage(1, " auction [message]");
|
||||
if (admin >= consoleKickStatus)
|
||||
SendMessage(1, " kick [charname]");
|
||||
if (admin >= consoleLockStatus)
|
||||
SendMessage(1, " lock/unlock");
|
||||
if (admin >= consoleZoneStatus) {
|
||||
SendMessage(1, " zoneshutdown [zonename or ZoneServerID]");
|
||||
SendMessage(1, " zonebootup [ZoneServerID] [zonename]");
|
||||
SendMessage(1, " zonelock [list|lock|unlock] [zonename]");
|
||||
}
|
||||
if (admin >= consoleFlagStatus)
|
||||
SendMessage(1, " flag [status] [accountname]");
|
||||
if (admin >= consolePassStatus)
|
||||
SendMessage(1, " setpass [accountname] [newpass]");
|
||||
if (admin >= consoleWorldStatus) {
|
||||
SendMessage(1, " version");
|
||||
SendMessage(1, " worldshutdown");
|
||||
}
|
||||
if (admin >= 201) {
|
||||
SendMessage(1, " IPLookup [name]");
|
||||
}
|
||||
if (admin >= 100) {
|
||||
SendMessage(1, " signalcharbyname charname ID");
|
||||
SendMessage(1, " reloadworld");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "ping") == 0) {
|
||||
// do nothing
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "signalcharbyname") == 0) {
|
||||
SendMessage(1, "Signal Sent to %s with ID %i", (char*) sep.arg[1], atoi(sep.arg[2]));
|
||||
uint32 message_len = strlen((char*) sep.arg[1]) + 1;
|
||||
auto pack = new ServerPacket(ServerOP_CZSignalClientByName,
|
||||
sizeof(CZClientSignalByName_Struct) + message_len);
|
||||
CZClientSignalByName_Struct* CZSC = (CZClientSignalByName_Struct*) pack->pBuffer;
|
||||
strn0cpy(CZSC->Name, (char*) sep.arg[1], 64);
|
||||
CZSC->data = atoi(sep.arg[2]);
|
||||
zoneserver_list.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "setpass") == 0 && admin >= consolePassStatus) {
|
||||
if (sep.argnum != 2)
|
||||
SendMessage(1, "Format: setpass accountname password");
|
||||
else {
|
||||
|
||||
int16 tmpstatus = 0;
|
||||
uint32 tmpid = database.GetAccountIDByName(sep.arg[1], &tmpstatus);
|
||||
if (!tmpid)
|
||||
SendMessage(1, "Error: Account not found");
|
||||
else if (tmpstatus > admin)
|
||||
SendMessage(1, "Cannot change password: Account's status is higher than yours");
|
||||
else if (database.SetLocalPassword(tmpid, sep.arg[2]))
|
||||
SendMessage(1, "Password changed.");
|
||||
else
|
||||
SendMessage(1, "Error changing password.");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "uptime") == 0) {
|
||||
if (sep.IsNumber(1) && atoi(sep.arg[1]) > 0) {
|
||||
auto pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct));
|
||||
ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer;
|
||||
snprintf(sus->adminname, sizeof(sus->adminname), "*%s", this->GetName());
|
||||
sus->zoneserverid = atoi(sep.arg[1]);
|
||||
ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
|
||||
if (zs)
|
||||
zs->SendPacket(pack);
|
||||
else
|
||||
SendMessage(1, "Zoneserver not found.");
|
||||
delete pack;
|
||||
}
|
||||
else {
|
||||
ZSList::ShowUpTime(this);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "md5") == 0) {
|
||||
uint8 md5[16];
|
||||
MD5::Generate((const uchar*) sep.argplus[1], strlen(sep.argplus[1]), md5);
|
||||
SendMessage(1, "MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "whoami") == 0) {
|
||||
SendMessage(1, "You are logged in as '%s'", this->AccountName());
|
||||
SendMessage(1, "You are known as '*%s'", this->AccountName());
|
||||
SendMessage(1, "AccessLevel: %d", this->Admin());
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "echo") == 0) {
|
||||
if (strcasecmp(sep.arg[1], "on") == 0)
|
||||
tcpc->SetEcho(true);
|
||||
else if (strcasecmp(sep.arg[1], "off") == 0) {
|
||||
if (pAcceptMessages)
|
||||
SendMessage(1, "Echo can not be turned off while acceptmessages is on");
|
||||
else
|
||||
tcpc->SetEcho(false);
|
||||
}
|
||||
else
|
||||
SendMessage(1, "Usage: echo [on/off]");
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "acceptmessages") == 0) {
|
||||
if (strcasecmp(sep.arg[1], "on") == 0)
|
||||
if (tcpc->GetEcho())
|
||||
SendMessage(1, "AcceptMessages can not be turned on while echo is on");
|
||||
else
|
||||
pAcceptMessages = true;
|
||||
else if (strcasecmp(sep.arg[1], "off") == 0)
|
||||
pAcceptMessages = false;
|
||||
else
|
||||
SendMessage(1, "Usage: acceptmessages [on/off]");
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "tell") == 0) {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
zoneserver_list.SendChannelMessage(tmpname, sep.arg[1], 7, 0, sep.argplus[2]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "broadcast") == 0) {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
zoneserver_list.SendChannelMessage(tmpname, 0, 6, 0, sep.argplus[1]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "ooc") == 0) {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
zoneserver_list.SendChannelMessage(tmpname, 0, 5, 0, sep.argplus[1]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "auction") == 0) {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
zoneserver_list.SendChannelMessage(tmpname, 0, 4, 0, sep.argplus[1]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "gmsay") == 0 || strcasecmp(sep.arg[0], "pr") == 0) {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
zoneserver_list.SendChannelMessage(tmpname, 0, 11, 0, sep.argplus[1]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "emote") == 0) {
|
||||
if (strcasecmp(sep.arg[1], "world") == 0)
|
||||
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
|
||||
else {
|
||||
ZoneServer* zs = zoneserver_list.FindByName(sep.arg[1]);
|
||||
if (zs != 0)
|
||||
zs->SendEmoteMessageRaw(0, 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
|
||||
else
|
||||
zoneserver_list.SendEmoteMessageRaw(sep.arg[1], 0, 0, atoi(sep.arg[2]), sep.argplus[3]);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "movechar") == 0) {
|
||||
if(sep.arg[1][0]==0 || sep.arg[2][0] == 0)
|
||||
SendMessage(1, "Usage: movechar [charactername] [zonename]");
|
||||
else {
|
||||
if (!database.GetZoneID(sep.arg[2]))
|
||||
SendMessage(1, "Error: Zone '%s' not found", sep.arg[2]);
|
||||
else if (!database.CheckUsedName((char*) sep.arg[1])) {
|
||||
if (!database.MoveCharacterToZone((char*) sep.arg[1], (char*) sep.arg[2]))
|
||||
SendMessage(1, "Character Move Failed!");
|
||||
else
|
||||
SendMessage(1, "Character has been moved.");
|
||||
}
|
||||
else
|
||||
SendMessage(1, "Character Does Not Exist");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "flag") == 0 && this->Admin() >= consoleFlagStatus) {
|
||||
// SCORPIOUS2K - reversed parameter order for flag
|
||||
if(sep.arg[2][0]==0 || !sep.IsNumber(1))
|
||||
SendMessage(1, "Usage: flag [status] [accountname]");
|
||||
else
|
||||
{
|
||||
if (atoi(sep.arg[1]) > this->Admin())
|
||||
SendMessage(1, "You cannot set people's status to higher than your own");
|
||||
else if (atoi(sep.arg[1]) < 0 && this->Admin() < consoleFlagStatus)
|
||||
SendMessage(1, "You have too low of status to change flags");
|
||||
else if (!database.SetAccountStatus(sep.arg[2], atoi(sep.arg[1])))
|
||||
SendMessage(1, "Unable to flag account!");
|
||||
else
|
||||
SendMessage(1, "Account Flaged");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "kick") == 0 && admin >= consoleKickStatus) {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
auto pack = new ServerPacket;
|
||||
pack->opcode = ServerOP_KickPlayer;
|
||||
pack->size = sizeof(ServerKickPlayer_Struct);
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
|
||||
strcpy(skp->adminname, tmpname);
|
||||
strcpy(skp->name, sep.arg[1]);
|
||||
skp->adminrank = this->Admin();
|
||||
zoneserver_list.SendPacket(pack);
|
||||
delete pack;
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "who") == 0) {
|
||||
auto whom = new Who_All_Struct;
|
||||
memset(whom, 0, sizeof(Who_All_Struct));
|
||||
whom->lvllow = 0xFFFF;
|
||||
whom->lvlhigh = 0xFFFF;
|
||||
whom->wclass = 0xFFFF;
|
||||
whom->wrace = 0xFFFF;
|
||||
whom->gmlookup = 0xFFFF;
|
||||
for (int i=1; i<=sep.argnum; i++) {
|
||||
if (strcasecmp(sep.arg[i], "gm") == 0)
|
||||
whom->gmlookup = 1;
|
||||
else if (sep.IsNumber(i)) {
|
||||
if (whom->lvllow == 0xFFFF) {
|
||||
whom->lvllow = atoi(sep.arg[i]);
|
||||
whom->lvlhigh = whom->lvllow;
|
||||
}
|
||||
else if (atoi(sep.arg[i]) > int(whom->lvllow))
|
||||
whom->lvlhigh = atoi(sep.arg[i]);
|
||||
else
|
||||
whom->lvllow = atoi(sep.arg[i]);
|
||||
}
|
||||
else
|
||||
strn0cpy(whom->whom, sep.arg[i], sizeof(whom->whom));
|
||||
}
|
||||
client_list.ConsoleSendWhoAll(0, admin, whom, this);
|
||||
delete whom;
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "zonestatus") == 0) {
|
||||
zoneserver_list.SendZoneStatus(0, admin, this);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "exit") == 0 || strcasecmp(sep.arg[0], "quit") == 0) {
|
||||
SendMessage(1, "Bye Bye.");
|
||||
state = CONSOLE_STATE_CLOSED;
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "zoneshutdown") == 0 && admin >= consoleZoneStatus) {
|
||||
if (sep.arg[1][0] == 0) {
|
||||
SendMessage(1, "Usage: zoneshutdown zoneshortname");
|
||||
} else {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
|
||||
auto pack = new ServerPacket;
|
||||
pack->size = sizeof(ServerZoneStateChange_struct);
|
||||
pack->pBuffer = new uchar[pack->size];
|
||||
memset(pack->pBuffer, 0, sizeof(ServerZoneStateChange_struct));
|
||||
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
|
||||
pack->opcode = ServerOP_ZoneShutdown;
|
||||
strcpy(s->adminname, tmpname);
|
||||
if (sep.arg[1][0] >= '0' && sep.arg[1][0] <= '9')
|
||||
s->ZoneServerID = atoi(sep.arg[1]);
|
||||
else
|
||||
s->zoneid = database.GetZoneID(sep.arg[1]);
|
||||
|
||||
ZoneServer* zs = 0;
|
||||
if (s->ZoneServerID != 0)
|
||||
zs = zoneserver_list.FindByID(s->ZoneServerID);
|
||||
else if (s->zoneid != 0)
|
||||
zs = zoneserver_list.FindByName(database.GetZoneName(s->zoneid));
|
||||
else
|
||||
SendMessage(1, "Error: ZoneShutdown: neither ID nor name specified");
|
||||
|
||||
if (zs == 0)
|
||||
SendMessage(1, "Error: ZoneShutdown: zoneserver not found");
|
||||
else
|
||||
zs->SendPacket(pack);
|
||||
|
||||
delete pack;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "zonebootup") == 0 && admin >= consoleZoneStatus) {
|
||||
if (sep.arg[2][0] == 0 || !sep.IsNumber(1)) {
|
||||
SendMessage(1, "Usage: zonebootup ZoneServerID# zoneshortname");
|
||||
} else {
|
||||
char tmpname[64];
|
||||
tmpname[0] = '*';
|
||||
strcpy(&tmpname[1], paccountname);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Console ZoneBootup: %s, %s, %s",tmpname,sep.arg[2],sep.arg[1]);
|
||||
zoneserver_list.SOPZoneBootup(tmpname, atoi(sep.arg[1]), sep.arg[2], (bool) (strcasecmp(sep.arg[3], "static") == 0));
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "worldshutdown") == 0 && admin >= consoleWorldStatus) {
|
||||
int32 time, interval;
|
||||
if(sep.IsNumber(1) && sep.IsNumber(2) && ((time=atoi(sep.arg[1]))>0) && ((interval=atoi(sep.arg[2]))>0)) {
|
||||
zoneserver_list.WorldShutDown(time, interval);
|
||||
}
|
||||
else if(strcasecmp(sep.arg[1], "now") == 0) {
|
||||
zoneserver_list.WorldShutDown(0, 0);
|
||||
}
|
||||
else if(strcasecmp(sep.arg[1], "disable") == 0) {
|
||||
SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
|
||||
zoneserver_list.SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
|
||||
zoneserver_list.shutdowntimer->Disable();
|
||||
zoneserver_list.reminder->Disable();
|
||||
}
|
||||
else {
|
||||
SendMessage(1, "Usage: worldshutdown [now] [disable] ([time] [interval])");
|
||||
//Go ahead and shut down since that's what this used to do when invoked this way.
|
||||
zoneserver_list.WorldShutDown(0, 0);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "lock") == 0 && admin >= consoleLockStatus) {
|
||||
WorldConfig::LockWorld();
|
||||
if (loginserverlist.Connected()) {
|
||||
loginserverlist.SendStatus();
|
||||
SendMessage(1, "World locked.");
|
||||
}
|
||||
else {
|
||||
SendMessage(1, "World locked, but login server not connected.");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "unlock") == 0 && admin >= consoleLockStatus) {
|
||||
WorldConfig::UnlockWorld();
|
||||
if (loginserverlist.Connected()) {
|
||||
loginserverlist.SendStatus();
|
||||
SendMessage(1, "World unlocked.");
|
||||
}
|
||||
else {
|
||||
SendMessage(1, "World unlocked, but login server not connected.");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "version") == 0 && admin >= consoleWorldStatus) {
|
||||
SendMessage(1, "Current version information.");
|
||||
SendMessage(1, " %s", CURRENT_VERSION);
|
||||
SendMessage(1, " Compiled on: %s at %s", COMPILE_DATE, COMPILE_TIME);
|
||||
SendMessage(1, " Last modified on: %s", LAST_MODIFIED);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "serverinfo") == 0 && admin >= 200) {
|
||||
if (strcasecmp(sep.arg[1], "os") == 0) {
|
||||
#ifdef _WINDOWS
|
||||
GetOS();
|
||||
char intbuffer [sizeof(unsigned long)];
|
||||
SendMessage(1, "Operating system information.");
|
||||
SendMessage(1, " %s", Ver_name);
|
||||
SendMessage(1, " Build number: %s", ultoa(Ver_build, intbuffer, 10));
|
||||
SendMessage(1, " Minor version: %s", ultoa(Ver_min, intbuffer, 10));
|
||||
SendMessage(1, " Major version: %s", ultoa(Ver_maj, intbuffer, 10));
|
||||
SendMessage(1, " Platform Id: %s", ultoa(Ver_pid, intbuffer, 10));
|
||||
#else
|
||||
char os_string[100];
|
||||
SendMessage(1, "Operating system information.");
|
||||
SendMessage(1, " %s", GetOS(os_string));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
SendMessage(1, "Usage: Serverinfo [type]");
|
||||
SendMessage(1, " OS - Operating system version information.");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= 201) {
|
||||
client_list.SendCLEList(admin, 0, this, sep.argplus[1]);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "zonelock") == 0 && admin >= consoleZoneStatus) {
|
||||
if (strcasecmp(sep.arg[1], "list") == 0) {
|
||||
zoneserver_list.ListLockedZones(0, this);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[1], "lock") == 0 && admin >= 101) {
|
||||
uint16 tmp = database.GetZoneID(sep.arg[2]);
|
||||
if (tmp) {
|
||||
if (zoneserver_list.SetLockedZone(tmp, true))
|
||||
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(tmp));
|
||||
else
|
||||
SendMessage(1, "Failed to change lock");
|
||||
}
|
||||
else
|
||||
SendMessage(1, "Usage: #zonelock lock [zonename]");
|
||||
}
|
||||
else if (strcasecmp(sep.arg[1], "unlock") == 0 && admin >= 101) {
|
||||
uint16 tmp = database.GetZoneID(sep.arg[2]);
|
||||
if (tmp) {
|
||||
if (zoneserver_list.SetLockedZone(tmp, false))
|
||||
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(tmp));
|
||||
else
|
||||
SendMessage(1, "Failed to change lock");
|
||||
}
|
||||
else
|
||||
SendMessage(1, "Usage: #zonelock unlock [zonename]");
|
||||
}
|
||||
else {
|
||||
SendMessage(1, "#zonelock sub-commands");
|
||||
SendMessage(1, " list");
|
||||
if (admin >= 101) {
|
||||
SendMessage(1, " lock [zonename]");
|
||||
SendMessage(1, " unlock [zonename]");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "reloadworld") == 0 && admin > 101)
|
||||
{
|
||||
SendEmoteMessage(0,0,0,15,"Reloading World...");
|
||||
auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct));
|
||||
ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer;
|
||||
RW->Option = 1;
|
||||
zoneserver_list.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "") == 0){
|
||||
/* Hit Enter with no command */
|
||||
}
|
||||
else {
|
||||
SendMessage(1, "Command unknown.");
|
||||
}
|
||||
if (state == CONSOLE_STATE_CONNECTED)
|
||||
SendPrompt();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::SendPrompt() {
|
||||
if (tcpc->GetEcho())
|
||||
SendMessage(0, "%s> ", paccountname);
|
||||
}
|
||||
|
||||
109
world/console.h
109
world/console.h
@ -1,109 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CONSOLE_H
|
||||
#define CONSOLE_H
|
||||
|
||||
enum {
|
||||
consoleLoginStatus = 50, //ability to log in, basic commands.
|
||||
httpLoginStatus = 100, //can log into the HTTP interface
|
||||
consoleFlagStatus = 200, //flag
|
||||
consoleKickStatus = 150, //kick
|
||||
consoleLockStatus = 150, //world lock/unlock
|
||||
consoleZoneStatus = 150, //zone up/down/lock
|
||||
consolePassStatus = 200, //change password
|
||||
consoleWorldStatus = 200, //world shutdown
|
||||
consoleOpcodesStatus = 250
|
||||
};
|
||||
|
||||
#define CONSOLE_STATE_USERNAME 0
|
||||
#define CONSOLE_STATE_PASSWORD 1
|
||||
#define CONSOLE_STATE_CONNECTED 2
|
||||
#define CONSOLE_STATE_CLOSED 3
|
||||
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/queue.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "world_tcp_connection.h"
|
||||
#include "../common/mutex.h"
|
||||
|
||||
struct ServerChannelMessage_Struct;
|
||||
|
||||
class Console : public WorldTCPConnection {
|
||||
public:
|
||||
Console(EmuTCPConnection* itcpc);
|
||||
virtual ~Console();
|
||||
virtual inline bool IsConsole() { return true; }
|
||||
|
||||
bool Process();
|
||||
void Send(const char* message);
|
||||
int16 Admin() { return admin; }
|
||||
uint32 GetIP() { return tcpc->GetrIP(); }
|
||||
uint16 GetPort() { return tcpc->GetrPort(); }
|
||||
void ProcessCommand(const char* command);
|
||||
void Die();
|
||||
|
||||
bool SendChannelMessage(const ServerChannelMessage_Struct* scm);
|
||||
bool SendEmoteMessage(uint32 type, const char* message, ...);
|
||||
bool SendEmoteMessageRaw(uint32 type, const char* message);
|
||||
void SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...);
|
||||
void SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message);
|
||||
void SendMessage(uint8 newline, const char* message, ...);
|
||||
|
||||
const char* GetName() { return paccountname; }
|
||||
const char* AccountName() { return paccountname; }
|
||||
uint32 AccountID() { return paccountid; }
|
||||
private:
|
||||
EmuTCPConnection* tcpc;
|
||||
|
||||
Timer timeout_timer;
|
||||
Timer prompt_timer;
|
||||
|
||||
void SendPrompt();
|
||||
|
||||
uint32 paccountid;
|
||||
char paccountname[30];
|
||||
bool pAcceptMessages;
|
||||
|
||||
uint8 state;
|
||||
|
||||
int16 admin;
|
||||
uchar textbuf[1024];
|
||||
int bufindex;
|
||||
};
|
||||
|
||||
class ConsoleList
|
||||
{
|
||||
public:
|
||||
ConsoleList() {}
|
||||
~ConsoleList() {}
|
||||
|
||||
void Add(Console* con);
|
||||
void Process();
|
||||
void KillAll();
|
||||
|
||||
void SendChannelMessage(const ServerChannelMessage_Struct* scm);
|
||||
void SendConsoleWho(WorldTCPConnection* connection, const char* to, int16 admin, char** output, uint32* outsize, uint32* outlen);
|
||||
void SendEmoteMessage(uint32 type, const char* message, ...);
|
||||
void SendEmoteMessageRaw(uint32 type, const char* message);
|
||||
Console* FindByAccountName(const char* accname);
|
||||
private:
|
||||
LinkedList<Console*> list;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -1,335 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/global_define.h"
|
||||
#include "eqw_http_handler.h"
|
||||
#include "../common/SocketLib/Base64.h"
|
||||
#include "eqw_parser.h"
|
||||
#include "eqw.h"
|
||||
#include "http_request.h"
|
||||
|
||||
#include "worlddb.h"
|
||||
#include "console.h"
|
||||
|
||||
Mime EQWHTTPHandler::s_mime;
|
||||
#ifdef EMBPERL
|
||||
EQWParser *EQWHTTPHandler::s_parser = nullptr;
|
||||
#endif
|
||||
const int EQWHTTPHandler::READ_BUFFER_LEN = 1024; //for page IO, was a static const member, but VC6 got mad.
|
||||
|
||||
EQWHTTPHandler::EQWHTTPHandler(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort)
|
||||
: HttpdSocket(ID,in_socket,irIP,irPort),
|
||||
m_closeOnFinish(false)
|
||||
{
|
||||
}
|
||||
|
||||
EQWHTTPHandler::~EQWHTTPHandler() {
|
||||
|
||||
}
|
||||
|
||||
#ifdef EMBPERL
|
||||
EQWParser *EQWHTTPHandler::GetParser() {
|
||||
if(s_parser == nullptr) {
|
||||
EQW::Singleton()->ClearOutput();
|
||||
s_parser = new EQWParser();
|
||||
const std::string &res = EQW::Singleton()->GetOutput();
|
||||
if(!res.empty()) {
|
||||
printf("EQWParser Init output:\n%s\n\n", res.c_str());
|
||||
EQW::Singleton()->ClearOutput();
|
||||
}
|
||||
}
|
||||
return(s_parser);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*void EQWHTTPHandler::OnWrite() {
|
||||
HttpdSocket::OnWrite();
|
||||
if(m_closeOnFinish && GetOutputLength() == 0) {
|
||||
// printf("CLOSING\n");
|
||||
Close();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
void EQWHTTPHandler::Exec() {
|
||||
m_sentHeaders = false;
|
||||
m_responseCode = "200";
|
||||
// printf("Request: %s, %s, %s, %s.\n", GetMethod().c_str(), GetUrl().c_str(), GetUri().c_str(), GetQueryString().c_str());
|
||||
|
||||
SetHttpVersion("HTTP/1.0");
|
||||
AddResponseHeader("Connection", "close");
|
||||
|
||||
if(GetUri().find("..") != std::string::npos) {
|
||||
SendResponse("403", "Forbidden");
|
||||
printf("%s is forbidden.\n", GetUri().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(!CheckAuth()) {
|
||||
AddResponseHeader("Content-type", "text/plain");
|
||||
AddResponseHeader("WWW-Authenticate", "Basic realm=\"EQEmulator\"");
|
||||
SendResponse("401", "Authorization Required");
|
||||
SendString("Gotta Authenticate.");
|
||||
} else {
|
||||
std::string::size_type start = GetUri().find_first_not_of('/');
|
||||
std::string page;
|
||||
if(start != std::string::npos)
|
||||
page = GetUri().substr(start);
|
||||
else
|
||||
page = "index.html";
|
||||
SendPage(page);
|
||||
}
|
||||
/* if (!Detach()) {
|
||||
printf("Unable to detach...\n");
|
||||
}
|
||||
if(GetOutputLength() > 0) {
|
||||
//we cannot close yet
|
||||
m_closeOnFinish = true;
|
||||
} else {
|
||||
Close();
|
||||
}*/
|
||||
Free(); //the "app" side (us) is done with this connection too...
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
void EQWHTTPHandler::OnHeader(const std::string& key,const std::string& value) {
|
||||
HttpdSocket::OnHeader(key, value);
|
||||
|
||||
if (!strcasecmp(key.c_str(),"Authorization")) {
|
||||
if(strncasecmp(value.c_str(), "Basic ", 6)) {
|
||||
printf("Invalid auth type. Expected Basic: %s\n", value.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string dec;
|
||||
Base64::decode(value.c_str() + 6, dec);
|
||||
|
||||
std::string::size_type cpos;
|
||||
cpos = dec.find_first_of(':');
|
||||
if(cpos == std::string::npos) {
|
||||
printf("Invalid auth string: %s\n", dec.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_username = dec.substr(0, cpos);
|
||||
m_password = dec.substr(cpos+1);
|
||||
}
|
||||
}
|
||||
|
||||
//we should prolly cache login info here... if we load a fresh page, we could be checking
|
||||
//their auth dozens of times rather quickly...
|
||||
bool EQWHTTPHandler::CheckAuth() const {
|
||||
if(m_username.length() < 1)
|
||||
return(false);
|
||||
|
||||
int16 status = 0;
|
||||
uint32 acctid = database.CheckLogin(m_username.c_str(), m_password.c_str(), &status);
|
||||
if(acctid == 0) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Login autentication failed for %s with '%s'", m_username.c_str(), m_password.c_str());
|
||||
return(false);
|
||||
}
|
||||
if(status < httpLoginStatus) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Login of %s failed: status too low.", m_username.c_str());
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void EQWHTTPHandler::SendPage(const std::string &file) {
|
||||
|
||||
std::string path = "templates/";
|
||||
path += file;
|
||||
|
||||
FILE *f = fopen(path.c_str(), "rb");
|
||||
if(f == nullptr) {
|
||||
SendResponse("404", "Not Found");
|
||||
SendString("Not found.");
|
||||
printf("%s not found.\n", file.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string type = s_mime.GetMimeFromFilename(file);
|
||||
AddResponseHeader("Content-type", type);
|
||||
|
||||
bool process = false;
|
||||
#ifdef EMBPERL
|
||||
if(type == "text/html")
|
||||
process = true;
|
||||
else {
|
||||
//not processing, send headers right away
|
||||
#endif
|
||||
SendResponse("200", "OK");
|
||||
#ifdef EMBPERL
|
||||
}
|
||||
#endif
|
||||
|
||||
auto buffer = new char[READ_BUFFER_LEN + 1];
|
||||
size_t len;
|
||||
std::string to_process;
|
||||
while((len = fread(buffer, 1, READ_BUFFER_LEN, f)) > 0) {
|
||||
buffer[len] = '\0';
|
||||
if(process)
|
||||
to_process += buffer;
|
||||
else
|
||||
SendBuf(buffer, len);
|
||||
}
|
||||
delete[] buffer;
|
||||
fclose(f);
|
||||
#ifdef EMBPERL
|
||||
if(process) {
|
||||
//convert the base form into a useful perl exportable form
|
||||
HTTPRequest req(this, GetHttpForm());
|
||||
GetParser()->SetHTTPRequest("testing", &req);
|
||||
|
||||
//parse out the page and potentially pass some stuff on to perl.
|
||||
ProcessAndSend(to_process);
|
||||
|
||||
//clear out the form, just in case (since it gets destroyed next)
|
||||
GetParser()->SetHTTPRequest("testing", nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EQWHTTPHandler::LoadMimeTypes(const char *filename) {
|
||||
return(s_mime.LoadMimeFile(filename));
|
||||
}
|
||||
|
||||
#ifdef EMBPERL
|
||||
void EQWHTTPHandler::ProcessAndSend(const std::string &str) {
|
||||
std::string::size_type len = str.length();
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type pos, end;
|
||||
|
||||
while((pos = str.find("<?", start)) != std::string::npos) {
|
||||
//send all the crap leading up to the script block
|
||||
if(pos != start) {
|
||||
ProcessText(str.c_str() + start, pos-start);
|
||||
}
|
||||
|
||||
//look for the end of this script block...
|
||||
end = str.find("?>", pos+2);
|
||||
if(end == std::string::npos) {
|
||||
//terminal ?> not found... should issue a warning or something...
|
||||
std::string scriptBody = str.substr(pos+2);
|
||||
ProcessScript(scriptBody);
|
||||
start = len;
|
||||
break;
|
||||
} else {
|
||||
//script only consumes some of this buffer...
|
||||
std::string scriptBody = str.substr(pos+2, end-pos-2);
|
||||
ProcessScript(scriptBody);
|
||||
start = end + 2;
|
||||
}
|
||||
}
|
||||
|
||||
//send whatever is left over
|
||||
if(start != len)
|
||||
ProcessText(str.c_str() + start, len-start);
|
||||
}
|
||||
|
||||
void EQWHTTPHandler::ProcessScript(const std::string &script_body) {
|
||||
const char *script = script_body.c_str();
|
||||
if(strcmp("perl", script) == 0)
|
||||
script += 4; //allow <?perl
|
||||
|
||||
// printf("Script: ''''%s''''\n\n", script_body.c_str());
|
||||
|
||||
GetParser()->EQW_eval("testing", script_body.c_str());
|
||||
const std::string &res = EQW::Singleton()->GetOutput();
|
||||
if(!res.empty()) {
|
||||
ProcessText(res.c_str(), res.length());
|
||||
EQW::Singleton()->ClearOutput();
|
||||
}
|
||||
}
|
||||
|
||||
void EQWHTTPHandler::ProcessText(const char *txt, int len) {
|
||||
if(!m_sentHeaders) {
|
||||
SendResponse(m_responseCode, "OK");
|
||||
m_sentHeaders = true;
|
||||
}
|
||||
SendBuf(txt, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
EQWHTTPServer::EQWHTTPServer()
|
||||
: m_port(0)
|
||||
{
|
||||
}
|
||||
|
||||
void EQWHTTPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) {
|
||||
auto conn = new EQWHTTPHandler(ID, in_socket, irIP, irPort);
|
||||
AddConnection(conn);
|
||||
}
|
||||
|
||||
void EQWHTTPServer::Stop() {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Requesting that HTTP Service stop.");
|
||||
m_running = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
bool EQWHTTPServer::Start(uint16 port, const char *mime_file) {
|
||||
if(m_running) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "HTTP Service is already running on port %d", m_port);
|
||||
return(false);
|
||||
}
|
||||
|
||||
//load up our nice mime types
|
||||
if(!EQWHTTPHandler::LoadMimeTypes(mime_file)) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Failed to load mime types from '%s'", mime_file);
|
||||
return(false);
|
||||
} else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Loaded mime types from %s", mime_file);
|
||||
}
|
||||
|
||||
//fire up the server thread
|
||||
char errbuf[TCPServer_ErrorBufferSize];
|
||||
if(!Open(port, errbuf)) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Unable to bind to port %d for HTTP service: %s", port, errbuf);
|
||||
return(false);
|
||||
}
|
||||
|
||||
m_running = true;
|
||||
m_port = port;
|
||||
|
||||
/*
|
||||
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(ThreadProc, 0, this);
|
||||
#else
|
||||
pthread_create(&m_thread, nullptr, ThreadProc, this);
|
||||
#endif*/
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/*
|
||||
void EQWHTTPServer::Run() {
|
||||
Log.LogDebugType(Logs::Detail, Logs::World_Server, "HTTP Processing thread started on port %d", m_port);
|
||||
do {
|
||||
#warning DELETE THIS IF YOU DONT USE IT
|
||||
Sleep(10);
|
||||
} while(m_running);
|
||||
Log.LogDebugType(Logs::Detail, Logs::World_Server, "HTTP Processing thread terminating on port %d", m_port);
|
||||
}
|
||||
|
||||
ThreadReturnType EQWHTTPServer::ThreadProc(void *data) {
|
||||
((EQWHTTPServer *) data)->Run();
|
||||
THREAD_RETURN(nullptr);
|
||||
}*/
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQWHTTPHandler_H
|
||||
#define EQWHTTPHandler_H
|
||||
|
||||
#include "../common/tcp_server.h"
|
||||
#include "../common/tcp_connection.h"
|
||||
#include "../common/SocketLib/HttpdSocket.h"
|
||||
#include "../common/SocketLib/Mime.h"
|
||||
#include "../common/types.h"
|
||||
|
||||
class EQWParser;
|
||||
|
||||
class EQWHTTPHandler : public HttpdSocket {
|
||||
static const int READ_BUFFER_LEN;
|
||||
public:
|
||||
EQWHTTPHandler(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
|
||||
virtual ~EQWHTTPHandler();
|
||||
|
||||
void SetResponseCode(const char *code) { m_responseCode = code; }
|
||||
|
||||
//HttpdSocket interface:
|
||||
virtual void Exec();
|
||||
virtual void OnHeader(const std::string& key,const std::string& value);
|
||||
|
||||
static bool LoadMimeTypes(const char *filename);
|
||||
protected:
|
||||
bool CheckAuth() const;
|
||||
void SendPage(const std::string &file);
|
||||
|
||||
//credentials
|
||||
std::string m_username;
|
||||
std::string m_password;
|
||||
|
||||
bool m_closeOnFinish;
|
||||
std::string m_responseCode;
|
||||
bool m_sentHeaders;
|
||||
|
||||
|
||||
//our mime type manager
|
||||
static Mime s_mime;
|
||||
|
||||
|
||||
#ifdef EMBPERL
|
||||
void ProcessAndSend(const std::string &entire_html_page);
|
||||
void ProcessScript(const std::string &script_body);
|
||||
void ProcessText(const char *txt, int len);
|
||||
|
||||
static EQWParser *GetParser();
|
||||
|
||||
private:
|
||||
static EQWParser *s_parser;
|
||||
#endif
|
||||
};
|
||||
|
||||
class EQWHTTPServer : protected TCPServer<EQWHTTPHandler> {
|
||||
public:
|
||||
EQWHTTPServer();
|
||||
|
||||
bool Start(uint16 port, const char *mime_file);
|
||||
void Stop();
|
||||
|
||||
|
||||
protected:
|
||||
volatile bool m_running;
|
||||
uint16 m_port;
|
||||
|
||||
virtual void CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort);
|
||||
|
||||
/* //I decided to put this into its own thread so that the HTTP pages
|
||||
//cannot block the main world server's operation.
|
||||
static ThreadReturnType ThreadProc(void* tmp);
|
||||
void Run();
|
||||
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
pthread_t m_thread;
|
||||
#endif*/
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,346 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//a lot of this is copied from embperl.cpp, but I didnt feel like factoring the common stuff out
|
||||
|
||||
#ifdef EMBPERL
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "eqw_parser.h"
|
||||
#include "eqw.h"
|
||||
#include "../common/eqdb.h"
|
||||
|
||||
#include "worlddb.h"
|
||||
|
||||
#ifndef GvCV_set
|
||||
#define GvCV_set(gv,cv) (GvCV(gv) = (cv))
|
||||
#endif
|
||||
|
||||
XS(XS_EQWIO_PRINT);
|
||||
|
||||
//so embedded scripts can use xs extensions (ala 'use socket;')
|
||||
EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
|
||||
EXTERN_C XS(boot_EQW);
|
||||
EXTERN_C XS(boot_EQDB);
|
||||
EXTERN_C XS(boot_EQDBRes);
|
||||
EXTERN_C XS(boot_HTTPRequest);
|
||||
EXTERN_C XS(boot_EQLConfig);
|
||||
|
||||
EXTERN_C void xs_init(pTHX)
|
||||
{
|
||||
char file[256];
|
||||
strncpy(file, __FILE__, 256);
|
||||
file[255] = '\0';
|
||||
|
||||
char buf[128]; //shouldent have any function names longer than this.
|
||||
|
||||
//add the strcpy stuff to get rid of const warnings....
|
||||
|
||||
newXS(strcpy(buf, "DynaLoader::boot_DynaLoader"), boot_DynaLoader, file);
|
||||
newXS(strcpy(buf, "EQW::boot_EQW"), boot_EQW, file);
|
||||
newXS(strcpy(buf, "EQDB::boot_EQDB"), boot_EQDB, file);
|
||||
newXS(strcpy(buf, "EQDBRes::boot_EQDBRes"), boot_EQDBRes, file);
|
||||
newXS(strcpy(buf, "HTTPRequest::boot_HTTPRequest"), boot_HTTPRequest, file);
|
||||
newXS(strcpy(buf, "EQLConfig::boot_EQLConfig"), boot_EQLConfig, file);
|
||||
newXS(strcpy(buf, "EQWIO::PRINT"), XS_EQWIO_PRINT, file);
|
||||
}
|
||||
|
||||
EQWParser::EQWParser() {
|
||||
//setup perl...
|
||||
my_perl = perl_alloc();
|
||||
_empty_sv = newSV(0);
|
||||
if(!my_perl)
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Error: perl_alloc failed!");
|
||||
else
|
||||
DoInit();
|
||||
}
|
||||
|
||||
void EQWParser::DoInit() {
|
||||
const char *argv_eqemu[] = { "",
|
||||
"-w", "-W",
|
||||
"-e", "0;", nullptr };
|
||||
|
||||
int argc = 5;
|
||||
|
||||
char **argv = (char **)argv_eqemu;
|
||||
char **env = { nullptr };
|
||||
|
||||
PL_perl_destruct_level = 1;
|
||||
|
||||
perl_construct(my_perl);
|
||||
|
||||
PERL_SYS_INIT3(&argc, &argv, &env);
|
||||
|
||||
perl_parse(my_perl, xs_init, argc, argv, env);
|
||||
|
||||
perl_run(my_perl);
|
||||
|
||||
//a little routine we use a lot.
|
||||
eval_pv("sub my_eval {eval $_[0];}", TRUE); //dies on error
|
||||
|
||||
//ruin the perl exit and command:
|
||||
eval_pv("sub my_exit {}",TRUE);
|
||||
eval_pv("sub my_sleep {}",TRUE);
|
||||
if(gv_stashpv("CORE::GLOBAL", FALSE)) {
|
||||
GV *exitgp = gv_fetchpv("CORE::GLOBAL::exit", TRUE, SVt_PVCV);
|
||||
GvCV_set(exitgp, perl_get_cv("my_exit", TRUE)); //dies on error
|
||||
GvIMPORTED_CV_on(exitgp);
|
||||
GV *sleepgp = gv_fetchpv("CORE::GLOBAL::sleep", TRUE, SVt_PVCV);
|
||||
GvCV_set(sleepgp, perl_get_cv("my_sleep", TRUE)); //dies on error
|
||||
GvIMPORTED_CV_on(sleepgp);
|
||||
}
|
||||
|
||||
//setup eval_file
|
||||
eval_pv(
|
||||
"our %Cache;"
|
||||
"use Symbol qw(delete_package);"
|
||||
"sub eval_file {"
|
||||
"my($package, $filename) = @_;"
|
||||
"$filename=~s/\'//g;"
|
||||
"if(! -r $filename) { print \"Unable to read perl file '$filename'\\n\"; return; }"
|
||||
"my $mtime = -M $filename;"
|
||||
"if(defined $Cache{$package}{mtime}&&$Cache{$package}{mtime} <= $mtime && !($package eq 'plugin')){"
|
||||
" return;"
|
||||
"} else {"
|
||||
//we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
|
||||
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require '$filename'; \");"
|
||||
"}"
|
||||
"}"
|
||||
,FALSE);
|
||||
|
||||
//make a tie-able class to capture IO and get it where it needs to go
|
||||
eval_pv(
|
||||
"package EQWIO; "
|
||||
// "&boot_EQEmuIO;"
|
||||
"sub TIEHANDLE { my $me = bless {}, $_[0]; $me->PRINT('Creating '.$me); return($me); } "
|
||||
"sub WRITE { } "
|
||||
"sub PRINTF { my $me = shift; my $fmt = shift; $me->PRINT(sprintf($fmt, @_)); } "
|
||||
"sub CLOSE { my $me = shift; $me->PRINT('Closing '.$me); } "
|
||||
"sub DESTROY { my $me = shift; $me->PRINT('Destroying '.$me); } "
|
||||
//this ties us for all packages
|
||||
"package MAIN;"
|
||||
" if(tied *STDOUT) { untie(*STDOUT); }"
|
||||
" if(tied *STDERR) { untie(*STDERR); }"
|
||||
" tie *STDOUT, 'EQWIO';"
|
||||
" tie *STDERR, 'EQWIO';"
|
||||
,FALSE);
|
||||
|
||||
eval_pv(
|
||||
"package world; "
|
||||
,FALSE
|
||||
);
|
||||
|
||||
//make sure the EQW pointer is set up in this package
|
||||
EQW *curc = EQW::Singleton();
|
||||
SV *l = get_sv("world::EQW", true);
|
||||
if(curc != nullptr) {
|
||||
sv_setref_pv(l, "EQW", curc);
|
||||
} else {
|
||||
//clear out the value, mainly to get rid of blessedness
|
||||
sv_setsv(l, _empty_sv);
|
||||
}
|
||||
|
||||
//make sure the EQDB pointer is set up in this package
|
||||
EQDB::SetMySQL(database.getMySQL());
|
||||
EQDB *curc_db = EQDB::Singleton();
|
||||
SV *l_db = get_sv("world::EQDB", true);
|
||||
if(curc_db != nullptr) {
|
||||
sv_setref_pv(l_db, "EQDB", curc_db);
|
||||
} else {
|
||||
//clear out the value, mainly to get rid of blessedness
|
||||
sv_setsv(l_db, _empty_sv);
|
||||
}
|
||||
|
||||
//load up EQW
|
||||
eval_pv(
|
||||
"package EQW;"
|
||||
"&boot_EQW;" //load our EQW XS
|
||||
"package EQDB;"
|
||||
"&boot_EQDB;" //load our EQW XS
|
||||
"package EQDBRes;"
|
||||
"&boot_EQDBRes;" //load our EQW XS
|
||||
"package HTTPRequest;"
|
||||
"&boot_HTTPRequest;" //load our HTTPRequest XS
|
||||
"package EQLConfig;"
|
||||
"&boot_EQLConfig;" //load our EQLConfig XS
|
||||
, FALSE );
|
||||
|
||||
|
||||
#ifdef EMBPERL_PLUGIN
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Loading worldui perl plugins.");
|
||||
std::string err;
|
||||
if(!eval_file("world", "worldui.pl", err)) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Warning - world.pl: %s", err.c_str());
|
||||
}
|
||||
|
||||
eval_pv(
|
||||
"package world; "
|
||||
"if(opendir(D,'worldui')) { "
|
||||
" my @d = readdir(D);"
|
||||
" closedir(D);"
|
||||
" foreach(@d){ "
|
||||
" next unless(/\\.pl$); "
|
||||
" require 'templates/'.$_;"
|
||||
" }"
|
||||
"}"
|
||||
,FALSE);
|
||||
#endif //EMBPERL_PLUGIN
|
||||
}
|
||||
|
||||
EQWParser::~EQWParser() {
|
||||
//removed to try to stop perl from exploding on reload, we'll see
|
||||
/* eval_pv(
|
||||
"package quest;"
|
||||
" untie *STDOUT;"
|
||||
" untie *STDERR;"
|
||||
,FALSE);
|
||||
*/
|
||||
perl_free(my_perl);
|
||||
}
|
||||
|
||||
bool EQWParser::eval_file(const char * packagename, const char * filename, std::string &error)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
args.push_back(packagename);
|
||||
args.push_back(filename);
|
||||
return(dosub("eval_file", args, error));
|
||||
}
|
||||
|
||||
bool EQWParser::dosub(const char * subname, const std::vector<std::string> &args, std::string &error, int mode) {
|
||||
bool err = false;
|
||||
dSP; // initialize stack pointer
|
||||
ENTER; // everything created after here
|
||||
SAVETMPS; // ...is a temporary variable
|
||||
PUSHMARK(SP); // remember the stack pointer
|
||||
if(!args.empty())
|
||||
{
|
||||
for (auto i = args.begin(); i != args.end(); ++i) { /* push the arguments onto the perl stack */
|
||||
XPUSHs(sv_2mortal(newSVpv(i->c_str(), i->length())));
|
||||
}
|
||||
}
|
||||
PUTBACK; // make local stack pointer global
|
||||
call_pv(subname, mode); /*eval our code*/
|
||||
SPAGAIN; // refresh stack pointer
|
||||
if(SvTRUE(ERRSV)) {
|
||||
err = true;
|
||||
}
|
||||
FREETMPS; // free temp values
|
||||
LEAVE; // ...and the XPUSHed "mortal" args.
|
||||
|
||||
if(err) {
|
||||
error = "Perl runtime error: ";
|
||||
error += SvPVX(ERRSV);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool EQWParser::eval(const char * code, std::string &error) {
|
||||
std::vector<std::string> arg;
|
||||
arg.push_back(code);
|
||||
return(dosub("my_eval", arg, error, G_SCALAR|G_DISCARD|G_EVAL|G_KEEPERR));
|
||||
}
|
||||
|
||||
void EQWParser::EQW_eval(const char *pkg, const char *code) {
|
||||
char namebuf[64];
|
||||
|
||||
snprintf(namebuf, 64, "package %s;", pkg);
|
||||
eval_pv(namebuf, FALSE);
|
||||
|
||||
//make sure the EQW pointer is set up
|
||||
EQW *curc = EQW::Singleton();
|
||||
snprintf(namebuf, 64, "EQW");
|
||||
// snprintf(namebuf, 64, "%s::EQW", pkg);
|
||||
SV *l = get_sv(namebuf, true);
|
||||
if(curc != nullptr) {
|
||||
sv_setref_pv(l, "EQW", curc);
|
||||
} else {
|
||||
//clear out the value, mainly to get rid of blessedness
|
||||
sv_setsv(l, _empty_sv);
|
||||
}
|
||||
//make sure the EQDB pointer is set up
|
||||
EQDB *curc_db = EQDB::Singleton();
|
||||
snprintf(namebuf, 64, "EQDB");
|
||||
// snprintf(namebuf, 64, "%s::EQW", pkg);
|
||||
SV *l_db = get_sv(namebuf, true);
|
||||
if(curc_db != nullptr) {
|
||||
sv_setref_pv(l_db, "EQDB", curc_db);
|
||||
} else {
|
||||
//clear out the value, mainly to get rid of blessedness
|
||||
sv_setsv(l_db, _empty_sv);
|
||||
}
|
||||
|
||||
std::string err;
|
||||
if(!eval(code, err)) {
|
||||
EQW::Singleton()->AppendOutput(err.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EQWParser::SetHTTPRequest(const char *pkg, HTTPRequest *it) {
|
||||
char namebuf[64];
|
||||
|
||||
snprintf(namebuf, 64, "package %s;", pkg);
|
||||
eval_pv(namebuf, FALSE);
|
||||
|
||||
snprintf(namebuf, 64, "request");
|
||||
// snprintf(namebuf, 64, "%s::EQW", pkg);
|
||||
SV *l = get_sv(namebuf, true);
|
||||
if(it != nullptr) {
|
||||
sv_setref_pv(l, "HTTPRequest", it);
|
||||
} else {
|
||||
//clear out the value, mainly to get rid of blessedness
|
||||
sv_setsv(l, _empty_sv);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
$editors = array();
|
||||
$editors["merchant"] = new MerchantEditor();
|
||||
#... for other editors
|
||||
|
||||
if(defined($editors[$editor])) {
|
||||
$edit = $editors[$editor];
|
||||
$edit->dispatch($action);
|
||||
}
|
||||
|
||||
class MerchantEditor extends BaseEditor {
|
||||
MerchantEditor() {
|
||||
$this->RegisterAction(0, "get_merchantlist", "merchant/merchant.tmpl.php", "no");
|
||||
$this->RegisterAction(1, "get_merchantlist", "merchant/merchant.edit.tmpl.php", "no");
|
||||
}
|
||||
}
|
||||
|
||||
function dispatch() {
|
||||
my $dispatcher = $this->_dispatchers[$action];
|
||||
$body = new Template($dispatcher["template"]);
|
||||
my $proc = $dispatcher["proc"];
|
||||
$vars = $this->$proc();
|
||||
if($dispatcher["guestmode"] == "no") {
|
||||
check_authorization();
|
||||
}
|
||||
if ($vars) {
|
||||
foreach ($vars as $key=>$value) {
|
||||
$body->set($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#endif //EMBPERL
|
||||
|
||||
@ -1,72 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQWPARSER_H_
|
||||
#define EQWPARSER_H_
|
||||
|
||||
|
||||
|
||||
#ifdef EMBPERL
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "../common/useperl.h"
|
||||
|
||||
class HTTPRequest;
|
||||
|
||||
class EQWParser {
|
||||
public:
|
||||
EQWParser();
|
||||
~EQWParser();
|
||||
|
||||
void EQW_eval(const char *pkg, const char *code);
|
||||
void SetHTTPRequest(const char *pkg, HTTPRequest *it);
|
||||
|
||||
//put an integer into a perl varable
|
||||
void seti(const char *varname, int val) const {
|
||||
SV *t = get_sv(varname, true);
|
||||
sv_setiv(t, val);
|
||||
}
|
||||
//put a real into a perl varable
|
||||
void setd(const char *varname, float val) const {
|
||||
SV *t = get_sv(varname, true);
|
||||
sv_setnv(t, val);
|
||||
}
|
||||
//put a string into a perl varable
|
||||
void setstr(const char *varname, const char *val) const {
|
||||
SV *t = get_sv(varname, true);
|
||||
sv_setpv(t, val);
|
||||
}
|
||||
|
||||
protected:
|
||||
void DoInit();
|
||||
bool eval(const char * code, std::string &error);
|
||||
bool dosub(const char * subname, const std::vector<std::string> &args, std::string &error, int mode = G_SCALAR|G_DISCARD|G_EVAL);
|
||||
bool eval_file(const char * packagename, const char * filename, std::string &error);
|
||||
|
||||
//the embedded interpreter
|
||||
PerlInterpreter * my_perl;
|
||||
SV *_empty_sv;
|
||||
};
|
||||
#endif //EMBPERL
|
||||
|
||||
#endif /*EQWPARSER_H_*/
|
||||
|
||||
@ -24,8 +24,8 @@
|
||||
#include "../common/md5.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "worlddb.h"
|
||||
#include "eql_config.h"
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "../common/version.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "login_server.h"
|
||||
#include "login_server_list.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
@ -166,7 +167,7 @@ bool LoginServer::Connect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
char errbuf[TCPConnection_ErrorBufferSize];
|
||||
char errbuf[1024];
|
||||
if ((LoginServerIP = ResolveIP(LoginServerAddress, errbuf)) == 0) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Unable to resolve '%s' to an IP.",LoginServerAddress);
|
||||
return false;
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
#include "../common/queue.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
|
||||
class LoginServer;
|
||||
|
||||
|
||||
@ -21,10 +21,8 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/queue.h"
|
||||
#include "../common/timer.h"
|
||||
@ -67,14 +65,11 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include "../common/emu_tcp_server.h"
|
||||
#include "../common/patches/patches.h"
|
||||
#include "../common/random.h"
|
||||
#include "zoneserver.h"
|
||||
#include "console.h"
|
||||
#include "login_server.h"
|
||||
#include "login_server_list.h"
|
||||
#include "eqw_http_handler.h"
|
||||
#include "world_config.h"
|
||||
#include "zoneserver.h"
|
||||
#include "zonelist.h"
|
||||
@ -85,16 +80,15 @@
|
||||
#include "adventure_manager.h"
|
||||
#include "ucs.h"
|
||||
#include "queryserv.h"
|
||||
#include "web_interface.h"
|
||||
|
||||
#include "../common/net/tcp_server.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
|
||||
EmuTCPServer tcps;
|
||||
ClientList client_list;
|
||||
GroupLFPList LFPGroupList;
|
||||
ZSList zoneserver_list;
|
||||
LoginServerList loginserverlist;
|
||||
EQWHTTPServer http_server;
|
||||
UCSConnection UCSLink;
|
||||
QueryServConnection QSLink;
|
||||
LauncherList launcher_list;
|
||||
@ -106,6 +100,7 @@ uint32 numzones = 0;
|
||||
bool holdzones = false;
|
||||
const WorldConfig *Config;
|
||||
EQEmuLogSys Log;
|
||||
WebInterfaceList web_interface;
|
||||
|
||||
void CatchSignal(int sig_num);
|
||||
|
||||
@ -130,22 +125,21 @@ int main(int argc, char** argv) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Loading server configuration failed.");
|
||||
return 1;
|
||||
}
|
||||
Config=WorldConfig::get();
|
||||
|
||||
Config = WorldConfig::get();
|
||||
|
||||
Log.Out(Logs::General, Logs::World_Server, "CURRENT_VERSION: %s", CURRENT_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
#endif
|
||||
|
||||
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Could not set signal handler");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Could not set signal handler");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Could not set signal handler");
|
||||
@ -281,13 +275,6 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if(Config->WorldHTTPEnabled) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Starting HTTP world service...");
|
||||
http_server.Start(Config->WorldHTTPPort, Config->WorldHTTPMimeFile.c_str());
|
||||
} else {
|
||||
Log.Out(Logs::General, Logs::World_Server, "HTTP world service disabled.");
|
||||
}
|
||||
|
||||
if(!ignore_db) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Checking Database Conversions..");
|
||||
database.CheckDatabaseConversions();
|
||||
@ -445,12 +432,26 @@ int main(int argc, char** argv) {
|
||||
});
|
||||
|
||||
server_connection->OnConnectionRemoved("UCS", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||
Log.OutF(Logs::General, Logs::World_Server, "UCS Query Server connection from {0}",
|
||||
Log.OutF(Logs::General, Logs::World_Server, "Removed Query Server connection from {0}",
|
||||
connection->GetUUID());
|
||||
|
||||
UCSLink.SetConnection(nullptr);
|
||||
});
|
||||
|
||||
server_connection->OnConnectionIdentified("WebInterface", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||
Log.OutF(Logs::General, Logs::World_Server, "New WebInterface Server connection from {2} at {0}:{1}",
|
||||
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
|
||||
|
||||
web_interface.AddConnection(connection);
|
||||
});
|
||||
|
||||
server_connection->OnConnectionRemoved("WebInterface", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||
Log.OutF(Logs::General, Logs::World_Server, "Removed WebInterface Server connection from {0}",
|
||||
connection->GetUUID());
|
||||
|
||||
web_interface.RemoveConnection(connection);
|
||||
});
|
||||
|
||||
EQ::Net::EQStreamManagerOptions opts(9000, false, false);
|
||||
EQ::Net::EQStreamManager eqsm(opts);
|
||||
|
||||
@ -538,9 +539,7 @@ int main(int argc, char** argv) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "Shutting down zone connections (if any).");
|
||||
zoneserver_list.KillAll();
|
||||
Log.Out(Logs::General, Logs::World_Server, "Zone (TCP) listener stopped.");
|
||||
//tcps.Close();
|
||||
Log.Out(Logs::General, Logs::World_Server, "Signaling HTTP service to stop...");
|
||||
http_server.Stop();
|
||||
Log.CloseFileLogs();
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1,477 +0,0 @@
|
||||
/*
|
||||
* This file was generated automatically by xsubpp version 1.9508 from the
|
||||
* contents of tmp. Do not edit this file, edit tmp instead.
|
||||
*
|
||||
* ANY CHANGES MADE HERE WILL BE LOST!
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
typedef const char Const_char;
|
||||
|
||||
#ifdef EMBPERL
|
||||
#include "../common/global_define.h"
|
||||
#include "eqw_parser.h"
|
||||
#include "eql_config.h"
|
||||
|
||||
#ifdef seed
|
||||
#undef seed
|
||||
#endif
|
||||
|
||||
#ifdef THIS /* this macro seems to leak out on some systems */
|
||||
#undef THIS
|
||||
#endif
|
||||
|
||||
|
||||
XS(XS_EQLConfig_GetName); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_GetName)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::GetName(THIS)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
Const_char * RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetName();
|
||||
sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_GetStaticCount); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_GetStaticCount)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::GetStaticCount(THIS)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
int RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetStaticCount();
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_IsConnected); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_IsConnected)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::IsConnected(THIS)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
bool RETVAL;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsConnected();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_DeleteLauncher); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_DeleteLauncher)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::DeleteLauncher(THIS)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->DeleteLauncher();
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_RestartZone); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_RestartZone)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::RestartZone(THIS, zone_ref)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
Const_char * zone_ref = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->RestartZone(zone_ref);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_StopZone); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_StopZone)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::StopZone(THIS, zone_ref)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
Const_char * zone_ref = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->StopZone(zone_ref);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_StartZone); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_StartZone)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::StartZone(THIS, zone_ref)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
Const_char * zone_ref = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->StartZone(zone_ref);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_BootStaticZone); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_BootStaticZone)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::BootStaticZone(THIS, short_name, port)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
bool RETVAL;
|
||||
Const_char * short_name = (Const_char *)SvPV_nolen(ST(1));
|
||||
uint16 port = (uint16)SvUV(ST(2));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->BootStaticZone(short_name, port);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_ChangeStaticZone); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_ChangeStaticZone)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::ChangeStaticZone(THIS, short_name, port)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
bool RETVAL;
|
||||
Const_char * short_name = (Const_char *)SvPV_nolen(ST(1));
|
||||
uint16 port = (uint16)SvUV(ST(2));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->ChangeStaticZone(short_name, port);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_DeleteStaticZone); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_DeleteStaticZone)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::DeleteStaticZone(THIS, short_name)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
bool RETVAL;
|
||||
Const_char * short_name = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->DeleteStaticZone(short_name);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_SetDynamicCount); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_SetDynamicCount)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::SetDynamicCount(THIS, count)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
bool RETVAL;
|
||||
int count = (int)SvIV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->SetDynamicCount(count);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_GetDynamicCount); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_GetDynamicCount)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::GetDynamicCount(THIS)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
int RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetDynamicCount();
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_ListZones); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_ListZones)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::ListZones(THIS)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
std::vector<std::string> RETVAL;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->ListZones();
|
||||
ST(0) = sv_newmortal();
|
||||
{
|
||||
U32 ix_RETVAL;
|
||||
/* pop crap off the stack we dont really want */
|
||||
POPs;
|
||||
POPs;
|
||||
/* grow the stack to the number of elements being returned */
|
||||
EXTEND(SP, RETVAL.size());
|
||||
for (ix_RETVAL = 0; ix_RETVAL < RETVAL.size(); ix_RETVAL++) {
|
||||
const std::string &it = RETVAL[ix_RETVAL];
|
||||
ST(ix_RETVAL) = sv_newmortal();
|
||||
sv_setpvn(ST(ix_RETVAL), it.c_str(), it.length());
|
||||
}
|
||||
/* hackish, but im over it. The normal xsubpp return will be right below this */
|
||||
XSRETURN(RETVAL.size());
|
||||
}
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQLConfig_GetZoneDetails); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQLConfig_GetZoneDetails)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EQLConfig::GetZoneDetails(THIS, zone_ref)");
|
||||
{
|
||||
EQLConfig * THIS;
|
||||
std::map<std::string,std::string> RETVAL;
|
||||
Const_char * zone_ref = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EQLConfig")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQLConfig *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQLConfig");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetZoneDetails(zone_ref);
|
||||
ST(0) = sv_newmortal();
|
||||
if (RETVAL.begin()!=RETVAL.end())
|
||||
{
|
||||
//NOTE: we are leaking the original ST(0) right now
|
||||
HV *hv = newHV();
|
||||
sv_2mortal((SV*)hv);
|
||||
ST(0) = newRV((SV*)hv);
|
||||
|
||||
std::map<std::string,std::string>::const_iterator cur, end;
|
||||
cur = RETVAL.begin();
|
||||
end = RETVAL.end();
|
||||
for(; cur != end; cur++) {
|
||||
/* get the element from the hash, creating if needed (will be needed) */
|
||||
SV**ele = hv_fetch(hv, cur->first.c_str(), cur->first.length(), TRUE);
|
||||
if(ele == nullptr) {
|
||||
Perl_croak(aTHX_ "Unable to create a hash element for RETVAL");
|
||||
break;
|
||||
}
|
||||
/* put our string in the SV associated with this element in the hash */
|
||||
sv_setpvn(*ele, cur->second.c_str(), cur->second.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
XS(boot_EQLConfig); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(boot_EQLConfig)
|
||||
{
|
||||
dXSARGS;
|
||||
char file[256];
|
||||
strncpy(file, __FILE__, 256);
|
||||
file[255] = 0;
|
||||
|
||||
if(items != 1)
|
||||
fprintf(stderr, "boot_quest does not take any arguments.");
|
||||
char buf[128];
|
||||
|
||||
//add the strcpy stuff to get rid of const warnings....
|
||||
|
||||
XS_VERSION_BOOTCHECK ;
|
||||
|
||||
newXSproto(strcpy(buf, "GetName"), XS_EQLConfig_GetName, file, "$");
|
||||
newXSproto(strcpy(buf, "GetStaticCount"), XS_EQLConfig_GetStaticCount, file, "$");
|
||||
newXSproto(strcpy(buf, "IsConnected"), XS_EQLConfig_IsConnected, file, "$");
|
||||
newXSproto(strcpy(buf, "DeleteLauncher"), XS_EQLConfig_DeleteLauncher, file, "$");
|
||||
newXSproto(strcpy(buf, "RestartZone"), XS_EQLConfig_RestartZone, file, "$$");
|
||||
newXSproto(strcpy(buf, "StopZone"), XS_EQLConfig_StopZone, file, "$$");
|
||||
newXSproto(strcpy(buf, "StartZone"), XS_EQLConfig_StartZone, file, "$$");
|
||||
newXSproto(strcpy(buf, "BootStaticZone"), XS_EQLConfig_BootStaticZone, file, "$$$");
|
||||
newXSproto(strcpy(buf, "ChangeStaticZone"), XS_EQLConfig_ChangeStaticZone, file, "$$$");
|
||||
newXSproto(strcpy(buf, "DeleteStaticZone"), XS_EQLConfig_DeleteStaticZone, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetDynamicCount"), XS_EQLConfig_SetDynamicCount, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetDynamicCount"), XS_EQLConfig_GetDynamicCount, file, "$");
|
||||
newXSproto(strcpy(buf, "ListZones"), XS_EQLConfig_ListZones, file, "$");
|
||||
newXSproto(strcpy(buf, "GetZoneDetails"), XS_EQLConfig_GetZoneDetails, file, "$$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
#endif //EMBPERL_XS_CLASSES
|
||||
|
||||
1020
world/perl_eqw.cpp
1020
world/perl_eqw.cpp
File diff suppressed because it is too large
Load Diff
@ -1,330 +0,0 @@
|
||||
/*
|
||||
* This file was generated automatically by xsubpp version 1.9508 from the
|
||||
* contents of tmp. Do not edit this file, edit tmp instead.
|
||||
*
|
||||
* ANY CHANGES MADE HERE WILL BE LOST!
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
typedef const char Const_char;
|
||||
|
||||
#ifdef EMBPERL
|
||||
#include "../common/global_define.h"
|
||||
#include "eqw_parser.h"
|
||||
#include "http_request.h"
|
||||
|
||||
#ifdef seed
|
||||
#undef seed
|
||||
#endif
|
||||
|
||||
#ifdef THIS /* this macro seems to leak out on some systems */
|
||||
#undef THIS
|
||||
#endif
|
||||
|
||||
|
||||
XS(XS_HTTPRequest_get); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_get)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 3)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::get(THIS, name, default_value= \"\")");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
Const_char * RETVAL;
|
||||
dXSTARG;
|
||||
Const_char * name = (Const_char *)SvPV_nolen(ST(1));
|
||||
Const_char * default_value;
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items < 3)
|
||||
default_value = "";
|
||||
else {
|
||||
default_value = (Const_char *)SvPV_nolen(ST(2));
|
||||
}
|
||||
|
||||
RETVAL = THIS->get(name, default_value);
|
||||
sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_getInt); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_getInt)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 3)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::getInt(THIS, name, default_value= 0)");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
int RETVAL;
|
||||
dXSTARG;
|
||||
Const_char * name = (Const_char *)SvPV_nolen(ST(1));
|
||||
int default_value;
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items < 3)
|
||||
default_value = 0;
|
||||
else {
|
||||
default_value = (int)SvIV(ST(2));
|
||||
}
|
||||
|
||||
RETVAL = THIS->getInt(name, default_value);
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_getFloat); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_getFloat)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 3)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::getFloat(THIS, name, default_value= 0.0)");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
Const_char * name = (Const_char *)SvPV_nolen(ST(1));
|
||||
float default_value;
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items < 3)
|
||||
default_value = 0.0;
|
||||
else {
|
||||
default_value = (float)SvNV(ST(2));
|
||||
}
|
||||
|
||||
RETVAL = THIS->getFloat(name, default_value);
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_getEscaped); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_getEscaped)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 3)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::getEscaped(THIS, name, default_value= \"\")");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
Const_char * RETVAL;
|
||||
dXSTARG;
|
||||
Const_char * name = (Const_char *)SvPV_nolen(ST(1));
|
||||
Const_char * default_value;
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items < 3)
|
||||
default_value = "";
|
||||
else {
|
||||
default_value = (Const_char *)SvPV_nolen(ST(2));
|
||||
}
|
||||
|
||||
RETVAL = THIS->getEscaped(name, default_value);
|
||||
sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_get_all); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_get_all)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::get_all(THIS)");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
std::map<std::string,std::string> RETVAL;
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->get_all();
|
||||
ST(0) = sv_newmortal();
|
||||
if (RETVAL.begin()!=RETVAL.end())
|
||||
{
|
||||
//NOTE: we are leaking the original ST(0) right now
|
||||
HV *hv = newHV();
|
||||
sv_2mortal((SV*)hv);
|
||||
ST(0) = newRV((SV*)hv);
|
||||
|
||||
std::map<std::string,std::string>::const_iterator cur, end;
|
||||
cur = RETVAL.begin();
|
||||
end = RETVAL.end();
|
||||
for(; cur != end; cur++) {
|
||||
/* get the element from the hash, creating if needed (will be needed) */
|
||||
SV**ele = hv_fetch(hv, cur->first.c_str(), cur->first.length(), TRUE);
|
||||
if(ele == nullptr) {
|
||||
Perl_croak(aTHX_ "Unable to create a hash element for RETVAL");
|
||||
break;
|
||||
}
|
||||
/* put our string in the SV associated with this element in the hash */
|
||||
sv_setpvn(*ele, cur->second.c_str(), cur->second.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_redirect); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_redirect)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::redirect(THIS, URL)");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
Const_char * URL = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->redirect(URL);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_SetResponseCode); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_SetResponseCode)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::SetResponseCode(THIS, code)");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
Const_char * code = (Const_char *)SvPV_nolen(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SetResponseCode(code);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_HTTPRequest_header); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_HTTPRequest_header)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: HTTPRequest::header(THIS, name, value)");
|
||||
{
|
||||
HTTPRequest * THIS;
|
||||
Const_char * name = (Const_char *)SvPV_nolen(ST(1));
|
||||
Const_char * value = (Const_char *)SvPV_nolen(ST(2));
|
||||
|
||||
if (sv_derived_from(ST(0), "HTTPRequest")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(HTTPRequest *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type HTTPRequest");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->header(name, value);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
XS(boot_HTTPRequest); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(boot_HTTPRequest)
|
||||
{
|
||||
dXSARGS;
|
||||
char file[256];
|
||||
strncpy(file, __FILE__, 256);
|
||||
file[255] = 0;
|
||||
|
||||
if(items != 1)
|
||||
fprintf(stderr, "boot_quest does not take any arguments.");
|
||||
char buf[128];
|
||||
|
||||
//add the strcpy stuff to get rid of const warnings....
|
||||
|
||||
XS_VERSION_BOOTCHECK ;
|
||||
|
||||
newXSproto(strcpy(buf, "get"), XS_HTTPRequest_get, file, "$$;$");
|
||||
newXSproto(strcpy(buf, "getInt"), XS_HTTPRequest_getInt, file, "$$;$");
|
||||
newXSproto(strcpy(buf, "getFloat"), XS_HTTPRequest_getFloat, file, "$$;$");
|
||||
newXSproto(strcpy(buf, "getEscaped"), XS_HTTPRequest_getEscaped, file, "$$;$");
|
||||
newXSproto(strcpy(buf, "get_all"), XS_HTTPRequest_get_all, file, "$");
|
||||
newXSproto(strcpy(buf, "redirect"), XS_HTTPRequest_redirect, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetResponseCode"), XS_HTTPRequest_SetResponseCode, file, "$$");
|
||||
newXSproto(strcpy(buf, "header"), XS_HTTPRequest_header, file, "$$$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
#endif //EMBPERL_XS_CLASSES
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
#include "../common/md5.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "../common/packet_dump.h"
|
||||
|
||||
extern ClientList client_list;
|
||||
|
||||
@ -3,9 +3,8 @@
|
||||
#include "ucs.h"
|
||||
#include "world_config.h"
|
||||
|
||||
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/md5.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "../common/packet_dump.h"
|
||||
|
||||
UCSConnection::UCSConnection()
|
||||
|
||||
164
world/web_interface.cpp
Normal file
164
world/web_interface.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
#include "web_interface.h"
|
||||
#include "../common/json/json.h"
|
||||
|
||||
#include "web_interface_eqw.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
WebInterface::WebInterface(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||
{
|
||||
m_connection = connection;
|
||||
m_connection->OnMessage(ServerOP_WebInterfaceCall, std::bind(&WebInterface::OnCall, this, std::placeholders::_1, std::placeholders::_2));
|
||||
RegisterEQW(this);
|
||||
}
|
||||
|
||||
WebInterface::~WebInterface()
|
||||
{
|
||||
}
|
||||
|
||||
void WebInterface::OnCall(uint16 opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
Json::Value root;
|
||||
try {
|
||||
auto json_str = p.GetCString(0);
|
||||
std::stringstream ss(json_str);
|
||||
ss >> root;
|
||||
}
|
||||
catch (std::exception) {
|
||||
SendError("Could not parse request");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string method;
|
||||
Json::Value params;
|
||||
std::string id;
|
||||
|
||||
try {
|
||||
method = root["method"].asString();
|
||||
if (method.length() == 0) {
|
||||
SendError("Invalid request: method not supplied");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (std::exception) {
|
||||
SendError("Invalid request: method not supplied");
|
||||
return;
|
||||
}
|
||||
|
||||
//optional "params" -> Json::Value
|
||||
try {
|
||||
params = root["params"];
|
||||
}
|
||||
catch (std::exception) {
|
||||
params = nullptr;
|
||||
}
|
||||
|
||||
//optional "id" needs to be string
|
||||
try {
|
||||
id = root["id"].asString();
|
||||
}
|
||||
catch (std::exception) {
|
||||
id = "";
|
||||
}
|
||||
|
||||
//check for registered method
|
||||
auto iter = m_calls.find(method);
|
||||
if (iter == m_calls.end()) {
|
||||
//if not exist then error
|
||||
SendError("Invalid request: method not found");
|
||||
return;
|
||||
}
|
||||
|
||||
iter->second(this, method, id, params);
|
||||
}
|
||||
|
||||
void WebInterface::Send(const Json::Value &value)
|
||||
{
|
||||
try {
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
|
||||
EQ::Net::DynamicPacket p;
|
||||
p.PutString(0, ss.str());
|
||||
m_connection->Send(ServerOP_WebInterfaceCall, p);
|
||||
}
|
||||
catch (std::exception) {
|
||||
//Log error
|
||||
}
|
||||
}
|
||||
|
||||
void WebInterface::SendError(const std::string &message)
|
||||
{
|
||||
Json::Value error;
|
||||
error["error"] = Json::Value();
|
||||
error["error"]["message"] = message;
|
||||
|
||||
Send(error);
|
||||
}
|
||||
|
||||
void WebInterface::SendError(const std::string &message, const std::string &id)
|
||||
{
|
||||
Json::Value error;
|
||||
error["error"] = Json::Value();
|
||||
error["error"]["message"] = message;
|
||||
|
||||
Send(error);
|
||||
}
|
||||
|
||||
void WebInterface::AddCall(const std::string &method, WebInterfaceCall call)
|
||||
{
|
||||
m_calls.insert(std::make_pair(method, call));
|
||||
}
|
||||
|
||||
void WebInterface::SendResponse(const std::string &id, const Json::Value &response)
|
||||
{
|
||||
Json::Value out;
|
||||
if(!id.empty())
|
||||
out["id"] = id;
|
||||
out["response"] = response;
|
||||
|
||||
Send(out);
|
||||
}
|
||||
|
||||
WebInterfaceList::WebInterfaceList()
|
||||
{
|
||||
}
|
||||
|
||||
WebInterfaceList::~WebInterfaceList()
|
||||
{
|
||||
}
|
||||
|
||||
void WebInterfaceList::AddConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||
{
|
||||
m_interfaces.insert(std::make_pair(connection->GetUUID(), std::unique_ptr<WebInterface>(new WebInterface(connection))));
|
||||
}
|
||||
|
||||
void WebInterfaceList::RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
||||
{
|
||||
auto iter = m_interfaces.find(connection->GetUUID());
|
||||
if (iter != m_interfaces.end()) {
|
||||
m_interfaces.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WebInterfaceList::SendResponse(const std::string &uuid, std::string &id, const Json::Value &response) {
|
||||
auto iter = m_interfaces.find(uuid);
|
||||
if (iter != m_interfaces.end()) {
|
||||
iter->second->SendResponse(id, response);
|
||||
}
|
||||
}
|
||||
|
||||
void WebInterfaceList::SendError(const std::string &uuid, const std::string &message) {
|
||||
auto iter = m_interfaces.find(uuid);
|
||||
if (iter != m_interfaces.end()) {
|
||||
iter->second->SendError(message);
|
||||
}
|
||||
}
|
||||
|
||||
void WebInterfaceList::SendError(const std::string &uuid, const std::string &message, const std::string &id) {
|
||||
auto iter = m_interfaces.find(uuid);
|
||||
if (iter != m_interfaces.end()) {
|
||||
iter->second->SendError(message, id);
|
||||
}
|
||||
}
|
||||
45
world/web_interface.h
Normal file
45
world/web_interface.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/net/servertalk_server_connection.h"
|
||||
#include "../common/json/json.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
|
||||
|
||||
class WebInterface
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(WebInterface *, const std::string&, const std::string&, const Json::Value&)> WebInterfaceCall;
|
||||
WebInterface(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
~WebInterface();
|
||||
|
||||
std::string GetUUID() const { return m_connection->GetUUID(); }
|
||||
void SendResponse(const std::string &id, const Json::Value &response);
|
||||
void SendError(const std::string &message);
|
||||
void SendError(const std::string &message, const std::string &id);
|
||||
void AddCall(const std::string &method, WebInterfaceCall call);
|
||||
private:
|
||||
void OnCall(uint16 opcode, EQ::Net::Packet &p);
|
||||
void Send(const Json::Value &value);
|
||||
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> m_connection;
|
||||
std::map<std::string, WebInterfaceCall> m_calls;
|
||||
};
|
||||
|
||||
class WebInterfaceList
|
||||
{
|
||||
public:
|
||||
WebInterfaceList();
|
||||
~WebInterfaceList();
|
||||
|
||||
void AddConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
void RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
void SendResponse(const std::string &uuid, std::string &id, const Json::Value &response);
|
||||
void SendError(const std::string &uuid, const std::string &message);
|
||||
void SendError(const std::string &uuid, const std::string &message, const std::string &id);
|
||||
|
||||
private:
|
||||
std::map<std::string, std::unique_ptr<WebInterface>> m_interfaces;
|
||||
};
|
||||
40
world/web_interface_eqw.cpp
Normal file
40
world/web_interface_eqw.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "web_interface_eqw.h"
|
||||
#include "web_interface.h"
|
||||
#include "world_config.h"
|
||||
#include "login_server_list.h"
|
||||
|
||||
extern LoginServerList loginserverlist;
|
||||
|
||||
void EQW__IsLocked(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) {
|
||||
Json::Value ret = WorldConfig::get()->Locked;
|
||||
i->SendResponse(id, ret);
|
||||
}
|
||||
|
||||
void EQW__Lock(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) {
|
||||
WorldConfig::LockWorld();
|
||||
if (loginserverlist.Connected()) {
|
||||
loginserverlist.SendStatus();
|
||||
}
|
||||
|
||||
Json::Value ret;
|
||||
ret["status"] = "complete";
|
||||
i->SendResponse(id, ret);
|
||||
}
|
||||
|
||||
void EQW__Unlock(WebInterface *i, const std::string& method, const std::string& id, const Json::Value& params) {
|
||||
WorldConfig::UnlockWorld();
|
||||
if (loginserverlist.Connected()) {
|
||||
loginserverlist.SendStatus();
|
||||
}
|
||||
|
||||
Json::Value ret;
|
||||
ret["status"] = "complete";
|
||||
i->SendResponse(id, ret);
|
||||
}
|
||||
|
||||
void RegisterEQW(WebInterface *i)
|
||||
{
|
||||
i->AddCall("IsLocked", std::bind(EQW__IsLocked, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||
i->AddCall("Lock", std::bind(EQW__Lock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||
i->AddCall("Unlock", std::bind(EQW__Unlock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||
}
|
||||
5
world/web_interface_eqw.h
Normal file
5
world/web_interface_eqw.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
class WebInterface;
|
||||
|
||||
void RegisterEQW(WebInterface *i);
|
||||
@ -18,10 +18,9 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "zonelist.h"
|
||||
#include "zoneserver.h"
|
||||
#include "world_tcp_connection.h"
|
||||
#include "worlddb.h"
|
||||
#include "console.h"
|
||||
#include "world_config.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/random.h"
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
#include "login_server_list.h"
|
||||
#include "zonelist.h"
|
||||
#include "worlddb.h"
|
||||
#include "console.h"
|
||||
#include "client.h"
|
||||
#include "../common/md5.h"
|
||||
#include "world_config.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user