mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 01:11: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)
|
FIND_PACKAGE(Sodium REQUIRED)
|
||||||
IF(SODIUM_FOUND)
|
IF(SODIUM_FOUND)
|
||||||
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
OPTION(EQEMU_ENABLE_SECURITY "Use Encryption For TCP Connections" ON)
|
||||||
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
IF(EQEMU_ENABLE_SECURITY)
|
||||||
SET(SERVER_LIBS ${SERVER_LIBS} ${SODIUM_LIBRARIES})
|
INCLUDE_DIRECTORIES(SYSTEM "${SODIUM_INCLUDE_DIRS}")
|
||||||
|
ADD_DEFINITIONS(-DENABLE_SECURITY)
|
||||||
|
SET(SERVER_LIBS ${SERVER_LIBS} ${SODIUM_LIBRARIES})
|
||||||
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(WIN32)
|
IF(WIN32)
|
||||||
@ -384,9 +387,9 @@ IF(EQEMU_BUILD_SERVER)
|
|||||||
ADD_SUBDIRECTORY(shared_memory)
|
ADD_SUBDIRECTORY(shared_memory)
|
||||||
ADD_SUBDIRECTORY(world)
|
ADD_SUBDIRECTORY(world)
|
||||||
ADD_SUBDIRECTORY(zone)
|
ADD_SUBDIRECTORY(zone)
|
||||||
ADD_SUBDIRECTORY(ucs)
|
#ADD_SUBDIRECTORY(ucs)
|
||||||
#ADD_SUBDIRECTORY(queryserv)
|
#ADD_SUBDIRECTORY(queryserv)
|
||||||
ADD_SUBDIRECTORY(eqlaunch)
|
#ADD_SUBDIRECTORY(eqlaunch)
|
||||||
ENDIF(EQEMU_BUILD_SERVER)
|
ENDIF(EQEMU_BUILD_SERVER)
|
||||||
IF(EQEMU_BUILD_LOGIN)
|
IF(EQEMU_BUILD_LOGIN)
|
||||||
ADD_SUBDIRECTORY(loginserver)
|
ADD_SUBDIRECTORY(loginserver)
|
||||||
|
|||||||
@ -41,6 +41,7 @@ public:
|
|||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
virtual void ReleaseFromUse() = 0;
|
virtual void ReleaseFromUse() = 0;
|
||||||
virtual void RemoveData() = 0;
|
virtual void RemoveData() = 0;
|
||||||
|
virtual std::string GetRemoteAddr() const = 0;
|
||||||
virtual uint32 GetRemoteIP() const = 0;
|
virtual uint32 GetRemoteIP() const = 0;
|
||||||
virtual uint16 GetRemotePort() const = 0;
|
virtual uint16 GetRemotePort() const = 0;
|
||||||
virtual bool CheckState(EQStreamState state) = 0;
|
virtual bool CheckState(EQStreamState state) = 0;
|
||||||
|
|||||||
@ -63,6 +63,10 @@ void EQStreamProxy::Close() {
|
|||||||
m_stream->Close();
|
m_stream->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string EQStreamProxy::GetRemoteAddr() const {
|
||||||
|
return(m_stream->GetRemoteAddr());
|
||||||
|
}
|
||||||
|
|
||||||
uint32 EQStreamProxy::GetRemoteIP() const {
|
uint32 EQStreamProxy::GetRemoteIP() const {
|
||||||
return(m_stream->GetRemoteIP());
|
return(m_stream->GetRemoteIP());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public:
|
|||||||
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
|
virtual void FastQueuePacket(EQApplicationPacket **p, bool ack_req=true);
|
||||||
virtual EQApplicationPacket *PopPacket();
|
virtual EQApplicationPacket *PopPacket();
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
|
virtual std::string GetRemoteAddr() const;
|
||||||
virtual uint32 GetRemoteIP() const;
|
virtual uint32 GetRemoteIP() const;
|
||||||
virtual uint16 GetRemotePort() const;
|
virtual uint16 GetRemotePort() const;
|
||||||
virtual void ReleaseFromUse();
|
virtual void ReleaseFromUse();
|
||||||
|
|||||||
@ -132,6 +132,11 @@ void EQ::Net::EQStream::Close() {
|
|||||||
m_connection->Close();
|
m_connection->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string EQ::Net::EQStream::GetRemoteAddr() const
|
||||||
|
{
|
||||||
|
return RemoteEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
uint32 EQ::Net::EQStream::GetRemoteIP() const {
|
uint32 EQ::Net::EQStream::GetRemoteIP() const {
|
||||||
return inet_addr(RemoteEndpoint().c_str());
|
return inet_addr(RemoteEndpoint().c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,6 +75,7 @@ namespace EQ
|
|||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual void ReleaseFromUse() { };
|
virtual void ReleaseFromUse() { };
|
||||||
virtual void RemoveData() { };
|
virtual void RemoveData() { };
|
||||||
|
virtual std::string GetRemoteAddr() const;
|
||||||
virtual uint32 GetRemoteIP() const;
|
virtual uint32 GetRemoteIP() const;
|
||||||
virtual uint16 GetRemotePort() const { return m_connection->RemotePort(); }
|
virtual uint16 GetRemotePort() const { return m_connection->RemotePort(); }
|
||||||
virtual bool CheckState(EQStreamState state);
|
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()
|
void EQ::Net::ServertalkClient::Connect()
|
||||||
{
|
{
|
||||||
if (m_addr.length() == 0 || m_port == 0 || m_connection || m_connecting) {
|
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 = connection;
|
||||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
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);
|
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_encrypted = false;
|
||||||
|
m_connection.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_connection->OnRead(std::bind(&EQ::Net::ServertalkClient::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
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];
|
length = *(uint32_t*)&m_buffer[current];
|
||||||
type = *(uint8_t*)&m_buffer[current + 4];
|
type = *(uint8_t*)&m_buffer[current + 4];
|
||||||
|
|
||||||
if (current + 5 + length < total) {
|
if (current + 5 + length > total) {
|
||||||
break;
|
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_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
||||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
||||||
|
memset(m_shared_key, 0, crypto_box_BEFORENMBYTES);
|
||||||
m_encrypted = false;
|
m_encrypted = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -156,6 +196,10 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
|||||||
m_encrypted = true;
|
m_encrypted = true;
|
||||||
|
|
||||||
SendHandshake();
|
SendHandshake();
|
||||||
|
|
||||||
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.OutF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
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 {
|
else {
|
||||||
SendHandshake();
|
SendHandshake();
|
||||||
|
|
||||||
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||||
m_connection->Disconnect();
|
m_connection->Disconnect();
|
||||||
|
|
||||||
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
try {
|
try {
|
||||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||||
|
|
||||||
if (enc) {
|
if (enc) {
|
||||||
Log.OutF(Logs::General, Logs::Error, "Server requested encryption but we do not support encryption.");
|
SendHandshake(true);
|
||||||
m_connection->Disconnect();
|
|
||||||
return;
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SendHandshake();
|
SendHandshake();
|
||||||
|
|
||||||
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
Log.OutF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||||
m_connection->Disconnect();
|
m_connection->Disconnect();
|
||||||
|
|
||||||
|
if (m_on_connect_cb) {
|
||||||
|
m_on_connect_cb(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
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;
|
EQ::Net::WritablePacket handshake;
|
||||||
#ifdef ENABLE_SECURITY
|
#ifdef ENABLE_SECURITY
|
||||||
@ -206,30 +317,41 @@ void EQ::Net::ServertalkClient::SendHandshake()
|
|||||||
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
||||||
handshake.PutData(crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
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 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;
|
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];
|
std::unique_ptr<unsigned char[]> signed_buffer(new unsigned char[cipher_length]);
|
||||||
memset(data_buffer, 0, data_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[0], m_identifier.c_str(), m_identifier.length());
|
||||||
memcpy(&data_buffer[1 + m_identifier.length()], m_credentials.c_str(), m_credentials.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])++;
|
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||||
|
|
||||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, signed_buffer, cipher_length);
|
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, &signed_buffer[0], cipher_length);
|
||||||
|
|
||||||
Log.OutF(Logs::General, Logs::Debug, "Sending {1} bytes handshake:\n{0}", handshake.ToString(), handshake.Length());
|
|
||||||
|
|
||||||
delete[] signed_buffer;
|
|
||||||
delete[] data_buffer;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
handshake.PutString(0, m_identifier);
|
handshake.PutString(0, m_identifier);
|
||||||
|
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||||
|
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
handshake.PutString(0, m_identifier);
|
handshake.PutString(0, m_identifier);
|
||||||
|
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||||
|
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||||
#endif
|
#endif
|
||||||
InternalSend(ServertalkClientHandshake, handshake);
|
|
||||||
|
if (downgrade) {
|
||||||
|
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
InternalSend(ServertalkClientHandshake, handshake);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
#include "../event/timer.h"
|
#include "../event/timer.h"
|
||||||
#include "servertalk_common.h"
|
#include "servertalk_common.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
#ifdef ENABLE_SECURITY
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace EQ
|
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(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials);
|
||||||
~ServertalkClient();
|
~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:
|
private:
|
||||||
void Connect();
|
void Connect();
|
||||||
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
|
||||||
@ -24,7 +33,8 @@ namespace EQ
|
|||||||
void ProcessReadBuffer();
|
void ProcessReadBuffer();
|
||||||
void ProcessHello(EQ::Net::Packet &p);
|
void ProcessHello(EQ::Net::Packet &p);
|
||||||
void ProcessMessage(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;
|
std::unique_ptr<EQ::Timer> m_timer;
|
||||||
|
|
||||||
@ -37,6 +47,8 @@ namespace EQ
|
|||||||
bool m_encrypted;
|
bool m_encrypted;
|
||||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||||
std::vector<char> m_buffer;
|
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
|
#ifdef ENABLE_SECURITY
|
||||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../servertalk.h"
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
namespace Net
|
namespace Net
|
||||||
@ -9,6 +11,7 @@ namespace EQ
|
|||||||
ServertalkClientHello = 1,
|
ServertalkClientHello = 1,
|
||||||
ServertalkServerHello,
|
ServertalkServerHello,
|
||||||
ServertalkClientHandshake,
|
ServertalkClientHandshake,
|
||||||
|
ServertalkClientDowngradeSecurityHandshake,
|
||||||
ServertalkMessage,
|
ServertalkMessage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,10 @@ void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
|||||||
{
|
{
|
||||||
m_encrypted = opts.encrypted;
|
m_encrypted = opts.encrypted;
|
||||||
m_credentials = opts.credentials;
|
m_credentials = opts.credentials;
|
||||||
|
m_allow_downgrade = opts.allow_downgrade;
|
||||||
m_server.reset(new EQ::Net::TCPServer());
|
m_server.reset(new EQ::Net::TCPServer());
|
||||||
m_server->Listen(opts.port, opts.ipv6, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
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;
|
int port;
|
||||||
bool ipv6;
|
bool ipv6;
|
||||||
bool encrypted;
|
bool encrypted;
|
||||||
|
bool allow_downgrade;
|
||||||
std::string credentials;
|
std::string credentials;
|
||||||
|
|
||||||
ServertalkServerOptions() {
|
ServertalkServerOptions() {
|
||||||
#ifdef ENABLE_SECURITY
|
#ifdef ENABLE_SECURITY
|
||||||
encrypted = true;
|
encrypted = true;
|
||||||
|
allow_downgrade = true;
|
||||||
|
#else
|
||||||
|
encrypted = false;
|
||||||
|
allow_downgrade = true;
|
||||||
#endif
|
#endif
|
||||||
ipv6 = false;
|
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_ident;
|
||||||
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
std::map<std::string, std::function<void(std::shared_ptr<ServertalkServerConnection>)>> m_on_disc;
|
||||||
bool m_encrypted;
|
bool m_encrypted;
|
||||||
|
bool m_allow_downgrade;
|
||||||
std::string m_credentials;
|
std::string m_credentials;
|
||||||
|
|
||||||
friend class ServertalkServerConnection;
|
friend class ServertalkServerConnection;
|
||||||
|
|||||||
@ -2,11 +2,12 @@
|
|||||||
#include "servertalk_server.h"
|
#include "servertalk_server.h"
|
||||||
#include "../eqemu_logsys.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_connection = c;
|
||||||
m_parent = parent;
|
m_parent = parent;
|
||||||
m_encrypted = encrypted;
|
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->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->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
|
||||||
m_connection->Start();
|
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)
|
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);
|
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];
|
length = *(uint32_t*)&m_buffer[current];
|
||||||
type = *(uint8_t*)&m_buffer[current + 4];
|
type = *(uint8_t*)&m_buffer[current + 4];
|
||||||
|
|
||||||
if (current + 5 + length < total) {
|
if (current + 5 + length > total) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +113,9 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
|||||||
case ServertalkClientHandshake:
|
case ServertalkClientHandshake:
|
||||||
ProcessHandshake(p);
|
ProcessHandshake(p);
|
||||||
break;
|
break;
|
||||||
|
case ServertalkClientDowngradeSecurityHandshake:
|
||||||
|
ProcessHandshake(p, true);
|
||||||
|
break;
|
||||||
case ServertalkMessage:
|
case ServertalkMessage:
|
||||||
ProcessMessage(p);
|
ProcessMessage(p);
|
||||||
break;
|
break;
|
||||||
@ -142,9 +183,15 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
|||||||
m_connection->Write((const char*)out.Data(), out.Length());
|
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
|
#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) {
|
if (m_encrypted) {
|
||||||
try {
|
try {
|
||||||
if (p.Length() > (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
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 cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
||||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
||||||
unsigned char *decrypted_text = new unsigned char[message_len];
|
std::unique_ptr<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))
|
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.");
|
Log.OutF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
|
||||||
m_connection->Disconnect();
|
m_connection->Disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_identifier = (const char*)decrypted_text;
|
m_identifier = (const char*)&decrypted_text[0];
|
||||||
std::string credentials = (const char*)decrypted_text + (m_identifier.length() + 1);
|
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
||||||
|
|
||||||
if (!m_parent->CheckCredentials(credentials)) {
|
if (!m_parent->CheckCredentials(credentials)) {
|
||||||
Log.OutF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
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);
|
m_parent->ConnectionIdentified(this);
|
||||||
|
|
||||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||||
delete[] decrypted_text;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
@ -184,13 +230,92 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
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 "servertalk_common.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#ifdef ENABLE_SECURITY
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
@ -14,28 +16,34 @@ namespace EQ
|
|||||||
class ServertalkServerConnection
|
class ServertalkServerConnection
|
||||||
{
|
{
|
||||||
public:
|
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();
|
~ServertalkServerConnection();
|
||||||
|
|
||||||
std::string GetIdentifier() const {
|
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
return m_identifier;
|
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:
|
private:
|
||||||
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
||||||
void ProcessReadBuffer();
|
void ProcessReadBuffer();
|
||||||
void OnDisconnect(TCPConnection* c);
|
void OnDisconnect(TCPConnection* c);
|
||||||
void SendHello();
|
void SendHello();
|
||||||
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
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);
|
void ProcessMessage(EQ::Net::Packet &p);
|
||||||
|
|
||||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||||
ServertalkServer *m_parent;
|
ServertalkServer *m_parent;
|
||||||
|
|
||||||
std::vector<char> m_buffer;
|
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;
|
std::string m_identifier;
|
||||||
|
|
||||||
bool m_encrypted;
|
bool m_encrypted;
|
||||||
|
bool m_allow_downgrade;
|
||||||
#ifdef ENABLE_SECURITY
|
#ifdef ENABLE_SECURITY
|
||||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
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
|
std::string EQ::Net::TCPConnection::RemoteIP() const
|
||||||
{
|
{
|
||||||
sockaddr_storage addr;
|
sockaddr_storage addr;
|
||||||
|
|||||||
@ -23,6 +23,9 @@ namespace EQ
|
|||||||
void Disconnect();
|
void Disconnect();
|
||||||
void Read(const char *data, size_t count);
|
void Read(const char *data, size_t count);
|
||||||
void Write(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;
|
std::string RemoteIP() const;
|
||||||
int RemotePort() const;
|
int RemotePort() const;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -530,7 +530,7 @@ struct ClientAuth_Struct {
|
|||||||
char key[30]; // the Key the client will present
|
char key[30]; // the Key the client will present
|
||||||
uint8 lsadmin; // login server admin level
|
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
|
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
|
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)
|
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)
|
TARGET_LINK_LIBRARIES(loginserver ${SERVER_LIBS})
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||||
|
|||||||
@ -197,7 +197,6 @@ int main()
|
|||||||
while (run_server) {
|
while (run_server) {
|
||||||
Timer::SetCurrentTime();
|
Timer::SetCurrentTime();
|
||||||
server.client_manager->Process();
|
server.client_manager->Process();
|
||||||
server.server_manager->Process();
|
|
||||||
EQ::EventLoop::Get().Process();
|
EQ::EventLoop::Get().Process();
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,87 +28,54 @@ extern bool run_server;
|
|||||||
|
|
||||||
ServerManager::ServerManager()
|
ServerManager::ServerManager()
|
||||||
{
|
{
|
||||||
char error_buffer[TCPConnection_ErrorBufferSize];
|
|
||||||
|
|
||||||
int listen_port = atoi(server.config->GetVariable("options", "listen_port").c_str());
|
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)) {
|
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||||
Log.Out(Logs::General, Logs::Login_Server, "ServerManager listening on port %u", listen_port);
|
EQ::Net::ServertalkServerOptions opts;
|
||||||
}
|
opts.port = listen_port;
|
||||||
else {
|
opts.ipv6 = false;
|
||||||
Log.Out(Logs::General, Logs::Error, "ServerManager fatal error opening port on %u: %s", listen_port, error_buffer);
|
server_connection->Listen(opts);
|
||||||
run_server = false;
|
|
||||||
}
|
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()
|
ServerManager::~ServerManager()
|
||||||
{
|
{
|
||||||
if (tcps) {
|
|
||||||
tcps->Close();
|
|
||||||
delete tcps;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerManager::Process()
|
WorldServer* ServerManager::GetServerByAddress(const std::string &addr, int port)
|
||||||
{
|
{
|
||||||
ProcessDisconnect();
|
auto iter = world_servers.begin();
|
||||||
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();
|
|
||||||
while (iter != world_servers.end()) {
|
while (iter != world_servers.end()) {
|
||||||
if ((*iter)->Process() == false) {
|
if ((*iter)->GetConnection()->Handle()->RemoteIP() == addr && (*iter)->GetConnection()->Handle()->RemotePort()) {
|
||||||
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());
|
return (*iter).get();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
@ -124,15 +91,14 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c)
|
|||||||
in.s_addr = c->GetConnection()->GetRemoteIP();
|
in.s_addr = c->GetConnection()->GetRemoteIP();
|
||||||
string client_ip = inet_ntoa(in);
|
string client_ip = inet_ntoa(in);
|
||||||
|
|
||||||
list<WorldServer*>::iterator iter = world_servers.begin();
|
auto iter = world_servers.begin();
|
||||||
while (iter != world_servers.end()) {
|
while (iter != world_servers.end()) {
|
||||||
if ((*iter)->IsAuthorized() == false) {
|
if ((*iter)->IsAuthorized() == false) {
|
||||||
++iter;
|
++iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
in.s_addr = (*iter)->GetConnection()->GetrIP();
|
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
|
||||||
string world_ip = inet_ntoa(in);
|
|
||||||
|
|
||||||
if (world_ip.compare(client_ip) == 0) {
|
if (world_ip.compare(client_ip) == 0) {
|
||||||
packet_size += (*iter)->GetLongName().size() + (*iter)->GetLocalIP().size() + 24;
|
packet_size += (*iter)->GetLongName().size() + (*iter)->GetLocalIP().size() + 24;
|
||||||
@ -171,8 +137,7 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
in.s_addr = (*iter)->GetConnection()->GetrIP();
|
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
|
||||||
string world_ip = inet_ntoa(in);
|
|
||||||
if (world_ip.compare(client_ip) == 0) {
|
if (world_ip.compare(client_ip) == 0) {
|
||||||
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
|
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
|
||||||
data_pointer += ((*iter)->GetLocalIP().size() + 1);
|
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)
|
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;
|
bool found = false;
|
||||||
while (iter != world_servers.end()) {
|
while (iter != world_servers.end()) {
|
||||||
if ((*iter)->GetRuntimeID() == server_id) {
|
if ((*iter)->GetRuntimeID() == server_id) {
|
||||||
ServerPacket *outapp = new ServerPacket(ServerOP_UsertoWorldReq, sizeof(UsertoWorldRequest_Struct));
|
EQ::Net::WritablePacket outapp;
|
||||||
UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct*)outapp->pBuffer;
|
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
|
||||||
|
UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct*)outapp.Data();
|
||||||
utwr->worldid = server_id;
|
utwr->worldid = server_id;
|
||||||
utwr->lsaccountid = client_account_id;
|
utwr->lsaccountid = client_account_id;
|
||||||
(*iter)->GetConnection()->SendPacket(outapp);
|
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp);
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
if (server.options.IsDumpInPacketsOn()) {
|
if (server.options.IsDumpInPacketsOn()) {
|
||||||
DumpPacket(outapp);
|
Log.OutF(Logs::General, Logs::Login_Server, "{0}", outapp.ToString());
|
||||||
}
|
}
|
||||||
delete outapp;
|
|
||||||
}
|
}
|
||||||
++iter;
|
++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)
|
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()) {
|
while (iter != world_servers.end()) {
|
||||||
if ((*iter) == ignore) {
|
if ((*iter).get() == ignore) {
|
||||||
++iter;
|
++iter;
|
||||||
continue;
|
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)
|
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()) {
|
while (iter != world_servers.end()) {
|
||||||
if ((*iter) == ignore) {
|
if ((*iter).get() == ignore) {
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) {
|
if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) {
|
||||||
EmuTCPConnection *c = (*iter)->GetConnection();
|
(*iter)->GetConnection()->Handle()->Disconnect();
|
||||||
if (c->Connected()) {
|
|
||||||
c->Disconnect();
|
|
||||||
}
|
|
||||||
c->Free();
|
|
||||||
delete (*iter);
|
|
||||||
iter = world_servers.erase(iter);
|
iter = world_servers.erase(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
#include "../common/emu_tcp_server.h"
|
#include "../common/emu_tcp_server.h"
|
||||||
#include "../common/servertalk.h"
|
#include "../common/servertalk.h"
|
||||||
#include "../common/packet_dump.h"
|
#include "../common/packet_dump.h"
|
||||||
|
#include "../common/net/servertalk_server.h"
|
||||||
#include "world_server.h"
|
#include "world_server.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
@ -43,11 +44,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
~ServerManager();
|
~ServerManager();
|
||||||
|
|
||||||
/**
|
|
||||||
* Does basic processing for all the servers.
|
|
||||||
*/
|
|
||||||
void Process();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a request to world to see if the client is banned or suspended.
|
* 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);
|
void DestroyServerByName(std::string l_name, std::string s_name, WorldServer *ignore = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* Processes all the disconnected connections in Process(), not used outside.
|
|
||||||
*/
|
|
||||||
void ProcessDisconnect();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a server(if exists) by ip address
|
* Retrieves a server(if exists) by ip address
|
||||||
* Useful utility for the reconnect process.
|
* Useful utility for the reconnect process.
|
||||||
*/
|
*/
|
||||||
WorldServer* GetServerByAddress(unsigned int address);
|
WorldServer* GetServerByAddress(const std::string &address, int port);
|
||||||
|
|
||||||
EmuTCPServer* tcps;
|
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||||
std::list<WorldServer*> world_servers;
|
std::list<std::unique_ptr<WorldServer>> world_servers;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
extern EQEmuLogSys Log;
|
extern EQEmuLogSys Log;
|
||||||
extern LoginServer server;
|
extern LoginServer server;
|
||||||
|
|
||||||
WorldServer::WorldServer(EmuTCPConnection *c)
|
WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> c)
|
||||||
{
|
{
|
||||||
connection = c;
|
connection = c;
|
||||||
zones_booted = 0;
|
zones_booted = 0;
|
||||||
@ -37,13 +37,16 @@ WorldServer::WorldServer(EmuTCPConnection *c)
|
|||||||
is_server_authorized = false;
|
is_server_authorized = false;
|
||||||
is_server_trusted = false;
|
is_server_trusted = false;
|
||||||
is_server_logged_in = 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()
|
WorldServer::~WorldServer()
|
||||||
{
|
{
|
||||||
if(connection) {
|
|
||||||
connection->Free();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::Reset()
|
void WorldServer::Reset()
|
||||||
@ -58,183 +61,162 @@ void WorldServer::Reset()
|
|||||||
is_server_logged_in = false;
|
is_server_logged_in = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldServer::Process()
|
void WorldServer::ProcessPacket(uint16_t opcode, const EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
ServerPacket *app = nullptr;
|
if(server.options.IsWorldTraceOn())
|
||||||
while(app = connection->PopPacket())
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
case ServerOP_LSStatus:
|
||||||
if(server.options.IsDumpInPacketsOn())
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
case ServerOP_UsertoWorldResp:
|
||||||
switch(app->opcode)
|
|
||||||
{
|
{
|
||||||
case ServerOP_NewLSInfo:
|
if(p.Length() < sizeof(UsertoWorldResponse_Struct))
|
||||||
{
|
{
|
||||||
if(app->size < sizeof(ServerNewLSInfo_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.");
|
||||||
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);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_LSStatus:
|
|
||||||
{
|
|
||||||
if(app->size < 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*)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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ServerOP_UsertoWorldResp:
|
//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(UsertoWorldResponse_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_UsertoWorldResp, "
|
per->Allowed = 1;
|
||||||
"but was too small. Discarded to avoid buffer overrun.");
|
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;
|
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())
|
if(server.options.IsTraceOn())
|
||||||
{
|
{
|
||||||
Log.Out(Logs::General, Logs::Netcode, "User-To-World Response received.");
|
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);
|
||||||
|
|
||||||
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, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str());
|
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 User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
delete app;
|
Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str());
|
||||||
app = nullptr;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
||||||
@ -308,8 +290,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
|||||||
if(strlen(i->remote_address) == 0)
|
if(strlen(i->remote_address) == 0)
|
||||||
{
|
{
|
||||||
in_addr in;
|
in_addr in;
|
||||||
in.s_addr = GetConnection()->GetrIP();
|
remote_ip = GetConnection()->Handle()->RemoteIP();
|
||||||
remote_ip = inet_ntoa(in);
|
|
||||||
Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was null, defaulting to stream address %s.", remote_ip.c_str());
|
Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was null, defaulting to stream address %s.", remote_ip.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -320,8 +301,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
in_addr in;
|
in_addr in;
|
||||||
in.s_addr = GetConnection()->GetrIP();
|
remote_ip = GetConnection()->Handle()->RemoteIP();
|
||||||
remote_ip = inet_ntoa(in);
|
|
||||||
Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was too long, defaulting to stream address %s.", remote_ip.c_str());
|
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;
|
server.db->UpdateWorldRegistration(GetRuntimeID(), long_name, GetConnection()->Handle()->RemoteIP());
|
||||||
in.s_addr = connection->GetrIP();
|
|
||||||
server.db->UpdateWorldRegistration(GetRuntimeID(), long_name, string(inet_ntoa(in)));
|
|
||||||
|
|
||||||
if(is_server_authorized)
|
if(is_server_authorized)
|
||||||
{
|
{
|
||||||
@ -508,7 +486,7 @@ void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s)
|
|||||||
server_status = s->status;
|
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));
|
ServerPacket *outapp = new ServerPacket(ServerOP_LSClientAuth, sizeof(ClientAuth_Struct));
|
||||||
ClientAuth_Struct* client_auth = (ClientAuth_Struct*)outapp->pBuffer;
|
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);
|
strncpy(client_auth->key, key.c_str(), 10);
|
||||||
client_auth->lsadmin = 0;
|
client_auth->lsadmin = 0;
|
||||||
client_auth->worldadmin = 0;
|
client_auth->worldadmin = 0;
|
||||||
client_auth->ip = ip;
|
strcpy(client_auth->ip, ip.c_str());
|
||||||
|
|
||||||
in_addr in;
|
string client_address(ip);
|
||||||
in.s_addr = ip; connection->GetrIP();
|
string world_address(connection->Handle()->RemoteIP());
|
||||||
string client_address(inet_ntoa(in));
|
|
||||||
in.s_addr = connection->GetrIP();
|
|
||||||
string world_address(inet_ntoa(in));
|
|
||||||
|
|
||||||
if (client_address.compare(world_address) == 0) {
|
if (client_address.compare(world_address) == 0) {
|
||||||
client_auth->local = 1;
|
client_auth->local = 1;
|
||||||
|
|||||||
@ -19,11 +19,11 @@
|
|||||||
#define EQEMU_WORLDSERVER_H
|
#define EQEMU_WORLDSERVER_H
|
||||||
|
|
||||||
#include "../common/global_define.h"
|
#include "../common/global_define.h"
|
||||||
#include "../common/emu_tcp_connection.h"
|
#include "../common/net/servertalk_server_connection.h"
|
||||||
#include "../common/emu_tcp_server.h"
|
|
||||||
#include "../common/servertalk.h"
|
#include "../common/servertalk.h"
|
||||||
#include "../common/packet_dump.h"
|
#include "../common/packet_dump.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* World server class, controls the connected server processing.
|
* World server class, controls the connected server processing.
|
||||||
@ -34,7 +34,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Constructor, sets our connection to c.
|
* Constructor, sets our connection to c.
|
||||||
*/
|
*/
|
||||||
WorldServer(EmuTCPConnection *c);
|
WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor, frees our connection if it exists.
|
* Destructor, frees our connection if it exists.
|
||||||
@ -47,20 +47,19 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does processing of all the connections for this world.
|
* Does processing of all the packets in for this world.
|
||||||
* Returns true except for a fatal error that requires disconnection.
|
|
||||||
*/
|
*/
|
||||||
bool Process();
|
void ProcessPacket(uint16_t opcode, const EQ::Net::Packet &p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accesses connection, it is intentional that this is not const (trust me).
|
* 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.
|
* 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.
|
* Gets the runtime id of this server.
|
||||||
@ -130,11 +129,11 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Informs world that there is a client incoming with the following data.
|
* 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:
|
private:
|
||||||
|
|
||||||
EmuTCPConnection *connection;
|
std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
|
||||||
unsigned int zones_booted;
|
unsigned int zones_booted;
|
||||||
unsigned int players_online;
|
unsigned int players_online;
|
||||||
int server_status;
|
int server_status;
|
||||||
|
|||||||
22
ucs/ucs.cpp
22
ucs/ucs.cpp
@ -34,7 +34,6 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include "../common/net/tcp_server.h"
|
#include "../common/net/tcp_server.h"
|
||||||
#include "../common/net/servertalk_server.h"
|
|
||||||
#include "../common/net/servertalk_client_connection.h"
|
#include "../common/net/servertalk_client_connection.h"
|
||||||
|
|
||||||
ChatChannelList *ChannelList;
|
ChatChannelList *ChannelList;
|
||||||
@ -146,21 +145,14 @@ int main() {
|
|||||||
|
|
||||||
worldserver->Connect();
|
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");
|
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) {
|
while(RunLoops) {
|
||||||
|
|
||||||
|
|||||||
@ -467,7 +467,6 @@ void Console::ProcessCommand(const char* command) {
|
|||||||
SendMessage(1, " IPLookup [name]");
|
SendMessage(1, " IPLookup [name]");
|
||||||
}
|
}
|
||||||
if (admin >= 100) {
|
if (admin >= 100) {
|
||||||
SendMessage(1, " LSReconnect");
|
|
||||||
SendMessage(1, " signalcharbyname charname ID");
|
SendMessage(1, " signalcharbyname charname ID");
|
||||||
SendMessage(1, " reloadworld");
|
SendMessage(1, " reloadworld");
|
||||||
}
|
}
|
||||||
@ -794,17 +793,6 @@ void Console::ProcessCommand(const char* command) {
|
|||||||
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= 201) {
|
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= 201) {
|
||||||
client_list.SendCLEList(admin, 0, this, sep.argplus[1]);
|
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) {
|
else if (strcasecmp(sep.arg[0], "zonelock") == 0 && admin >= consoleZoneStatus) {
|
||||||
if (strcasecmp(sep.arg[1], "list") == 0) {
|
if (strcasecmp(sep.arg[1], "list") == 0) {
|
||||||
zoneserver_list.ListLockedZones(0, this);
|
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);
|
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 EQW::CreateGuild(const char* name, uint32 leader_char_id) {
|
||||||
uint32 id = guild_mgr.CreateGuild(name, leader_char_id);
|
uint32 id = guild_mgr.CreateGuild(name, leader_char_id);
|
||||||
if(id != GUILD_NONE)
|
if(id != GUILD_NONE)
|
||||||
|
|||||||
@ -42,7 +42,6 @@ public:
|
|||||||
void UnlockWorld();
|
void UnlockWorld();
|
||||||
|
|
||||||
bool LSConnected();
|
bool LSConnected();
|
||||||
void LSReconnect();
|
|
||||||
|
|
||||||
int CountZones();
|
int CountZones();
|
||||||
std::vector<std::string> ListBootedZones(); //returns an array of zone_refs (opaque)
|
std::vector<std::string> ListBootedZones(); //returns an array of zone_refs (opaque)
|
||||||
|
|||||||
@ -22,35 +22,6 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../common/version.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 "../common/servertalk.h"
|
||||||
#include "login_server.h"
|
#include "login_server.h"
|
||||||
#include "login_server_list.h"
|
#include "login_server_list.h"
|
||||||
@ -70,145 +41,107 @@ extern uint32 numplayers;
|
|||||||
extern volatile bool RunLoops;
|
extern volatile bool RunLoops;
|
||||||
|
|
||||||
LoginServer::LoginServer(const char* iAddress, uint16 iPort, const char* Account, const char* Password)
|
LoginServer::LoginServer(const char* iAddress, uint16 iPort, const char* Account, const char* Password)
|
||||||
: statusupdate_timer(LoginServer_StatusUpdateInterval)
|
|
||||||
{
|
{
|
||||||
strn0cpy(LoginServerAddress,iAddress,256);
|
strn0cpy(LoginServerAddress,iAddress,256);
|
||||||
LoginServerPort = iPort;
|
LoginServerPort = iPort;
|
||||||
strn0cpy(LoginAccount,Account,31);
|
strn0cpy(LoginAccount,Account,31);
|
||||||
strn0cpy(LoginPassword,Password,31);
|
strn0cpy(LoginPassword,Password,31);
|
||||||
CanAccountUpdate = false;
|
CanAccountUpdate = false;
|
||||||
tcpc = new EmuTCPConnection(true);
|
Connect();
|
||||||
tcpc->SetPacketMode(EmuTCPConnection::packetModeLogin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoginServer::~LoginServer() {
|
LoginServer::~LoginServer() {
|
||||||
delete tcpc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoginServer::Process() {
|
void LoginServer::ProcessPacket(uint16_t opcode, EQ::Net::Packet &p) {
|
||||||
const WorldConfig *Config=WorldConfig::get();
|
const WorldConfig *Config=WorldConfig::get();
|
||||||
|
|
||||||
if (statusupdate_timer.Check()) {
|
|
||||||
this->SendStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/************ Get all packets from packet manager out queue and process them ************/
|
/************ Get all packets from packet manager out queue and process them ************/
|
||||||
ServerPacket *pack = 0;
|
Log.Out(Logs::Detail, Logs::World_Server,"Recevied ServerPacket from LS OpCode 0x04x", opcode);
|
||||||
while((pack = tcpc->PopPacket()))
|
|
||||||
{
|
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode);
|
|
||||||
|
|
||||||
switch(pack->opcode) {
|
switch(opcode) {
|
||||||
case 0:
|
case ServerOP_UsertoWorldReq: {
|
||||||
break;
|
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*)p.Data();
|
||||||
case ServerOP_KeepAlive: {
|
uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
|
||||||
// ignore this
|
int16 status = database.CheckStatus(id);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_UsertoWorldReq: {
|
|
||||||
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer;
|
|
||||||
uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
|
|
||||||
int16 status = database.CheckStatus(id);
|
|
||||||
|
|
||||||
auto outpack = new ServerPacket;
|
auto outpack = new ServerPacket;
|
||||||
outpack->opcode = ServerOP_UsertoWorldResp;
|
outpack->opcode = ServerOP_UsertoWorldResp;
|
||||||
outpack->size = sizeof(UsertoWorldResponse_Struct);
|
outpack->size = sizeof(UsertoWorldResponse_Struct);
|
||||||
outpack->pBuffer = new uchar[outpack->size];
|
outpack->pBuffer = new uchar[outpack->size];
|
||||||
memset(outpack->pBuffer, 0, outpack->size);
|
memset(outpack->pBuffer, 0, outpack->size);
|
||||||
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
|
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
|
||||||
utwrs->lsaccountid = utwr->lsaccountid;
|
utwrs->lsaccountid = utwr->lsaccountid;
|
||||||
utwrs->ToID = utwr->FromID;
|
utwrs->ToID = utwr->FromID;
|
||||||
|
|
||||||
if(Config->Locked == true)
|
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:
|
|
||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::World_Server, "Unknown LSOpCode: 0x%04x size=%d",(int)pack->opcode,pack->size);
|
if((status == 0 || status < 100) && (status != -2 || status != -1))
|
||||||
DumpPacket(pack->pBuffer, pack->size);
|
utwrs->response = 0;
|
||||||
break;
|
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() {
|
client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, inet_addr(slsca->ip), slsca->local);
|
||||||
if(Connected() == false) {
|
break;
|
||||||
if(ConnectReady()) {
|
}
|
||||||
Log.Out(Logs::Detail, Logs::World_Server, "Connecting to login server: %s:%d",LoginServerAddress,LoginServerPort);
|
case ServerOP_LSFatalError: {
|
||||||
Connect();
|
Log.Out(Logs::Detail, Logs::World_Server, "Login server responded with FatalError.");
|
||||||
} else {
|
if (p.Length() > 1) {
|
||||||
Log.Out(Logs::Detail, Logs::World_Server, "Not connected but not ready to connect, this is bad: %s:%d",
|
Log.Out(Logs::Detail, Logs::World_Server, " %s", (const char*)p.Data());
|
||||||
LoginServerAddress,LoginServerPort);
|
}
|
||||||
|
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() {
|
bool LoginServer::Connect() {
|
||||||
@ -236,20 +169,32 @@ bool LoginServer::Connect() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) {
|
client.reset(new EQ::Net::ServertalkClient(LoginServerAddress, LoginServerPort, false, "World", ""));
|
||||||
Log.Out(Logs::Detail, Logs::World_Server, "Connected to Loginserver: %s:%d",LoginServerAddress,LoginServerPort);
|
client->OnConnect([this](EQ::Net::ServertalkClient *client) {
|
||||||
if (minilogin)
|
if (client) {
|
||||||
SendInfo();
|
Log.Out(Logs::Detail, Logs::World_Server, "Connected to Loginserver: %s:%d", LoginServerAddress, LoginServerPort);
|
||||||
else
|
if (minilogin)
|
||||||
SendNewInfo();
|
SendInfo();
|
||||||
SendStatus();
|
else
|
||||||
zoneserver_list.SendLSZones();
|
SendNewInfo();
|
||||||
return true;
|
SendStatus();
|
||||||
}
|
zoneserver_list.SendLSZones();
|
||||||
else {
|
|
||||||
Log.Out(Logs::Detail, Logs::World_Server, "Could not connect to login server: %s:%d %s",LoginServerAddress,LoginServerPort,errbuf);
|
statusupdate_timer.reset(new EQ::Timer(LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) {
|
||||||
return false;
|
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() {
|
void LoginServer::SendInfo() {
|
||||||
const WorldConfig *Config=WorldConfig::get();
|
const WorldConfig *Config=WorldConfig::get();
|
||||||
@ -291,15 +236,13 @@ void LoginServer::SendNewInfo() {
|
|||||||
if (Config->LocalAddress.length())
|
if (Config->LocalAddress.length())
|
||||||
strcpy(lsi->local_address, Config->LocalAddress.c_str());
|
strcpy(lsi->local_address, Config->LocalAddress.c_str());
|
||||||
else {
|
else {
|
||||||
tcpc->GetSockName(lsi->local_address,&port);
|
WorldConfig::SetLocalAddress(client->Handle()->LocalIP());
|
||||||
WorldConfig::SetLocalAddress(lsi->local_address);
|
|
||||||
}
|
}
|
||||||
SendPacket(pack);
|
SendPacket(pack);
|
||||||
delete pack;
|
delete pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoginServer::SendStatus() {
|
void LoginServer::SendStatus() {
|
||||||
statusupdate_timer.Start();
|
|
||||||
auto pack = new ServerPacket;
|
auto pack = new ServerPacket;
|
||||||
pack->opcode = ServerOP_LSStatus;
|
pack->opcode = ServerOP_LSStatus;
|
||||||
pack->size = sizeof(ServerLSStatus_Struct);
|
pack->size = sizeof(ServerLSStatus_Struct);
|
||||||
|
|||||||
@ -24,39 +24,37 @@
|
|||||||
#include "../common/queue.h"
|
#include "../common/queue.h"
|
||||||
#include "../common/eq_packet_structs.h"
|
#include "../common/eq_packet_structs.h"
|
||||||
#include "../common/mutex.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{
|
class LoginServer{
|
||||||
public:
|
public:
|
||||||
LoginServer(const char*, uint16, const char*, const char*);
|
LoginServer(const char*, uint16, const char*, const char*);
|
||||||
~LoginServer();
|
~LoginServer();
|
||||||
|
|
||||||
bool InitLoginServer();
|
void ProcessPacket(uint16_t opcode, EQ::Net::Packet &p);
|
||||||
|
|
||||||
bool Process();
|
|
||||||
bool Connect();
|
bool Connect();
|
||||||
|
|
||||||
void SendInfo();
|
void SendInfo();
|
||||||
void SendNewInfo();
|
void SendNewInfo();
|
||||||
void SendStatus();
|
void SendStatus();
|
||||||
|
|
||||||
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
|
void SendPacket(ServerPacket* pack) { client->SendPacket(pack); }
|
||||||
void SendAccountUpdate(ServerPacket* pack);
|
void SendAccountUpdate(ServerPacket* pack);
|
||||||
bool ConnectReady() { return tcpc->ConnectReady(); }
|
bool Connected() { return client->Connected(); }
|
||||||
bool Connected() { return tcpc->Connected(); }
|
|
||||||
bool MiniLogin() { return minilogin; }
|
bool MiniLogin() { return minilogin; }
|
||||||
bool CanUpdate() { return CanAccountUpdate; }
|
bool CanUpdate() { return CanAccountUpdate; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool minilogin;
|
bool minilogin;
|
||||||
EmuTCPConnection* tcpc;
|
std::unique_ptr<EQ::Net::ServertalkClient> client;
|
||||||
|
std::unique_ptr<EQ::Timer> statusupdate_timer;
|
||||||
char LoginServerAddress[256];
|
char LoginServerAddress[256];
|
||||||
uint32 LoginServerIP;
|
uint32 LoginServerIP;
|
||||||
uint16 LoginServerPort;
|
uint16 LoginServerPort;
|
||||||
char LoginAccount[32];
|
char LoginAccount[32];
|
||||||
char LoginPassword[32];
|
char LoginPassword[32];
|
||||||
bool CanAccountUpdate;
|
bool CanAccountUpdate;
|
||||||
|
|
||||||
Timer statusupdate_timer;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -55,38 +55,6 @@ void LoginServerList::Add(const char* iAddress, uint16 iPort, const char* Accoun
|
|||||||
list.Insert(loginserver);
|
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() {
|
bool LoginServerList::SendInfo() {
|
||||||
LinkedListIterator<LoginServer*> iterator(list);
|
LinkedListIterator<LoginServer*> iterator(list);
|
||||||
|
|
||||||
|
|||||||
@ -9,12 +9,6 @@
|
|||||||
#include "../common/mutex.h"
|
#include "../common/mutex.h"
|
||||||
#include "../common/emu_tcp_connection.h"
|
#include "../common/emu_tcp_connection.h"
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
void AutoInitLoginServer(void *tmp);
|
|
||||||
#else
|
|
||||||
void *AutoInitLoginServer(void *tmp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class LoginServer;
|
class LoginServer;
|
||||||
|
|
||||||
class LoginServerList{
|
class LoginServerList{
|
||||||
@ -23,9 +17,6 @@ public:
|
|||||||
~LoginServerList();
|
~LoginServerList();
|
||||||
|
|
||||||
void Add(const char*, uint16, const char*, const char*);
|
void Add(const char*, uint16, const char*, const char*);
|
||||||
void InitLoginServer();
|
|
||||||
|
|
||||||
bool Process();
|
|
||||||
|
|
||||||
bool SendInfo();
|
bool SendInfo();
|
||||||
bool SendNewInfo();
|
bool SendNewInfo();
|
||||||
|
|||||||
@ -86,6 +86,9 @@
|
|||||||
#include "ucs.h"
|
#include "ucs.h"
|
||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
|
|
||||||
|
#include "../common/net/tcp_server.h"
|
||||||
|
#include "../common/net/servertalk_server.h"
|
||||||
|
|
||||||
EmuTCPServer tcps;
|
EmuTCPServer tcps;
|
||||||
ClientList client_list;
|
ClientList client_list;
|
||||||
GroupLFPList LFPGroupList;
|
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()));
|
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) {
|
while(RunLoops) {
|
||||||
Timer::SetCurrentTime();
|
Timer::SetCurrentTime();
|
||||||
eqs = nullptr;
|
eqs = nullptr;
|
||||||
@ -487,7 +512,6 @@ int main(int argc, char** argv) {
|
|||||||
Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved.");
|
Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved.");
|
||||||
}
|
}
|
||||||
|
|
||||||
loginserverlist.Process();
|
|
||||||
console_list.Process();
|
console_list.Process();
|
||||||
zoneserver_list.Process();
|
zoneserver_list.Process();
|
||||||
launcher_list.Process();
|
launcher_list.Process();
|
||||||
@ -499,16 +523,6 @@ int main(int argc, char** argv) {
|
|||||||
if (InterserverTimer.Check()) {
|
if (InterserverTimer.Check()) {
|
||||||
InterserverTimer.Start();
|
InterserverTimer.Start();
|
||||||
database.ping();
|
database.ping();
|
||||||
|
|
||||||
if (loginserverlist.AllConnected() == false) {
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
_beginthread(AutoInitLoginServer, 0, nullptr);
|
|
||||||
#else
|
|
||||||
pthread_t thread;
|
|
||||||
pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::EventLoop::Get().Process();
|
EQ::EventLoop::Get().Process();
|
||||||
|
|||||||
@ -140,29 +140,6 @@ XS(XS_EQW_LSConnected)
|
|||||||
XSRETURN(1);
|
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); /* prototype to pass -Wmissing-prototypes */
|
||||||
XS(XS_EQW_CountZones)
|
XS(XS_EQW_CountZones)
|
||||||
{
|
{
|
||||||
@ -1010,7 +987,6 @@ XS(boot_EQW)
|
|||||||
newXSproto(strcpy(buf, "LockWorld"), XS_EQW_LockWorld, file, "$");
|
newXSproto(strcpy(buf, "LockWorld"), XS_EQW_LockWorld, file, "$");
|
||||||
newXSproto(strcpy(buf, "UnlockWorld"), XS_EQW_UnlockWorld, file, "$");
|
newXSproto(strcpy(buf, "UnlockWorld"), XS_EQW_UnlockWorld, file, "$");
|
||||||
newXSproto(strcpy(buf, "LSConnected"), XS_EQW_LSConnected, 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, "CountZones"), XS_EQW_CountZones, file, "$");
|
||||||
newXSproto(strcpy(buf, "ListBootedZones"), XS_EQW_ListBootedZones, file, "$");
|
newXSproto(strcpy(buf, "ListBootedZones"), XS_EQW_ListBootedZones, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetZoneDetails"), XS_EQW_GetZoneDetails, file, "$$");
|
newXSproto(strcpy(buf, "GetZoneDetails"), XS_EQW_GetZoneDetails, file, "$$");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user