World <-> Login connection reworked

This commit is contained in:
KimLS 2016-10-28 19:02:03 -07:00
parent fab8765c2f
commit 0b8b41d91f
32 changed files with 729 additions and 701 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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());
}

View File

@ -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();

View File

@ -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());
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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];

View File

@ -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,
};
}

View File

@ -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));
});
}

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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];

View File

@ -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;

View File

@ -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:

View File

@ -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
};

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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, "$$");