mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
World <-> Login connection reworked
This commit is contained in:
parent
fab8765c2f
commit
0b8b41d91f
@ -335,9 +335,12 @@ SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RE
|
||||
|
||||
FIND_PACKAGE(Sodium REQUIRED)
|
||||
IF(SODIUM_FOUND)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${SODIUM_LIBRARIES})
|
||||
OPTION(EQEMU_ENABLE_SECURITY "Use Encryption For TCP Connections" ON)
|
||||
IF(EQEMU_ENABLE_SECURITY)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${SODIUM_LIBRARIES})
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
@ -384,9 +387,9 @@ IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(shared_memory)
|
||||
ADD_SUBDIRECTORY(world)
|
||||
ADD_SUBDIRECTORY(zone)
|
||||
ADD_SUBDIRECTORY(ucs)
|
||||
#ADD_SUBDIRECTORY(ucs)
|
||||
#ADD_SUBDIRECTORY(queryserv)
|
||||
ADD_SUBDIRECTORY(eqlaunch)
|
||||
#ADD_SUBDIRECTORY(eqlaunch)
|
||||
ENDIF(EQEMU_BUILD_SERVER)
|
||||
IF(EQEMU_BUILD_LOGIN)
|
||||
ADD_SUBDIRECTORY(loginserver)
|
||||
|
||||
@ -41,6 +41,7 @@ public:
|
||||
virtual void Close() = 0;
|
||||
virtual void ReleaseFromUse() = 0;
|
||||
virtual void RemoveData() = 0;
|
||||
virtual std::string GetRemoteAddr() const = 0;
|
||||
virtual uint32 GetRemoteIP() const = 0;
|
||||
virtual uint16 GetRemotePort() const = 0;
|
||||
virtual bool CheckState(EQStreamState state) = 0;
|
||||
|
||||
@ -63,6 +63,10 @@ void EQStreamProxy::Close() {
|
||||
m_stream->Close();
|
||||
}
|
||||
|
||||
std::string EQStreamProxy::GetRemoteAddr() const {
|
||||
return(m_stream->GetRemoteAddr());
|
||||
}
|
||||
|
||||
uint32 EQStreamProxy::GetRemoteIP() const {
|
||||
return(m_stream->GetRemoteIP());
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ public:
|
||||
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
|
||||
virtual EQApplicationPacket *PopPacket();
|
||||
virtual void Close();
|
||||
virtual std::string GetRemoteAddr() const;
|
||||
virtual uint32 GetRemoteIP() const;
|
||||
virtual uint16 GetRemotePort() const;
|
||||
virtual void ReleaseFromUse();
|
||||
|
||||
@ -132,6 +132,11 @@ void EQ::Net::EQStream::Close() {
|
||||
m_connection->Close();
|
||||
}
|
||||
|
||||
std::string EQ::Net::EQStream::GetRemoteAddr() const
|
||||
{
|
||||
return RemoteEndpoint();
|
||||
}
|
||||
|
||||
uint32 EQ::Net::EQStream::GetRemoteIP() const {
|
||||
return inet_addr(RemoteEndpoint().c_str());
|
||||
}
|
||||
|
||||
@ -75,6 +75,7 @@ namespace EQ
|
||||
virtual void Close();
|
||||
virtual void ReleaseFromUse() { };
|
||||
virtual void RemoveData() { };
|
||||
virtual std::string GetRemoteAddr() const;
|
||||
virtual uint32 GetRemoteIP() const;
|
||||
virtual uint16 GetRemotePort() const { return m_connection->RemotePort(); }
|
||||
virtual bool CheckState(EQStreamState state);
|
||||
|
||||
@ -19,6 +19,45 @@ EQ::Net::ServertalkClient::~ServertalkClient()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::Send(uint16_t opcode, EQ::Net::Packet & p)
|
||||
{
|
||||
EQ::Net::WritablePacket out;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
||||
out.PutUInt16(4, opcode);
|
||||
unsigned char *cipher = new unsigned char[p.Length() + crypto_secretbox_MACBYTES];
|
||||
|
||||
crypto_box_easy_afternm(cipher, (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
out.PutData(6, cipher, p.Length() + crypto_secretbox_MACBYTES);
|
||||
|
||||
delete[] cipher;
|
||||
}
|
||||
else {
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::SendPacket(ServerPacket *p)
|
||||
{
|
||||
EQ::Net::ReadOnlyPacket pout(p->pBuffer, p->size);
|
||||
Send(p->opcode, pout);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
{
|
||||
m_message_callbacks.insert(std::make_pair(opcode, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::Connect()
|
||||
{
|
||||
if (m_addr.length() == 0 || m_port == 0 || m_connection || m_connecting) {
|
||||
@ -37,8 +76,8 @@ void EQ::Net::ServertalkClient::Connect()
|
||||
m_connection = connection;
|
||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||
Log.OutF(Logs::General, Logs::TCP_Connection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connection.reset();
|
||||
m_encrypted = false;
|
||||
m_connection.reset();
|
||||
});
|
||||
|
||||
m_connection->OnRead(std::bind(&EQ::Net::ServertalkClient::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
@ -98,7 +137,7 @@ void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
||||
length = *(uint32_t*)&m_buffer[current];
|
||||
type = *(uint8_t*)&m_buffer[current + 4];
|
||||
|
||||
if (current + 5 + length < total) {
|
||||
if (current + 5 + length > total) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -144,6 +183,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_shared_key, 0, crypto_box_BEFORENMBYTES);
|
||||
m_encrypted = false;
|
||||
|
||||
try {
|
||||
@ -156,6 +196,10 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
m_encrypted = true;
|
||||
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
@ -163,37 +207,104 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
try {
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
if (enc) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Server requested encryption but we do not support encryption.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
SendHandshake(true);
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
{
|
||||
try {
|
||||
auto length = p.GetUInt32(0);
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
auto data = p.GetString(6, length);
|
||||
#ifdef ENABLE_SECURITY
|
||||
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 server");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::ReadOnlyPacket decrypted_packet(&decrypted_text[0], message_len);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, decrypted_packet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t message_len = length;
|
||||
EQ::Net::ReadOnlyPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::ReadOnlyPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing message from server: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::SendHandshake()
|
||||
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
||||
{
|
||||
EQ::Net::WritablePacket handshake;
|
||||
#ifdef ENABLE_SECURITY
|
||||
@ -206,30 +317,41 @@ void EQ::Net::ServertalkClient::SendHandshake()
|
||||
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
|
||||
size_t cipher_length = m_identifier.length() + 1 + m_credentials.length() + 1 + crypto_secretbox_MACBYTES;
|
||||
size_t data_length = m_identifier.length() + 1 + m_credentials.length() + 1;
|
||||
unsigned char *signed_buffer = new unsigned char[cipher_length];
|
||||
unsigned char *data_buffer = new unsigned char[data_length];
|
||||
memset(data_buffer, 0, data_length);
|
||||
|
||||
std::unique_ptr<unsigned char[]> signed_buffer(new unsigned char[cipher_length]);
|
||||
std::unique_ptr<unsigned char[]> data_buffer(new unsigned char[data_length]);
|
||||
|
||||
memset(&data_buffer[0], 0, data_length);
|
||||
memcpy(&data_buffer[0], m_identifier.c_str(), m_identifier.length());
|
||||
memcpy(&data_buffer[1 + m_identifier.length()], m_credentials.c_str(), m_credentials.length());
|
||||
|
||||
crypto_box_easy_afternm(signed_buffer, data_buffer, data_length, m_nonce_ours, m_shared_key);
|
||||
crypto_box_easy_afternm(&signed_buffer[0], &data_buffer[0], data_length, m_nonce_ours, m_shared_key);
|
||||
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, signed_buffer, cipher_length);
|
||||
|
||||
Log.OutF(Logs::General, Logs::Debug, "Sending {1} bytes handshake:\n{0}", handshake.ToString(), handshake.Length());
|
||||
|
||||
delete[] signed_buffer;
|
||||
delete[] data_buffer;
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, &signed_buffer[0], cipher_length);
|
||||
}
|
||||
else {
|
||||
handshake.PutString(0, m_identifier);
|
||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||
}
|
||||
#else
|
||||
handshake.PutString(0, m_identifier);
|
||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||
#endif
|
||||
InternalSend(ServertalkClientHandshake, handshake);
|
||||
|
||||
if (downgrade) {
|
||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||
}
|
||||
else {
|
||||
InternalSend(ServertalkClientHandshake, handshake);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
#include "../event/timer.h"
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@ -16,6 +18,13 @@ namespace EQ
|
||||
ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials);
|
||||
~ServertalkClient();
|
||||
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket *p);
|
||||
void OnConnect(std::function<void(ServertalkClient*)> cb) { m_on_connect_cb = cb; }
|
||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||
bool Connected() const { return m_connecting != true; }
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
|
||||
private:
|
||||
void Connect();
|
||||
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
||||
@ -24,7 +33,8 @@ namespace EQ
|
||||
void ProcessReadBuffer();
|
||||
void ProcessHello(EQ::Net::Packet &p);
|
||||
void ProcessMessage(EQ::Net::Packet &p);
|
||||
void SendHandshake();
|
||||
void SendHandshake() { SendHandshake(false); }
|
||||
void SendHandshake(bool downgrade);
|
||||
|
||||
std::unique_ptr<EQ::Timer> m_timer;
|
||||
|
||||
@ -37,6 +47,8 @@ namespace EQ
|
||||
bool m_encrypted;
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
std::vector<char> m_buffer;
|
||||
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
||||
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../servertalk.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
@ -9,6 +11,7 @@ namespace EQ
|
||||
ServertalkClientHello = 1,
|
||||
ServertalkServerHello,
|
||||
ServertalkClientHandshake,
|
||||
ServertalkClientDowngradeSecurityHandshake,
|
||||
ServertalkMessage,
|
||||
};
|
||||
}
|
||||
|
||||
@ -12,9 +12,10 @@ void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
||||
{
|
||||
m_encrypted = opts.encrypted;
|
||||
m_credentials = opts.credentials;
|
||||
m_allow_downgrade = opts.allow_downgrade;
|
||||
m_server.reset(new EQ::Net::TCPServer());
|
||||
m_server->Listen(opts.port, opts.ipv6, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
m_unident_connections.push_back(std::make_shared<ServertalkServerConnection>(connection, this, m_encrypted));
|
||||
m_unident_connections.push_back(std::make_shared<ServertalkServerConnection>(connection, this, m_encrypted, m_allow_downgrade));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -18,11 +18,16 @@ namespace EQ
|
||||
int port;
|
||||
bool ipv6;
|
||||
bool encrypted;
|
||||
bool allow_downgrade;
|
||||
std::string credentials;
|
||||
|
||||
ServertalkServerOptions() {
|
||||
#ifdef ENABLE_SECURITY
|
||||
encrypted = true;
|
||||
allow_downgrade = true;
|
||||
#else
|
||||
encrypted = false;
|
||||
allow_downgrade = true;
|
||||
#endif
|
||||
ipv6 = false;
|
||||
}
|
||||
@ -50,6 +55,7 @@ namespace EQ
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_ident;
|
||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
||||
bool m_encrypted;
|
||||
bool m_allow_downgrade;
|
||||
std::string m_credentials;
|
||||
|
||||
friend class ServertalkServerConnection;
|
||||
|
||||
@ -2,11 +2,12 @@
|
||||
#include "servertalk_server.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent, bool encrypted)
|
||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent, bool encrypted, bool allow_downgrade)
|
||||
{
|
||||
m_connection = c;
|
||||
m_parent = parent;
|
||||
m_encrypted = encrypted;
|
||||
m_allow_downgrade = allow_downgrade;
|
||||
m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
|
||||
m_connection->Start();
|
||||
@ -16,6 +17,43 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
|
||||
{
|
||||
EQ::Net::WritablePacket out;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket * p)
|
||||
{
|
||||
EQ::Net::ReadOnlyPacket pout(p->pBuffer, p->size);
|
||||
Send(p->opcode, pout);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
|
||||
{
|
||||
m_message_callbacks.insert(std::make_pair(opcode, cb));
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz);
|
||||
@ -44,7 +82,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
length = *(uint32_t*)&m_buffer[current];
|
||||
type = *(uint8_t*)&m_buffer[current + 4];
|
||||
|
||||
if (current + 5 + length < total) {
|
||||
if (current + 5 + length > total) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -75,6 +113,9 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
case ServertalkClientHandshake:
|
||||
ProcessHandshake(p);
|
||||
break;
|
||||
case ServertalkClientDowngradeSecurityHandshake:
|
||||
ProcessHandshake(p, true);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
ProcessMessage(p);
|
||||
break;
|
||||
@ -142,9 +183,15 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, bool downgrade_security)
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (downgrade_security && m_allow_downgrade && m_encrypted) {
|
||||
Log.OutF(Logs::General, Logs::TCP_Connection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
||||
m_encrypted = false;
|
||||
}
|
||||
|
||||
if (m_encrypted) {
|
||||
try {
|
||||
if (p.Length() > (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
||||
@ -155,16 +202,16 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
|
||||
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
||||
unsigned char *decrypted_text = new unsigned char[message_len];
|
||||
if (crypto_box_open_easy_afternm(decrypted_text, (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
||||
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.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_identifier = (const char*)decrypted_text;
|
||||
std::string credentials = (const char*)decrypted_text + (m_identifier.length() + 1);
|
||||
m_identifier = (const char*)&decrypted_text[0];
|
||||
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
@ -175,7 +222,6 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
m_parent->ConnectionIdentified(this);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
delete[] decrypted_text;
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
@ -184,13 +230,92 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_identifier.assign((char*)p.Data(), p.Length());
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
#else
|
||||
m_identifier.assign((char*)p.Data(), p.Length());
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
{
|
||||
try {
|
||||
auto length = p.GetUInt32(0);
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
auto data = p.GetString(6, length);
|
||||
#ifdef ENABLE_SECURITY
|
||||
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");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::ReadOnlyPacket decrypted_packet(&decrypted_text[0], message_len);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, decrypted_packet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t message_len = length;
|
||||
EQ::Net::ReadOnlyPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::ReadOnlyPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
Log.OutF(Logs::General, Logs::Error, "Error parsing message from client: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#include <vector>
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@ -14,28 +16,34 @@ namespace EQ
|
||||
class ServertalkServerConnection
|
||||
{
|
||||
public:
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted);
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
||||
~ServertalkServerConnection();
|
||||
|
||||
std::string GetIdentifier() const {
|
||||
return m_identifier;
|
||||
}
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket *p);
|
||||
void OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb);
|
||||
|
||||
std::string GetIdentifier() const { return m_identifier; }
|
||||
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
|
||||
private:
|
||||
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
||||
void ProcessReadBuffer();
|
||||
void OnDisconnect(TCPConnection* c);
|
||||
void SendHello();
|
||||
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
||||
void ProcessHandshake(EQ::Net::Packet &p);
|
||||
void ProcessHandshake(EQ::Net::Packet &p) { ProcessHandshake(p, false); }
|
||||
void ProcessHandshake(EQ::Net::Packet &p, bool security_downgrade);
|
||||
void ProcessMessage(EQ::Net::Packet &p);
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
ServertalkServer *m_parent;
|
||||
|
||||
std::vector<char> m_buffer;
|
||||
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
||||
std::string m_identifier;
|
||||
|
||||
bool m_encrypted;
|
||||
bool m_allow_downgrade;
|
||||
#ifdef ENABLE_SECURITY
|
||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
||||
|
||||
@ -151,6 +151,42 @@ void EQ::Net::TCPConnection::Write(const char *data, size_t count)
|
||||
});
|
||||
}
|
||||
|
||||
std::string EQ::Net::TCPConnection::LocalIP() const
|
||||
{
|
||||
sockaddr_storage addr;
|
||||
int addr_len = sizeof(addr);
|
||||
uv_tcp_getsockname(m_socket, (sockaddr*)&addr, &addr_len);
|
||||
|
||||
char endpoint[64] = { 0 };
|
||||
if (addr.ss_family == AF_INET) {
|
||||
uv_ip4_name((const sockaddr_in*)&addr, endpoint, 64);
|
||||
}
|
||||
else if (addr.ss_family == AF_INET6) {
|
||||
uv_ip6_name((const sockaddr_in6*)&addr, endpoint, 64);
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
int EQ::Net::TCPConnection::LocalPort() const
|
||||
{
|
||||
sockaddr_storage addr;
|
||||
int addr_len = sizeof(addr);
|
||||
uv_tcp_getsockname(m_socket, (sockaddr*)&addr, &addr_len);
|
||||
|
||||
char endpoint[64] = { 0 };
|
||||
if (addr.ss_family == AF_INET) {
|
||||
sockaddr_in *s = (sockaddr_in*)&addr;
|
||||
return ntohs(s->sin_port);
|
||||
}
|
||||
else if (addr.ss_family == AF_INET6) {
|
||||
sockaddr_in6 *s = (sockaddr_in6*)&addr;
|
||||
return ntohs(s->sin6_port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string EQ::Net::TCPConnection::RemoteIP() const
|
||||
{
|
||||
sockaddr_storage addr;
|
||||
|
||||
@ -23,6 +23,9 @@ namespace EQ
|
||||
void Disconnect();
|
||||
void Read(const char *data, size_t count);
|
||||
void Write(const char *data, size_t count);
|
||||
|
||||
std::string LocalIP() const;
|
||||
int LocalPort() const;
|
||||
std::string RemoteIP() const;
|
||||
int RemotePort() const;
|
||||
private:
|
||||
|
||||
@ -530,7 +530,7 @@ struct ClientAuth_Struct {
|
||||
char key[30]; // the Key the client will present
|
||||
uint8 lsadmin; // login server admin level
|
||||
int16 worldadmin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
||||
uint32 ip;
|
||||
char ip[64];
|
||||
uint8 local; // 1 if the client is from the local network
|
||||
};
|
||||
|
||||
|
||||
@ -41,24 +41,6 @@ ADD_EXECUTABLE(loginserver ${eqlogin_sources} ${eqlogin_headers})
|
||||
|
||||
INSTALL(TARGETS loginserver RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(loginserver common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
|
||||
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(loginserver "ws2_32" "psapi" "iphlpapi" "userenv")
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(loginserver "${CMAKE_DL_LIBS}")
|
||||
TARGET_LINK_LIBRARIES(loginserver "z")
|
||||
TARGET_LINK_LIBRARIES(loginserver "m")
|
||||
IF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(loginserver "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(loginserver "pthread")
|
||||
TARGET_LINK_LIBRARIES(loginserver "EQEmuAuthCrypto")
|
||||
TARGET_LINK_LIBRARIES(loginserver "cryptopp")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(loginserver ${SERVER_LIBS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@ -197,7 +197,6 @@ int main()
|
||||
while (run_server) {
|
||||
Timer::SetCurrentTime();
|
||||
server.client_manager->Process();
|
||||
server.server_manager->Process();
|
||||
EQ::EventLoop::Get().Process();
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
@ -28,91 +28,58 @@ extern bool run_server;
|
||||
|
||||
ServerManager::ServerManager()
|
||||
{
|
||||
char error_buffer[TCPConnection_ErrorBufferSize];
|
||||
|
||||
int listen_port = atoi(server.config->GetVariable("options", "listen_port").c_str());
|
||||
tcps = new EmuTCPServer(listen_port, true);
|
||||
if(tcps->Open(listen_port, error_buffer)) {
|
||||
Log.Out(Logs::General, Logs::Login_Server, "ServerManager listening on port %u", listen_port);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::General, Logs::Error, "ServerManager fatal error opening port on %u: %s", listen_port, error_buffer);
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||
EQ::Net::ServertalkServerOptions opts;
|
||||
opts.port = listen_port;
|
||||
opts.ipv6 = false;
|
||||
server_connection->Listen(opts);
|
||||
|
||||
server_connection->OnConnectionIdentified("World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
|
||||
Log.OutF(Logs::General, Logs::Login_Server, "New world server connection from {0}:{1}", c->Handle()->RemoteIP(), c->Handle()->RemotePort());
|
||||
|
||||
WorldServer *server_entity = GetServerByAddress(c->Handle()->RemoteIP(), c->Handle()->RemotePort());
|
||||
if (server_entity) {
|
||||
Log.OutF(Logs::General, Logs::Login_Server, "World server already existed for {0}:{1}, removing existing connection and updating current.",
|
||||
c->Handle()->RemoteIP(), c->Handle()->RemotePort());
|
||||
|
||||
server_entity->SetConnection(c);
|
||||
server_entity->Reset();
|
||||
}
|
||||
else {
|
||||
world_servers.push_back(std::make_unique<WorldServer>(c));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
server_connection->OnConnectionRemoved("World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
|
||||
auto iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter)->GetConnection()->Handle() == c->Handle()) {
|
||||
Log.OutF(Logs::General, Logs::World_Server, "World server {0} has been disconnected, removing.", (*iter)->GetLongName().c_str());
|
||||
world_servers.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ServerManager::~ServerManager()
|
||||
{
|
||||
if (tcps) {
|
||||
tcps->Close();
|
||||
delete tcps;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ServerManager::Process()
|
||||
WorldServer* ServerManager::GetServerByAddress(const std::string &addr, int port)
|
||||
{
|
||||
ProcessDisconnect();
|
||||
EmuTCPConnection *tcp_c = nullptr;
|
||||
while (tcp_c = tcps->NewQueuePop()) {
|
||||
in_addr tmp;
|
||||
tmp.s_addr = tcp_c->GetrIP();
|
||||
Log.Out(Logs::General, Logs::Login_Server, "New world server connection from %s:%d", inet_ntoa(tmp), tcp_c->GetrPort());
|
||||
|
||||
WorldServer *server_entity = GetServerByAddress(tcp_c->GetrIP());
|
||||
if (server_entity) {
|
||||
Log.Out(Logs::General, Logs::Login_Server, "World server already existed for %s, removing existing connection and updating current.", inet_ntoa(tmp));
|
||||
server_entity->GetConnection()->Free();
|
||||
server_entity->SetConnection(tcp_c);
|
||||
server_entity->Reset();
|
||||
}
|
||||
else {
|
||||
WorldServer *w = new WorldServer(tcp_c);
|
||||
world_servers.push_back(w);
|
||||
}
|
||||
}
|
||||
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
auto iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter)->Process() == false) {
|
||||
Log.Out(Logs::General, Logs::World_Server, "World server %s had a fatal error and had to be removed from the login.", (*iter)->GetLongName().c_str());
|
||||
delete (*iter);
|
||||
iter = world_servers.erase(iter);
|
||||
}
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::ProcessDisconnect()
|
||||
{
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
EmuTCPConnection *connection = (*iter)->GetConnection();
|
||||
if (!connection->Connected()) {
|
||||
in_addr tmp;
|
||||
tmp.s_addr = connection->GetrIP();
|
||||
Log.Out(Logs::General, Logs::Login_Server, "World server disconnected from the server, removing server and freeing connection.");
|
||||
connection->Free();
|
||||
delete (*iter);
|
||||
iter = world_servers.erase(iter);
|
||||
}
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldServer* ServerManager::GetServerByAddress(unsigned int address)
|
||||
{
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter)->GetConnection()->GetrIP() == address) {
|
||||
return (*iter);
|
||||
if ((*iter)->GetConnection()->Handle()->RemoteIP() == addr && (*iter)->GetConnection()->Handle()->RemotePort()) {
|
||||
return (*iter).get();
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -124,15 +91,14 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c)
|
||||
in.s_addr = c->GetConnection()->GetRemoteIP();
|
||||
string client_ip = inet_ntoa(in);
|
||||
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
auto iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter)->IsAuthorized() == false) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
in.s_addr = (*iter)->GetConnection()->GetrIP();
|
||||
string world_ip = inet_ntoa(in);
|
||||
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
|
||||
|
||||
if (world_ip.compare(client_ip) == 0) {
|
||||
packet_size += (*iter)->GetLongName().size() + (*iter)->GetLocalIP().size() + 24;
|
||||
@ -171,8 +137,7 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c)
|
||||
continue;
|
||||
}
|
||||
|
||||
in.s_addr = (*iter)->GetConnection()->GetrIP();
|
||||
string world_ip = inet_ntoa(in);
|
||||
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
|
||||
if (world_ip.compare(client_ip) == 0) {
|
||||
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
|
||||
data_pointer += ((*iter)->GetLocalIP().size() + 1);
|
||||
@ -239,21 +204,21 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c)
|
||||
|
||||
void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int client_account_id)
|
||||
{
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
auto iter = world_servers.begin();
|
||||
bool found = false;
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter)->GetRuntimeID() == server_id) {
|
||||
ServerPacket *outapp = new ServerPacket(ServerOP_UsertoWorldReq, sizeof(UsertoWorldRequest_Struct));
|
||||
UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct*)outapp->pBuffer;
|
||||
EQ::Net::WritablePacket outapp;
|
||||
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
|
||||
UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct*)outapp.Data();
|
||||
utwr->worldid = server_id;
|
||||
utwr->lsaccountid = client_account_id;
|
||||
(*iter)->GetConnection()->SendPacket(outapp);
|
||||
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp);
|
||||
found = true;
|
||||
|
||||
if (server.options.IsDumpInPacketsOn()) {
|
||||
DumpPacket(outapp);
|
||||
Log.OutF(Logs::General, Logs::Login_Server, "{0}", outapp.ToString());
|
||||
}
|
||||
delete outapp;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
@ -265,9 +230,9 @@ void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int
|
||||
|
||||
bool ServerManager::ServerExists(string l_name, string s_name, WorldServer *ignore)
|
||||
{
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
auto iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter) == ignore) {
|
||||
if ((*iter).get() == ignore) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
@ -283,19 +248,14 @@ bool ServerManager::ServerExists(string l_name, string s_name, WorldServer *igno
|
||||
|
||||
void ServerManager::DestroyServerByName(string l_name, string s_name, WorldServer *ignore)
|
||||
{
|
||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
||||
auto iter = world_servers.begin();
|
||||
while (iter != world_servers.end()) {
|
||||
if ((*iter) == ignore) {
|
||||
if ((*iter).get() == ignore) {
|
||||
++iter;
|
||||
}
|
||||
|
||||
if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) {
|
||||
EmuTCPConnection *c = (*iter)->GetConnection();
|
||||
if (c->Connected()) {
|
||||
c->Disconnect();
|
||||
}
|
||||
c->Free();
|
||||
delete (*iter);
|
||||
(*iter)->GetConnection()->Handle()->Disconnect();
|
||||
iter = world_servers.erase(iter);
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "../common/emu_tcp_server.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "world_server.h"
|
||||
#include "client.h"
|
||||
#include <list>
|
||||
@ -43,11 +44,6 @@ public:
|
||||
*/
|
||||
~ServerManager();
|
||||
|
||||
/**
|
||||
* Does basic processing for all the servers.
|
||||
*/
|
||||
void Process();
|
||||
|
||||
/**
|
||||
* Sends a request to world to see if the client is banned or suspended.
|
||||
*/
|
||||
@ -69,19 +65,14 @@ public:
|
||||
void DestroyServerByName(std::string l_name, std::string s_name, WorldServer *ignore = nullptr);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Processes all the disconnected connections in Process(), not used outside.
|
||||
*/
|
||||
void ProcessDisconnect();
|
||||
|
||||
/**
|
||||
* Retrieves a server(if exists) by ip address
|
||||
* Useful utility for the reconnect process.
|
||||
*/
|
||||
WorldServer* GetServerByAddress(unsigned int address);
|
||||
WorldServer* GetServerByAddress(const std::string &address, int port);
|
||||
|
||||
EmuTCPServer* tcps;
|
||||
std::list<WorldServer*> world_servers;
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
std::list<std::unique_ptr<WorldServer>> world_servers;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
extern EQEmuLogSys Log;
|
||||
extern LoginServer server;
|
||||
|
||||
WorldServer::WorldServer(EmuTCPConnection *c)
|
||||
WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> c)
|
||||
{
|
||||
connection = c;
|
||||
zones_booted = 0;
|
||||
@ -37,13 +37,16 @@ WorldServer::WorldServer(EmuTCPConnection *c)
|
||||
is_server_authorized = false;
|
||||
is_server_trusted = false;
|
||||
is_server_logged_in = false;
|
||||
|
||||
c->OnMessage(ServerOP_NewLSInfo, std::bind(&WorldServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
c->OnMessage(ServerOP_LSStatus, std::bind(&WorldServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
c->OnMessage(ServerOP_UsertoWorldResp, std::bind(&WorldServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
c->OnMessage(ServerOP_LSAccountUpdate, std::bind(&WorldServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
WorldServer::~WorldServer()
|
||||
{
|
||||
if(connection) {
|
||||
connection->Free();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WorldServer::Reset()
|
||||
@ -58,183 +61,162 @@ void WorldServer::Reset()
|
||||
is_server_logged_in = false;
|
||||
}
|
||||
|
||||
bool WorldServer::Process()
|
||||
void WorldServer::ProcessPacket(uint16_t opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
ServerPacket *app = nullptr;
|
||||
while(app = connection->PopPacket())
|
||||
if(server.options.IsWorldTraceOn())
|
||||
{
|
||||
if(server.options.IsWorldTraceOn())
|
||||
Log.Out(Logs::General, Logs::Netcode, "Application packet received from server: 0x%.4X, (size %u)", opcode, p.Length());
|
||||
}
|
||||
|
||||
if(server.options.IsDumpInPacketsOn())
|
||||
{
|
||||
Log.OutF(Logs::General, Logs::Login_Server, "{0}", p.ToString());
|
||||
}
|
||||
|
||||
switch(opcode)
|
||||
{
|
||||
case ServerOP_NewLSInfo:
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "Application packet received from server: 0x%.4X, (size %u)", app->opcode, app->size);
|
||||
if(p.Length() < sizeof(ServerNewLSInfo_Struct))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Received application packet from server that had opcode ServerOP_NewLSInfo, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(server.options.IsWorldTraceOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "New Login Info Recieved.");
|
||||
}
|
||||
|
||||
ServerNewLSInfo_Struct *info = (ServerNewLSInfo_Struct*)p.Data();
|
||||
Handle_NewLSInfo(info);
|
||||
break;
|
||||
}
|
||||
|
||||
if(server.options.IsDumpInPacketsOn())
|
||||
case ServerOP_LSStatus:
|
||||
{
|
||||
DumpPacket(app);
|
||||
if(p.Length() < sizeof(ServerLSStatus_Struct))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_LSStatus, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(server.options.IsWorldTraceOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "World Server Status Recieved.");
|
||||
}
|
||||
|
||||
ServerLSStatus_Struct *ls_status = (ServerLSStatus_Struct*)p.Data();
|
||||
Handle_LSStatus(ls_status);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(app->opcode)
|
||||
case ServerOP_UsertoWorldResp:
|
||||
{
|
||||
case ServerOP_NewLSInfo:
|
||||
if(p.Length() < sizeof(UsertoWorldResponse_Struct))
|
||||
{
|
||||
if(app->size < sizeof(ServerNewLSInfo_Struct))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Received application packet from server that had opcode ServerOP_NewLSInfo, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(server.options.IsWorldTraceOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "New Login Info Recieved.");
|
||||
}
|
||||
|
||||
ServerNewLSInfo_Struct *info = (ServerNewLSInfo_Struct*)app->pBuffer;
|
||||
Handle_NewLSInfo(info);
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_UsertoWorldResp, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSStatus:
|
||||
|
||||
//I don't use world trace for this and here is why:
|
||||
//Because this is a part of the client login procedure it makes tracking client errors
|
||||
//While keeping world server spam with multiple servers connected almost impossible.
|
||||
if(server.options.IsTraceOn())
|
||||
{
|
||||
if(app->size < sizeof(ServerLSStatus_Struct))
|
||||
Log.Out(Logs::General, Logs::Netcode, "User-To-World Response received.");
|
||||
}
|
||||
|
||||
UsertoWorldResponse_Struct *utwr = (UsertoWorldResponse_Struct*)p.Data();
|
||||
Log.Out(Logs::General, Logs::Debug, "Trying to find client with user id of %u.", utwr->lsaccountid);
|
||||
Client *c = server.client_manager->GetClient(utwr->lsaccountid);
|
||||
if(c)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Debug, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str());
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse_Struct));
|
||||
PlayEverquestResponse_Struct *per = (PlayEverquestResponse_Struct*)outapp->pBuffer;
|
||||
per->Sequence = c->GetPlaySequence();
|
||||
per->ServerNumber = c->GetPlayServerID();
|
||||
Log.Out(Logs::General, Logs::Debug, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID());
|
||||
|
||||
Log.Out(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str());
|
||||
|
||||
if(utwr->response > 0)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_LSStatus, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
per->Allowed = 1;
|
||||
SendClientAuth(c->GetConnection()->GetRemoteAddr(), c->GetAccountName(), c->GetKey(), c->GetAccountID());
|
||||
}
|
||||
|
||||
switch(utwr->response)
|
||||
{
|
||||
case 1:
|
||||
per->Message = 101;
|
||||
break;
|
||||
case 0:
|
||||
per->Message = 326;
|
||||
break;
|
||||
case -1:
|
||||
per->Message = 337;
|
||||
break;
|
||||
case -2:
|
||||
per->Message = 338;
|
||||
break;
|
||||
case -3:
|
||||
per->Message = 303;
|
||||
break;
|
||||
}
|
||||
|
||||
if(server.options.IsWorldTraceOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "World Server Status Recieved.");
|
||||
}
|
||||
|
||||
ServerLSStatus_Struct *ls_status = (ServerLSStatus_Struct*)app->pBuffer;
|
||||
Handle_LSStatus(ls_status);
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSZoneInfo:
|
||||
case ServerOP_LSZoneShutdown:
|
||||
case ServerOP_LSZoneStart:
|
||||
case ServerOP_LSZoneBoot:
|
||||
case ServerOP_LSZoneSleep:
|
||||
case ServerOP_LSPlayerLeftWorld:
|
||||
case ServerOP_LSPlayerJoinWorld:
|
||||
case ServerOP_LSPlayerZoneChange:
|
||||
{
|
||||
//Not logging these to cut down on spam until we implement them
|
||||
break;
|
||||
}
|
||||
|
||||
case ServerOP_UsertoWorldResp:
|
||||
{
|
||||
if(app->size < sizeof(UsertoWorldResponse_Struct))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_UsertoWorldResp, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
|
||||
//I don't use world trace for this and here is why:
|
||||
//Because this is a part of the client login procedure it makes tracking client errors
|
||||
//While keeping world server spam with multiple servers connected almost impossible.
|
||||
|
||||
if(server.options.IsTraceOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "User-To-World Response received.");
|
||||
}
|
||||
|
||||
UsertoWorldResponse_Struct *utwr = (UsertoWorldResponse_Struct*)app->pBuffer;
|
||||
Log.Out(Logs::General, Logs::Debug, "Trying to find client with user id of %u.", utwr->lsaccountid);
|
||||
Client *c = server.client_manager->GetClient(utwr->lsaccountid);
|
||||
if(c)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Debug, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str());
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse_Struct));
|
||||
PlayEverquestResponse_Struct *per = (PlayEverquestResponse_Struct*)outapp->pBuffer;
|
||||
per->Sequence = c->GetPlaySequence();
|
||||
per->ServerNumber = c->GetPlayServerID();
|
||||
Log.Out(Logs::General, Logs::Debug, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID());
|
||||
|
||||
Log.Out(Logs::General, Logs::Netcode, "Sending play response with following data, allowed %u, sequence %u, server number %u, message %u",
|
||||
per->Allowed, per->Sequence, per->ServerNumber, per->Message);
|
||||
Log.Out(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str());
|
||||
|
||||
if(utwr->response > 0)
|
||||
{
|
||||
per->Allowed = 1;
|
||||
SendClientAuth(c->GetConnection()->GetRemoteIP(), c->GetAccountName(), c->GetKey(), c->GetAccountID());
|
||||
}
|
||||
|
||||
switch(utwr->response)
|
||||
{
|
||||
case 1:
|
||||
per->Message = 101;
|
||||
break;
|
||||
case 0:
|
||||
per->Message = 326;
|
||||
break;
|
||||
case -1:
|
||||
per->Message = 337;
|
||||
break;
|
||||
case -2:
|
||||
per->Message = 338;
|
||||
break;
|
||||
case -3:
|
||||
per->Message = 303;
|
||||
break;
|
||||
}
|
||||
|
||||
if(server.options.IsTraceOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "Sending play response with following data, allowed %u, sequence %u, server number %u, message %u",
|
||||
per->Allowed, per->Sequence, per->ServerNumber, per->Message);
|
||||
Log.Out(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str());
|
||||
}
|
||||
|
||||
if(server.options.IsDumpOutPacketsOn())
|
||||
{
|
||||
DumpPacket(outapp);
|
||||
}
|
||||
|
||||
c->SendPlayResponse(outapp);
|
||||
delete outapp;
|
||||
}
|
||||
else
|
||||
|
||||
if(server.options.IsDumpOutPacketsOn())
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid);
|
||||
DumpPacket(outapp);
|
||||
}
|
||||
break;
|
||||
|
||||
c->SendPlayResponse(outapp);
|
||||
delete outapp;
|
||||
}
|
||||
case ServerOP_LSAccountUpdate:
|
||||
else
|
||||
{
|
||||
if(app->size < sizeof(ServerLSAccountUpdate_Struct))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerLSAccountUpdate_Struct, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
|
||||
Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str());
|
||||
ServerLSAccountUpdate_Struct *lsau = (ServerLSAccountUpdate_Struct*)app->pBuffer;
|
||||
if(is_server_trusted)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate update processed for: %s", lsau->useraccount);
|
||||
string name;
|
||||
string password;
|
||||
string email;
|
||||
name.assign(lsau->useraccount);
|
||||
password.assign(lsau->userpassword);
|
||||
email.assign(lsau->useremail);
|
||||
server.db->UpdateLSAccountInfo(lsau->useraccountid, name, password, email);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had an unknown operation code 0x%.4X.", app->opcode);
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSAccountUpdate:
|
||||
{
|
||||
if(p.Length() < sizeof(ServerLSAccountUpdate_Struct))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerLSAccountUpdate_Struct, "
|
||||
"but was too small. Discarded to avoid buffer overrun.");
|
||||
break;
|
||||
}
|
||||
|
||||
Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str());
|
||||
ServerLSAccountUpdate_Struct *lsau = (ServerLSAccountUpdate_Struct*)p.Data();
|
||||
if(is_server_trusted)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate update processed for: %s", lsau->useraccount);
|
||||
string name;
|
||||
string password;
|
||||
string email;
|
||||
name.assign(lsau->useraccount);
|
||||
password.assign(lsau->userpassword);
|
||||
email.assign(lsau->useremail);
|
||||
server.db->UpdateLSAccountInfo(lsau->useraccountid, name, password, email);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had an unknown operation code 0x%.4X.", opcode);
|
||||
}
|
||||
|
||||
delete app;
|
||||
app = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
||||
@ -308,8 +290,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
||||
if(strlen(i->remote_address) == 0)
|
||||
{
|
||||
in_addr in;
|
||||
in.s_addr = GetConnection()->GetrIP();
|
||||
remote_ip = inet_ntoa(in);
|
||||
remote_ip = GetConnection()->Handle()->RemoteIP();
|
||||
Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was null, defaulting to stream address %s.", remote_ip.c_str());
|
||||
}
|
||||
else
|
||||
@ -320,8 +301,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
||||
else
|
||||
{
|
||||
in_addr in;
|
||||
in.s_addr = GetConnection()->GetrIP();
|
||||
remote_ip = inet_ntoa(in);
|
||||
remote_ip = GetConnection()->Handle()->RemoteIP();
|
||||
Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was too long, defaulting to stream address %s.", remote_ip.c_str());
|
||||
}
|
||||
|
||||
@ -491,9 +471,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
||||
}
|
||||
}
|
||||
|
||||
in_addr in;
|
||||
in.s_addr = connection->GetrIP();
|
||||
server.db->UpdateWorldRegistration(GetRuntimeID(), long_name, string(inet_ntoa(in)));
|
||||
server.db->UpdateWorldRegistration(GetRuntimeID(), long_name, GetConnection()->Handle()->RemoteIP());
|
||||
|
||||
if(is_server_authorized)
|
||||
{
|
||||
@ -508,7 +486,7 @@ void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s)
|
||||
server_status = s->status;
|
||||
}
|
||||
|
||||
void WorldServer::SendClientAuth(unsigned int ip, string account, string key, unsigned int account_id)
|
||||
void WorldServer::SendClientAuth(std::string ip, string account, string key, unsigned int account_id)
|
||||
{
|
||||
ServerPacket *outapp = new ServerPacket(ServerOP_LSClientAuth, sizeof(ClientAuth_Struct));
|
||||
ClientAuth_Struct* client_auth = (ClientAuth_Struct*)outapp->pBuffer;
|
||||
@ -518,13 +496,10 @@ void WorldServer::SendClientAuth(unsigned int ip, string account, string key, un
|
||||
strncpy(client_auth->key, key.c_str(), 10);
|
||||
client_auth->lsadmin = 0;
|
||||
client_auth->worldadmin = 0;
|
||||
client_auth->ip = ip;
|
||||
strcpy(client_auth->ip, ip.c_str());
|
||||
|
||||
in_addr in;
|
||||
in.s_addr = ip; connection->GetrIP();
|
||||
string client_address(inet_ntoa(in));
|
||||
in.s_addr = connection->GetrIP();
|
||||
string world_address(inet_ntoa(in));
|
||||
string client_address(ip);
|
||||
string world_address(connection->Handle()->RemoteIP());
|
||||
|
||||
if (client_address.compare(world_address) == 0) {
|
||||
client_auth->local = 1;
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
#define EQEMU_WORLDSERVER_H
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "../common/emu_tcp_server.h"
|
||||
#include "../common/net/servertalk_server_connection.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* World server class, controls the connected server processing.
|
||||
@ -34,7 +34,7 @@ public:
|
||||
/**
|
||||
* Constructor, sets our connection to c.
|
||||
*/
|
||||
WorldServer(EmuTCPConnection *c);
|
||||
WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> c);
|
||||
|
||||
/**
|
||||
* Destructor, frees our connection if it exists.
|
||||
@ -47,20 +47,19 @@ public:
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Does processing of all the connections for this world.
|
||||
* Returns true except for a fatal error that requires disconnection.
|
||||
* Does processing of all the packets in for this world.
|
||||
*/
|
||||
bool Process();
|
||||
void ProcessPacket(uint16_t opcode, const EQ::Net::Packet &p);
|
||||
|
||||
/**
|
||||
* Accesses connection, it is intentional that this is not const (trust me).
|
||||
*/
|
||||
EmuTCPConnection *GetConnection() { return connection; }
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> GetConnection() { return connection; }
|
||||
|
||||
/**
|
||||
* Sets the connection to c.
|
||||
*/
|
||||
void SetConnection(EmuTCPConnection *c) { connection = c; }
|
||||
void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> c) { connection = c; }
|
||||
|
||||
/**
|
||||
* Gets the runtime id of this server.
|
||||
@ -130,11 +129,11 @@ public:
|
||||
/**
|
||||
* Informs world that there is a client incoming with the following data.
|
||||
*/
|
||||
void SendClientAuth(unsigned int ip, std::string account, std::string key, unsigned int account_id);
|
||||
void SendClientAuth(std::string ip, std::string account, std::string key, unsigned int account_id);
|
||||
|
||||
private:
|
||||
|
||||
EmuTCPConnection *connection;
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
|
||||
unsigned int zones_booted;
|
||||
unsigned int players_online;
|
||||
int server_status;
|
||||
|
||||
22
ucs/ucs.cpp
22
ucs/ucs.cpp
@ -34,7 +34,6 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "../common/net/tcp_server.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
|
||||
ChatChannelList *ChannelList;
|
||||
@ -146,21 +145,14 @@ int main() {
|
||||
|
||||
worldserver->Connect();
|
||||
|
||||
EQ::Net::ServertalkServer server;
|
||||
EQ::Net::ServertalkServerOptions opts;
|
||||
opts.port = 5999;
|
||||
opts.credentials = "User:Root;Password:1234567890";
|
||||
server.Listen(opts);
|
||||
|
||||
server.OnConnectionIdentified("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> conn) {
|
||||
Log.Out(Logs::General, Logs::Debug, "New QueryServ Connection....");
|
||||
});
|
||||
|
||||
server.OnConnectionRemoved("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> conn) {
|
||||
Log.Out(Logs::General, Logs::Debug, "Lost QueryServ connection.");
|
||||
});
|
||||
|
||||
EQ::Net::ServertalkClient client("127.0.0.1", 5999, false, "QueryServ", "User:Root;Password:1234567890");
|
||||
client.OnMessage(1, [&](uint16_t opcode, EQ::Net::Packet &p) {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Client got message of type {0}\n{1}", opcode, p.ToString());
|
||||
|
||||
EQ::Net::WritablePacket out;
|
||||
out.PutCString(0, "Why Hello");
|
||||
client.Send(2, out);
|
||||
});
|
||||
|
||||
while(RunLoops) {
|
||||
|
||||
|
||||
@ -467,7 +467,6 @@ void Console::ProcessCommand(const char* command) {
|
||||
SendMessage(1, " IPLookup [name]");
|
||||
}
|
||||
if (admin >= 100) {
|
||||
SendMessage(1, " LSReconnect");
|
||||
SendMessage(1, " signalcharbyname charname ID");
|
||||
SendMessage(1, " reloadworld");
|
||||
}
|
||||
@ -794,17 +793,6 @@ void Console::ProcessCommand(const char* command) {
|
||||
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], "LSReconnect") == 0 && admin >= 100) {
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(AutoInitLoginServer, 0, nullptr);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr);
|
||||
#endif
|
||||
RunLoops = true;
|
||||
SendMessage(1, " Login Server Reconnect manually restarted by Console");
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Login Server Reconnect manually restarted by Console");
|
||||
}
|
||||
else if (strcasecmp(sep.arg[0], "zonelock") == 0 && admin >= consoleZoneStatus) {
|
||||
if (strcasecmp(sep.arg[1], "list") == 0) {
|
||||
zoneserver_list.ListLockedZones(0, this);
|
||||
|
||||
@ -261,84 +261,6 @@ void EQW::CreateLauncher(Const_char *launcher_name, int dynamic_count) {
|
||||
launcher_list.CreateLauncher(launcher_name, dynamic_count);
|
||||
}
|
||||
|
||||
void EQW::LSReconnect() {
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(AutoInitLoginServer, 0, nullptr);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr);
|
||||
#endif
|
||||
RunLoops = true;
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Login Server Reconnect manually restarted by Web Tool");
|
||||
}
|
||||
|
||||
/*EQLConfig * EQW::FindLauncher(Const_char *zone_ref) {
|
||||
return(nullptr);
|
||||
}*/
|
||||
|
||||
/*
|
||||
map<string,string> EQW::GetLaunchersDetails(Const_char *launcher_name) {
|
||||
map<string,string> res;
|
||||
|
||||
LauncherLink *ll = launcher_list.Get(launcher_name);
|
||||
if(ll == nullptr) {
|
||||
res["name"] = launcher_name;
|
||||
res["ip"] = "Not Connected";
|
||||
res["id"] = "0";
|
||||
res["zone_count"] = "0";
|
||||
res["connected"] = "no";
|
||||
return(res);
|
||||
} else {
|
||||
res["name"] = ll->GetName();
|
||||
res["ip"] = long2ip(ll->GetIP());
|
||||
res["id"] = itoa(ll->GetID());
|
||||
res["zone_count"] = itoa(ll->CountZones());
|
||||
res["connected"] = "yes";
|
||||
}
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
vector<string> EQW::ListLauncherZones(Const_char *launcher_name) {
|
||||
vector<string> list;
|
||||
LauncherLink *ll = launcher_list.Get(launcher_name);
|
||||
if(ll != nullptr) {
|
||||
ll->GetZoneList(list);
|
||||
}
|
||||
return(list);
|
||||
}
|
||||
|
||||
map<string,string> EQW::GetLauncherZoneDetails(Const_char *launcher_name, Const_char *zone_ref) {
|
||||
map<string,string> res;
|
||||
LauncherLink *ll = launcher_list.Get(launcher_name);
|
||||
if(ll != nullptr) {
|
||||
ll->GetZoneDetails(zone_ref, res);
|
||||
} else {
|
||||
res["error"] = "Launcher Not Found";
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
void EQW::CreateLauncher(Const_char *launcher_name, int dynamic_count) {
|
||||
}
|
||||
|
||||
bool EQW::BootStaticZone(Const_char *launcher_name, Const_char *short_name) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool EQW::DeleteStaticZone(Const_char *launcher_name, Const_char *short_name) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool EQW::SetDynamicCount(Const_char *launcher_name, int count) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
int EQW::GetDynamicCount(Const_char *launcher_name) {
|
||||
return(0);
|
||||
}
|
||||
*/
|
||||
|
||||
uint32 EQW::CreateGuild(const char* name, uint32 leader_char_id) {
|
||||
uint32 id = guild_mgr.CreateGuild(name, leader_char_id);
|
||||
if(id != GUILD_NONE)
|
||||
|
||||
@ -42,7 +42,6 @@ public:
|
||||
void UnlockWorld();
|
||||
|
||||
bool LSConnected();
|
||||
void LSReconnect();
|
||||
|
||||
int CountZones();
|
||||
std::vector<std::string> ListBootedZones(); //returns an array of zone_refs (opaque)
|
||||
|
||||
@ -22,35 +22,6 @@
|
||||
#include <iomanip>
|
||||
#include <stdlib.h>
|
||||
#include "../common/version.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#else // Pyro: fix for linux
|
||||
#include <sys/socket.h>
|
||||
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../common/unix.h"
|
||||
|
||||
#define SOCKET_ERROR -1
|
||||
#define INVALID_SOCKET -1
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define IGNORE_LS_FATAL_ERROR
|
||||
|
||||
#include "../common/servertalk.h"
|
||||
#include "login_server.h"
|
||||
#include "login_server_list.h"
|
||||
@ -70,145 +41,107 @@ extern uint32 numplayers;
|
||||
extern volatile bool RunLoops;
|
||||
|
||||
LoginServer::LoginServer(const char* iAddress, uint16 iPort, const char* Account, const char* Password)
|
||||
: statusupdate_timer(LoginServer_StatusUpdateInterval)
|
||||
{
|
||||
strn0cpy(LoginServerAddress,iAddress,256);
|
||||
LoginServerPort = iPort;
|
||||
strn0cpy(LoginAccount,Account,31);
|
||||
strn0cpy(LoginPassword,Password,31);
|
||||
CanAccountUpdate = false;
|
||||
tcpc = new EmuTCPConnection(true);
|
||||
tcpc->SetPacketMode(EmuTCPConnection::packetModeLogin);
|
||||
Connect();
|
||||
}
|
||||
|
||||
LoginServer::~LoginServer() {
|
||||
delete tcpc;
|
||||
}
|
||||
|
||||
bool LoginServer::Process() {
|
||||
void LoginServer::ProcessPacket(uint16_t opcode, EQ::Net::Packet &p) {
|
||||
const WorldConfig *Config=WorldConfig::get();
|
||||
|
||||
if (statusupdate_timer.Check()) {
|
||||
this->SendStatus();
|
||||
}
|
||||
|
||||
/************ Get all packets from packet manager out queue and process them ************/
|
||||
ServerPacket *pack = 0;
|
||||
while((pack = tcpc->PopPacket()))
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode);
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Recevied ServerPacket from LS OpCode 0x04x", opcode);
|
||||
|
||||
switch(pack->opcode) {
|
||||
case 0:
|
||||
break;
|
||||
case ServerOP_KeepAlive: {
|
||||
// ignore this
|
||||
break;
|
||||
}
|
||||
case ServerOP_UsertoWorldReq: {
|
||||
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer;
|
||||
uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
|
||||
int16 status = database.CheckStatus(id);
|
||||
switch(opcode) {
|
||||
case ServerOP_UsertoWorldReq: {
|
||||
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*)p.Data();
|
||||
uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
|
||||
int16 status = database.CheckStatus(id);
|
||||
|
||||
auto outpack = new ServerPacket;
|
||||
outpack->opcode = ServerOP_UsertoWorldResp;
|
||||
outpack->size = sizeof(UsertoWorldResponse_Struct);
|
||||
outpack->pBuffer = new uchar[outpack->size];
|
||||
memset(outpack->pBuffer, 0, outpack->size);
|
||||
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
|
||||
utwrs->lsaccountid = utwr->lsaccountid;
|
||||
utwrs->ToID = utwr->FromID;
|
||||
auto outpack = new ServerPacket;
|
||||
outpack->opcode = ServerOP_UsertoWorldResp;
|
||||
outpack->size = sizeof(UsertoWorldResponse_Struct);
|
||||
outpack->pBuffer = new uchar[outpack->size];
|
||||
memset(outpack->pBuffer, 0, outpack->size);
|
||||
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
|
||||
utwrs->lsaccountid = utwr->lsaccountid;
|
||||
utwrs->ToID = utwr->FromID;
|
||||
|
||||
if(Config->Locked == true)
|
||||
{
|
||||
if((status == 0 || status < 100) && (status != -2 || status != -1))
|
||||
utwrs->response = 0;
|
||||
if(status >= 100)
|
||||
utwrs->response = 1;
|
||||
}
|
||||
else {
|
||||
utwrs->response = 1;
|
||||
}
|
||||
|
||||
int32 x = Config->MaxClients;
|
||||
if( (int32)numplayers >= x && x != -1 && x != 255 && status < 80)
|
||||
utwrs->response = -3;
|
||||
|
||||
if(status == -1)
|
||||
utwrs->response = -1;
|
||||
if(status == -2)
|
||||
utwrs->response = -2;
|
||||
|
||||
utwrs->worldid = utwr->worldid;
|
||||
SendPacket(outpack);
|
||||
delete outpack;
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSClientAuth: {
|
||||
ClientAuth_Struct* slsca = (ClientAuth_Struct*) pack->pBuffer;
|
||||
|
||||
if (RuleI(World, AccountSessionLimit) >= 0) {
|
||||
// Enforce the limit on the number of characters on the same account that can be
|
||||
// online at the same time.
|
||||
client_list.EnforceSessionLimit(slsca->lsaccount_id);
|
||||
}
|
||||
|
||||
client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSFatalError: {
|
||||
#ifndef IGNORE_LS_FATAL_ERROR
|
||||
WorldConfig::DisableLoginserver();
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Login server responded with FatalError. Disabling reconnect.");
|
||||
#else
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Login server responded with FatalError.");
|
||||
#endif
|
||||
if (pack->size > 1) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, " %s",pack->pBuffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_SystemwideMessage: {
|
||||
ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack->pBuffer;
|
||||
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSRemoteAddr: {
|
||||
if (!Config->WorldAddress.length()) {
|
||||
WorldConfig::SetWorldAddress((char *)pack->pBuffer);
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Loginserver provided %s as world address",pack->pBuffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSAccountUpdate: {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Received ServerOP_LSAccountUpdate packet from loginserver");
|
||||
CanAccountUpdate = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if(Config->Locked == true)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Unknown LSOpCode: 0x%04x size=%d",(int)pack->opcode,pack->size);
|
||||
DumpPacket(pack->pBuffer, pack->size);
|
||||
break;
|
||||
if((status == 0 || status < 100) && (status != -2 || status != -1))
|
||||
utwrs->response = 0;
|
||||
if(status >= 100)
|
||||
utwrs->response = 1;
|
||||
}
|
||||
else {
|
||||
utwrs->response = 1;
|
||||
}
|
||||
|
||||
int32 x = Config->MaxClients;
|
||||
if( (int32)numplayers >= x && x != -1 && x != 255 && status < 80)
|
||||
utwrs->response = -3;
|
||||
|
||||
if(status == -1)
|
||||
utwrs->response = -1;
|
||||
if(status == -2)
|
||||
utwrs->response = -2;
|
||||
|
||||
utwrs->worldid = utwr->worldid;
|
||||
SendPacket(outpack);
|
||||
delete outpack;
|
||||
break;
|
||||
}
|
||||
delete pack;
|
||||
}
|
||||
case ServerOP_LSClientAuth: {
|
||||
ClientAuth_Struct* slsca = (ClientAuth_Struct*)p.Data();
|
||||
|
||||
return true;
|
||||
}
|
||||
if (RuleI(World, AccountSessionLimit) >= 0) {
|
||||
// Enforce the limit on the number of characters on the same account that can be
|
||||
// online at the same time.
|
||||
client_list.EnforceSessionLimit(slsca->lsaccount_id);
|
||||
}
|
||||
|
||||
bool LoginServer::InitLoginServer() {
|
||||
if(Connected() == false) {
|
||||
if(ConnectReady()) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Connecting to login server: %s:%d",LoginServerAddress,LoginServerPort);
|
||||
Connect();
|
||||
} else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Not connected but not ready to connect, this is bad: %s:%d",
|
||||
LoginServerAddress,LoginServerPort);
|
||||
client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, inet_addr(slsca->ip), slsca->local);
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSFatalError: {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Login server responded with FatalError.");
|
||||
if (p.Length() > 1) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, " %s", (const char*)p.Data());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_SystemwideMessage: {
|
||||
ServerSystemwideMessage* swm = (ServerSystemwideMessage*)p.Data();
|
||||
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSRemoteAddr: {
|
||||
if (!Config->WorldAddress.length()) {
|
||||
WorldConfig::SetWorldAddress((char *)p.Data());
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Loginserver provided %s as world address", (const char*)p.Data());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_LSAccountUpdate: {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Received ServerOP_LSAccountUpdate packet from loginserver");
|
||||
CanAccountUpdate = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Unknown LSOpCode: 0x%04x size=%d",(int)opcode, p.Length());
|
||||
Log.OutF(Logs::General, Logs::Login_Server, "{0}", p.ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoginServer::Connect() {
|
||||
@ -236,20 +169,32 @@ bool LoginServer::Connect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Connected to Loginserver: %s:%d",LoginServerAddress,LoginServerPort);
|
||||
if (minilogin)
|
||||
SendInfo();
|
||||
else
|
||||
SendNewInfo();
|
||||
SendStatus();
|
||||
zoneserver_list.SendLSZones();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Could not connect to login server: %s:%d %s",LoginServerAddress,LoginServerPort,errbuf);
|
||||
return false;
|
||||
}
|
||||
client.reset(new EQ::Net::ServertalkClient(LoginServerAddress, LoginServerPort, false, "World", ""));
|
||||
client->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
||||
if (client) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Connected to Loginserver: %s:%d", LoginServerAddress, LoginServerPort);
|
||||
if (minilogin)
|
||||
SendInfo();
|
||||
else
|
||||
SendNewInfo();
|
||||
SendStatus();
|
||||
zoneserver_list.SendLSZones();
|
||||
|
||||
statusupdate_timer.reset(new EQ::Timer(LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) {
|
||||
SendStatus();
|
||||
}));
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Could not connect to Loginserver: %s:%d", LoginServerAddress, LoginServerPort);
|
||||
}
|
||||
});
|
||||
|
||||
client->OnMessage(ServerOP_UsertoWorldReq, std::bind(&LoginServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
client->OnMessage(ServerOP_LSClientAuth, std::bind(&LoginServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
client->OnMessage(ServerOP_LSFatalError, std::bind(&LoginServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
client->OnMessage(ServerOP_SystemwideMessage, std::bind(&LoginServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
client->OnMessage(ServerOP_LSRemoteAddr, std::bind(&LoginServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
client->OnMessage(ServerOP_LSAccountUpdate, std::bind(&LoginServer::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
void LoginServer::SendInfo() {
|
||||
const WorldConfig *Config=WorldConfig::get();
|
||||
@ -291,15 +236,13 @@ void LoginServer::SendNewInfo() {
|
||||
if (Config->LocalAddress.length())
|
||||
strcpy(lsi->local_address, Config->LocalAddress.c_str());
|
||||
else {
|
||||
tcpc->GetSockName(lsi->local_address,&port);
|
||||
WorldConfig::SetLocalAddress(lsi->local_address);
|
||||
WorldConfig::SetLocalAddress(client->Handle()->LocalIP());
|
||||
}
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
}
|
||||
|
||||
void LoginServer::SendStatus() {
|
||||
statusupdate_timer.Start();
|
||||
auto pack = new ServerPacket;
|
||||
pack->opcode = ServerOP_LSStatus;
|
||||
pack->size = sizeof(ServerLSStatus_Struct);
|
||||
|
||||
@ -24,39 +24,37 @@
|
||||
#include "../common/queue.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
#include "../common/event/timer.h"
|
||||
#include <memory>
|
||||
|
||||
class LoginServer{
|
||||
public:
|
||||
LoginServer(const char*, uint16, const char*, const char*);
|
||||
~LoginServer();
|
||||
|
||||
bool InitLoginServer();
|
||||
|
||||
bool Process();
|
||||
void ProcessPacket(uint16_t opcode, EQ::Net::Packet &p);
|
||||
bool Connect();
|
||||
|
||||
void SendInfo();
|
||||
void SendNewInfo();
|
||||
void SendStatus();
|
||||
|
||||
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
|
||||
void SendPacket(ServerPacket* pack) { client->SendPacket(pack); }
|
||||
void SendAccountUpdate(ServerPacket* pack);
|
||||
bool ConnectReady() { return tcpc->ConnectReady(); }
|
||||
bool Connected() { return tcpc->Connected(); }
|
||||
bool Connected() { return client->Connected(); }
|
||||
bool MiniLogin() { return minilogin; }
|
||||
bool CanUpdate() { return CanAccountUpdate; }
|
||||
|
||||
private:
|
||||
bool minilogin;
|
||||
EmuTCPConnection* tcpc;
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> client;
|
||||
std::unique_ptr<EQ::Timer> statusupdate_timer;
|
||||
char LoginServerAddress[256];
|
||||
uint32 LoginServerIP;
|
||||
uint16 LoginServerPort;
|
||||
char LoginAccount[32];
|
||||
char LoginPassword[32];
|
||||
bool CanAccountUpdate;
|
||||
|
||||
Timer statusupdate_timer;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -55,38 +55,6 @@ void LoginServerList::Add(const char* iAddress, uint16 iPort, const char* Accoun
|
||||
list.Insert(loginserver);
|
||||
}
|
||||
|
||||
bool LoginServerList::Process() {
|
||||
LinkedListIterator<LoginServer*> iterator(list);
|
||||
|
||||
iterator.Reset();
|
||||
while(iterator.MoreElements()){
|
||||
iterator.GetData()->Process();
|
||||
iterator.Advance();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS
|
||||
void AutoInitLoginServer(void *tmp) {
|
||||
#else
|
||||
void *AutoInitLoginServer(void *tmp) {
|
||||
#endif
|
||||
loginserverlist.InitLoginServer();
|
||||
#ifndef WIN32
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoginServerList::InitLoginServer() {
|
||||
LinkedListIterator<LoginServer*> iterator(list);
|
||||
|
||||
iterator.Reset();
|
||||
while(iterator.MoreElements()){
|
||||
iterator.GetData()->InitLoginServer();
|
||||
iterator.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
bool LoginServerList::SendInfo() {
|
||||
LinkedListIterator<LoginServer*> iterator(list);
|
||||
|
||||
|
||||
@ -9,12 +9,6 @@
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/emu_tcp_connection.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
void AutoInitLoginServer(void *tmp);
|
||||
#else
|
||||
void *AutoInitLoginServer(void *tmp);
|
||||
#endif
|
||||
|
||||
class LoginServer;
|
||||
|
||||
class LoginServerList{
|
||||
@ -23,9 +17,6 @@ public:
|
||||
~LoginServerList();
|
||||
|
||||
void Add(const char*, uint16, const char*, const char*);
|
||||
void InitLoginServer();
|
||||
|
||||
bool Process();
|
||||
|
||||
bool SendInfo();
|
||||
bool SendNewInfo();
|
||||
|
||||
@ -86,6 +86,9 @@
|
||||
#include "ucs.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
#include "../common/net/tcp_server.h"
|
||||
#include "../common/net/servertalk_server.h"
|
||||
|
||||
EmuTCPServer tcps;
|
||||
ClientList client_list;
|
||||
GroupLFPList LFPGroupList;
|
||||
@ -412,6 +415,28 @@ int main(int argc, char** argv) {
|
||||
Log.OutF(Logs::Detail, Logs::World_Server, "New connection from IP {0}:{1}", stream->RemoteEndpoint(), ntohs(stream->GetRemotePort()));
|
||||
});
|
||||
|
||||
EQ::Net::ServertalkServer server;
|
||||
EQ::Net::ServertalkServerOptions stopts;
|
||||
stopts.port = 5999;
|
||||
stopts.credentials = "User:Root;Password:1234567890";
|
||||
stopts.encrypted = true;
|
||||
server.Listen(stopts);
|
||||
|
||||
server.OnConnectionIdentified("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> conn) {
|
||||
Log.Out(Logs::General, Logs::Debug, "New QueryServ Connection....");
|
||||
EQ::Net::WritablePacket out;
|
||||
out.PutCString(0, "Hello");
|
||||
conn->Send(1, out);
|
||||
|
||||
conn->OnMessage(2, [&](uint16_t opcode, EQ::Net::Packet &p) {
|
||||
Log.OutF(Logs::General, Logs::Debug, "Server got message of type {0}\n{1}", opcode, p.ToString());
|
||||
});
|
||||
});
|
||||
|
||||
server.OnConnectionRemoved("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> conn) {
|
||||
Log.Out(Logs::General, Logs::Debug, "Lost QueryServ connection.");
|
||||
});
|
||||
|
||||
while(RunLoops) {
|
||||
Timer::SetCurrentTime();
|
||||
eqs = nullptr;
|
||||
@ -487,7 +512,6 @@ int main(int argc, char** argv) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved.");
|
||||
}
|
||||
|
||||
loginserverlist.Process();
|
||||
console_list.Process();
|
||||
zoneserver_list.Process();
|
||||
launcher_list.Process();
|
||||
@ -498,17 +522,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (InterserverTimer.Check()) {
|
||||
InterserverTimer.Start();
|
||||
database.ping();
|
||||
|
||||
if (loginserverlist.AllConnected() == false) {
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(AutoInitLoginServer, 0, nullptr);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
database.ping();
|
||||
}
|
||||
|
||||
EQ::EventLoop::Get().Process();
|
||||
|
||||
@ -140,29 +140,6 @@ XS(XS_EQW_LSConnected)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EQW_LSReconnect); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQW_LSReconnect)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: EQW::LSReconnect(THIS)");
|
||||
{
|
||||
EQW * THIS;
|
||||
|
||||
if (sv_derived_from(ST(0), "EQW")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EQW *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EQW");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->LSReconnect();
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_EQW_CountZones); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EQW_CountZones)
|
||||
{
|
||||
@ -1010,7 +987,6 @@ XS(boot_EQW)
|
||||
newXSproto(strcpy(buf, "LockWorld"), XS_EQW_LockWorld, file, "$");
|
||||
newXSproto(strcpy(buf, "UnlockWorld"), XS_EQW_UnlockWorld, file, "$");
|
||||
newXSproto(strcpy(buf, "LSConnected"), XS_EQW_LSConnected, file, "$");
|
||||
newXSproto(strcpy(buf, "LSReconnect"), XS_EQW_LSReconnect, file, "$");
|
||||
newXSproto(strcpy(buf, "CountZones"), XS_EQW_CountZones, file, "$");
|
||||
newXSproto(strcpy(buf, "ListBootedZones"), XS_EQW_ListBootedZones, file, "$");
|
||||
newXSproto(strcpy(buf, "GetZoneDetails"), XS_EQW_GetZoneDetails, file, "$$");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user