This commit is contained in:
Joon Park 2020-03-09 01:23:06 -04:00
parent 64b2793519
commit 8765bd3e29
18 changed files with 835 additions and 698 deletions

View File

@ -3,7 +3,6 @@
#include "core/shared.h"
#include "core/network/connection.h"
#include "core/network/xg_session.h"
#include "core/network/timer.h"
namespace server
@ -15,26 +14,28 @@ namespace server
address(new_socket.remote_endpoint().address()),
port(new_socket.remote_endpoint().port()),
marked_for_delete(false),
parent(nullptr),
//parent(nullptr),
socket(std::move(new_socket)),
rbuffer(4096),
wbuffer(4096),
rqueue(this),
wqueue(this)
wbuffer(4096)
{
}
void tcp_connection::shutdown_and_close()
void tcp_connection::mark_for_delete()
{
asio::error_code error_code;
socket.shutdown(asio::ip::tcp::socket::shutdown_both, error_code);
/*
if (error_code)
printf("network: tcp_connection::close: %s errored when shutting down socket: %i (%s)", address.to_string().c_str(),
printf("network: tcp_connection::close: %s errored when shutting down socket: %i (%s)\n", address.to_string().c_str(),
error_code.value(), error_code.message().c_str());
*/
socket.close();
wsignal->fire(signal_code::shutdown);
marked_for_delete = true;
}
@ -55,18 +56,22 @@ namespace server
uint32 id = connection->id;
if (connection->marked_for_delete)
{
/*
if (connection->parent)
if (!connection->wqueue && !connection->rqueue)
{
connection->parent->remove_connection(connection);
delete connection;
connection = nullptr;
this->conneciton_count--;
connections_purged++;
}
delete connection;
connection = nullptr;
this->conneciton_count--;
connections_purged++;
*/
//*
//if (connection->parent)
//{
// connection->parent->remove_connection(connection);
//}
//*/
}
}
}

View File

@ -4,219 +4,13 @@
#include "asio/read.hpp"
#include "core/network/timer.h"
#include "core/network/packet_queue.h"
#include "core/network/byte_buffer.h"
namespace server
{
namespace core
{
struct packet
{
struct tcp_connection* connection;
uint8* data;
uint64 length;
};
static const uint32 max_frame_count = 2;
struct packet_queue
{
struct frame_data
{
std::vector<uint8> data;
uint64 wpos;
uint64 wsize;
std::vector<packet> packets;
uint64 rpos;
uint64 packet_count;
frame_data() : wpos(0), rpos(0), wsize(0), packet_count(0)
{
data.resize(4096);
packets.resize(128);
}
};
frame_data frame[max_frame_count];
struct tcp_connection* connection;
std::atomic<uint32> state;
uint32 read_state;
uint32 write_state;
enum packet_queue_state_bit
{
active_frame = 0,
write_busy = 1,
dirty_flag = 2,
total_bits
};
packet_queue(struct tcp_connection* connection) :
connection(connection), state(0), read_state(0), write_state(0), frame{}
{}
bool enqueue(uint8* packet_data, uint64 packet_size)
{
this->begin_write();
bool result = false;
uint32 write_idx = write_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[write_idx];
uint64 buffer_space = f.data.size() - f.wpos;
uint64 packet_slots = f.packets.size() - f.packet_count;
if (buffer_space >= packet_size && packet_slots >= 1)
{
memcpy(&f.data[f.wpos], packet_data, packet_size);
f.packets[f.packet_count] = { connection, &f.data[f.wpos], packet_size };
f.wpos += packet_size;
f.packet_count++;
result = true;
}
this->end_write();
return result;
}
packet* dequeue()
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
if (has_next())
{
return &f.packets[f.rpos++];
}
return nullptr;
}
bool requeue(packet* packet)
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
f.rpos--;
return &f.packets[f.rpos] == packet;
}
bool has_next()
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
return f.rpos < f.packet_count;
}
void begin_write()
{
write_state = state.fetch_add(0x1 << packet_queue_state_bit::write_busy, std::memory_order_relaxed);
assert((write_state & (0x1 << packet_queue_state_bit::write_busy)) == 0);
state.fetch_or(0x1 << packet_queue_state_bit::dirty_flag, std::memory_order_relaxed);
}
void end_write()
{
write_state = state.fetch_sub(0x1 << packet_queue_state_bit::write_busy, std::memory_order_relaxed);
assert((write_state & (0x1 << packet_queue_state_bit::write_busy)) != 0);
}
bool begin_read()
{
if (state.load() & (0x1 << packet_queue_state_bit::dirty_flag))
{
uint32 write_state = read_state ^ (0x1 << packet_queue_state_bit::active_frame);
uint32 test_state;
do
{
test_state = read_state | (0x1 << packet_queue_state_bit::dirty_flag);
} while (!state.compare_exchange_weak(test_state, write_state));
return true;
}
return false;
}
void end_read()
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
f.rpos = 0;
f.wpos = 0;
f.wsize = 0;
f.packet_count = 0;
memset(&f.data[0], 0, sizeof(uint8) * f.data.size());
memset(&f.packets[0], 0, sizeof(packet) * f.packets.size());
read_state ^= (0x1 << packet_queue_state_bit::active_frame);
}
};
struct byte_buffer
{
std::vector<uint8> buffer;
uint64 capacity;
uint64 rpos;
uint64 rend;
uint64 wpos;
byte_buffer(uint64 capacity) :
buffer(capacity),
capacity(capacity),
rpos(0),
rend(0),
wpos(0)
{}
uint64 size()
{
return wpos;
}
uint64 free_space()
{
return capacity - wpos;
}
uint8* data()
{
return buffer.data();
}
uint8* write(void* source, uint64 size)
{
uint8* wptr = buffer.data() + wpos;
if (this->free_space() > size)
{
memcpy(wptr, source, size);
rpos = wpos;
rend += size;
wpos = rend;
return wptr;
}
return nullptr;
}
void erase(uint64 num_erase)
{
if (wpos >= num_erase)
{
memmove(buffer.data(), buffer.data() + wpos, wpos - num_erase);
wpos -= num_erase;
}
}
};
struct tcp_connection
{
int id;
@ -228,29 +22,14 @@ namespace server
byte_buffer rbuffer;
byte_buffer wbuffer;
struct xg_session* parent;
packet_queue rqueue;
packet_queue wqueue;
async_signal wsignal;
packet_queue* rqueue;
packet_queue* wqueue;
async_signal* wsignal;
tcp_connection(asio::ip::tcp::socket&& new_socket);
void shutdown_and_close();
bool enqueue_response(uint8* packet_data, uint32 packet_size)
{
if (!wqueue.enqueue(packet_data, packet_size))
{
printf("enqueue failed.\n");
return false;
}
wsignal.fire();
return true;
}
void mark_for_delete();
//template<typename buffer_t>
//auto async_recv(tcp_connection& connection, buffer_t buffer);
@ -297,7 +76,7 @@ namespace server
{
while (socket.is_open())
{
packet_queue& packets = wqueue;
packet_queue& packets = *wqueue;
if (packets.begin_read())
{
@ -307,12 +86,13 @@ namespace server
if (wbuffer.free_space() < packet->length * 2)
{
assert(false);
packets.requeue(packet);
break;
}
uint8* packet_data = wbuffer.write(packet->data, packet->length);
wbuffer.rpos = packet_data - wbuffer.data();
wbuffer.rend = wbuffer.rpos + packet->length;
//wbuffer.rpos = packet_data - wbuffer.data();
//wbuffer.rend = wbuffer.rpos + packet->length;
//crossgate::xg_dispatch_packet(std::move(*packet));
send_handler(wbuffer);
@ -320,7 +100,7 @@ namespace server
//std::string packet_str((char*)packet->data, packet->length);
//packet_str = crossgate::decrypt_message(packet_str);
//printf("new packet:%s\n", packet_str.c_str());
//printf("outgoing packet:%s\n", wbuffer.data());
//xg_dispatch_packet()
}
packets.end_read();
@ -334,19 +114,107 @@ namespace server
}
else
{
co_await wsignal;
co_await *wsignal;
if (wsignal->val == signal_code::shutdown)
{
break;
}
}
}
}
catch (const std::exception& exception)
{
//shutdown_and_close();
//printf("connection %d marked for delete.\n", id);
printf("exception: %s", exception.what());
}
catch (signal_code signal)
{
if (signal == signal_code::shutdown)
{
printf("async_send_loop exited.\n");
}
}
wqueue = nullptr;
mark_for_delete();
}
template<typename lambda>
std::future<void> tcp_connection::async_recv_loop(lambda& receive_handler)
{
try
{
uint32 bytes_deferred = 0;
while (socket.is_open())
{
uint8* rdata = rbuffer.data();
uint32 bytes_read = co_await async_recv(*this, asio::buffer(rdata + bytes_deferred, 1024 - bytes_deferred));
if (bytes_read == -1)
{
break;
}
uint32 total_bytes = bytes_deferred + bytes_read;
uint32 begin = 0;
uint32 end = 0;
uint32 index = 0;
while (index != total_bytes)
{
if (rdata[index] == '\n')
{
rdata[index] = '\0';
end = index;
rbuffer.rpos = begin;
rbuffer.rend = end;
if (rbuffer.data()[rbuffer.rpos] == '\0')
{
printf("empty string\n");
}
else
{
// receive assumes decrypted packet is <= encrypted packet.
bool success = receive_handler(rbuffer);
if (!success)
{
printf("bad packet, packet dropped.\n");
}
if (!rqueue->enqueue(rbuffer.data() + rbuffer.rpos, rbuffer.rend - rbuffer.rpos))
{
printf("packet_queue full, packet dropped.\n");
}
}
begin = end + 1;
}
index++;
}
bytes_deferred = total_bytes - begin;
memcpy(rdata, rdata + begin, bytes_deferred);
memset(rdata + bytes_deferred, 0, total_bytes - bytes_deferred);
}
}
catch (const std::exception& exception)
{
//printf("connection %d marked for delete.\n", id);
printf("exception: %s", exception.what());
}
rqueue = nullptr;
mark_for_delete();
}
template<typename connection_t, typename buffer_t>
struct async_send_frame
{
@ -385,73 +253,6 @@ namespace server
}
};
template<typename lambda>
std::future<void> tcp_connection::async_recv_loop(lambda& receive_handler)
{
try
{
while (socket.is_open())
{
uint8* rdata = rbuffer.data();
uint32 bytes_read = co_await async_recv(*this, asio::buffer(rdata, 1024));
uint32 begin = 0;
uint32 end = 0;
uint32 index = 0;
while (index != bytes_read)
{
if (rdata[index] == '\n')
{
rdata[index] = '\0';
end = index;
uint8* packet_data = rdata + begin;
uint32 packet_size = end - begin;
rbuffer.rpos = begin;
rbuffer.rend = end;
if (*(rdata + begin) == '\0')
{
printf("empty string\n");
continue;
}
else
{
// receive assumes decrypted packet is <= encrypted packet.
receive_handler(rbuffer);
if (!rqueue.enqueue(rbuffer.data() + rbuffer.rpos, rbuffer.rend - rbuffer.rpos))
{
printf("enqueue failed.\n");
}
}
begin = index + 1;
}
index++;
}
memset(rdata, 0, bytes_read);
}
}
catch (const std::exception& /*exception*/)
{
shutdown_and_close();
//printf("connection %d marked for delete.\n", id);
//printf("exception: %s", exception.what());
}
}
template<typename buffer_t>
auto async_send(tcp_connection& connection, buffer_t buffer)
{
return async_send_frame<tcp_connection, buffer_t>(connection, std::forward<buffer_t>(buffer));
}
template<typename connection_t, typename buffer_t>
struct async_recv_frame
{
@ -473,7 +274,11 @@ namespace server
connection.socket.async_receive(buffer, [this, coro](auto error_code, size_t bytes_read)
{
this->error_code = error_code;
printf("%zd bytes read from connection %d\n", bytes_read, connection.id);
if (bytes_read)
{
printf("%zd bytes read from connection %d\n", bytes_read, connection.id);
}
return_value = (uint32)bytes_read;
coro.resume();
});
@ -483,13 +288,20 @@ namespace server
{
if (error_code)
{
throw asio::system_error(error_code);
return_value = -1;
//throw asio::system_error(error_code);
}
return return_value;
}
};
template<typename buffer_t>
auto async_send(tcp_connection& connection, buffer_t buffer)
{
return async_send_frame<tcp_connection, buffer_t>(connection, std::forward<buffer_t>(buffer));
}
template<typename buffer_t>
auto async_recv(tcp_connection& connection, buffer_t buffer)
{

View File

@ -0,0 +1,155 @@
#pragma once
namespace server
{
namespace core
{
struct packet
{
uint8* data;
uint64 length;
};
struct packet_queue
{
static const uint32 max_frame_count = 2;
struct frame_data
{
std::vector<uint8> data;
uint64 wpos;
uint64 wsize;
std::vector<packet> packets;
uint64 rpos;
uint64 packet_count;
frame_data() : wpos(0), rpos(0), wsize(0), packet_count(0)
{
data.resize(4096);
packets.resize(128);
}
};
frame_data frame[max_frame_count];
std::atomic<uint32> state;
uint32 read_state;
uint32 write_state;
enum packet_queue_state_bit
{
active_frame = 0,
write_busy = 1,
dirty_flag = 2,
total_bits
};
packet_queue() : state(0), read_state(0), write_state(0), frame{}
{}
bool enqueue(uint8* packet_data, uint64 packet_size)
{
this->begin_write();
bool result = false;
uint32 write_idx = write_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[write_idx];
uint64 buffer_space = f.data.size() - f.wpos;
uint64 packet_slots = f.packets.size() - f.packet_count;
if (buffer_space >= packet_size && packet_slots >= 1)
{
memcpy(&f.data[f.wpos], packet_data, packet_size);
f.packets[f.packet_count] = { &f.data[f.wpos], packet_size };
f.wpos += packet_size;
f.packet_count++;
result = true;
}
this->end_write();
return result;
}
packet* dequeue()
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
if (has_next())
{
return &f.packets[f.rpos++];
}
return nullptr;
}
bool requeue(packet* packet)
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
f.rpos--;
return &f.packets[f.rpos] == packet;
}
bool has_next()
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
return f.rpos < f.packet_count;
}
void begin_write()
{
write_state = state.fetch_add(0x1 << packet_queue_state_bit::write_busy, std::memory_order_acq_rel);
assert((write_state & (0x1 << packet_queue_state_bit::write_busy)) == 0);
state.fetch_or(0x1 << packet_queue_state_bit::dirty_flag, std::memory_order_acq_rel);
}
void end_write()
{
write_state = state.fetch_sub(0x1 << packet_queue_state_bit::write_busy, std::memory_order_acq_rel);
assert((write_state & (0x1 << packet_queue_state_bit::write_busy)) != 0);
}
bool begin_read()
{
if (state.load(std::memory_order_acquire) & (0x1 << packet_queue_state_bit::dirty_flag))
{
uint32 write_state = read_state ^ (0x1 << packet_queue_state_bit::active_frame);
uint32 test_state;
do
{
test_state = read_state | (0x1 << packet_queue_state_bit::dirty_flag);
} while (!state.compare_exchange_weak(test_state, write_state, std::memory_order_acq_rel));
return true;
}
return false;
}
void end_read()
{
uint32 read_idx = read_state & (0x1 << packet_queue_state_bit::active_frame);
frame_data& f = frame[read_idx];
f.rpos = 0;
f.wpos = 0;
f.wsize = 0;
f.packet_count = 0;
memset(&f.data[0], 0, sizeof(uint8) * f.data.size());
memset(&f.packets[0], 0, sizeof(packet) * f.packets.size());
read_state ^= (0x1 << packet_queue_state_bit::active_frame);
}
};
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include "core/network/timer.h"
#include "core/network/packet_queue.h"
namespace server
{
namespace core
{
struct session
{
uint32 id;
bool marked_for_delete;
std::chrono::time_point<steady_clock> last_active;
packet_queue rqueue;
packet_queue wqueue;
async_signal signal;
session() :
id(-1),
marked_for_delete(false),
last_active(std::chrono::steady_clock::now())
{}
void activate()
{
last_active = core::server_time;
}
};
}
}

View File

@ -2,6 +2,8 @@
#include "asio/steady_timer.hpp"
#include "core/shared.h"
namespace server
{
namespace core
@ -50,16 +52,23 @@ namespace server
}
};
enum class signal_code
{
no_error = 0,
shutdown = 1
};
struct async_signal_frame
{
asio::steady_timer timer;
asio::error_code error_code;
signal_code val;
async_signal_frame() : timer(io_context) {}
async_signal_frame() : timer(io_context), val(signal_code::no_error) {}
~async_signal_frame()
{
timer.cancel();
fire(signal_code::shutdown);
}
bool await_ready()
@ -70,25 +79,39 @@ namespace server
void await_suspend(std::experimental::coroutine_handle<> coro)
{
timer.expires_at(std::chrono::steady_clock::time_point::max());
timer.async_wait([this, coro](auto error_code) { this->error_code = error_code; coro.resume(); });
timer.async_wait([this, coro](auto error_code)
{
//this->error_code = error_code;
coro.resume();
});
}
void await_resume()
{
switch (error_code.value())
switch (val)
{
case 995:
// signal fired by calling timer.cancel_one()
case signal_code::no_error:
break;
//case 995:
// // signal fired by calling timer.cancel_one() or timer.cancel()
// break;
default:
throw asio::system_error(error_code);
break;
//throw val;
}
}
void fire()
void fire(signal_code signal = signal_code::no_error)
{
val = signal;
timer.cancel_one();
}
void shutdown()
{
val = signal_code::shutdown;
timer.cancel();
}
};
typedef async_signal_frame async_signal;

View File

@ -1,79 +0,0 @@
#pragma once
#include "core/shared.h"
#include "core/network/xg_session.h"
#include "core/network/connection.h"
#include "core/network/timer.h"
namespace server
{
namespace core
{
struct xg_session_pool xg_session_pool;
xg_session::xg_session(tcp_connection* connection, connection_type type) :
id(-1),
marked_for_delete(false),
connections{}
{
connection->parent = this;
connections[(uint32)type] = connection;
}
xg_session_pool::xg_session_pool() :
session_count(0)
{
async_every(1000ms, [this]()
{
int sessions_purged = 0;
for (auto& session : *this)
{
if (session)
{
uint32 id = session->id;
if (!session->has_connection())
{
delete session;
session = nullptr;
this->session_count--;
sessions_purged++;
}
}
}
if (sessions_purged)
{
printf("%d sessions purged.\n", sessions_purged);
}
});
}
xg_session* xg_session_pool::spawn_session(tcp_connection* connection, connection_type type)
{
for (int id = 0; id < this->size(); id++)
{
auto& new_session = this->at(id);
if (!new_session)
{
this->session_count++;
new_session = new xg_session(connection, type);
new_session->id = id;
return new_session;
}
}
return nullptr;
}
void init_user_session_pool(uint32 max_session_count)
{
xg_session_pool.resize(max_session_count);
}
}
}

View File

@ -1,63 +0,0 @@
#pragma once
//#include "core/network/connection.h"
namespace server
{
namespace core
{
static const uint32 max_session_count = 300;
extern struct xg_session_pool xg_session_pool;
enum class connection_type : uint8
{
CONNECTION_TYPE_GAME = 0,
CONNECTION_TYPE_MAIL = 1,
MAX_CONNECTION_TYPES,
};
struct xg_session
{
uint32 id;
bool marked_for_delete;
struct tcp_connection* connections[(uint32)connection_type::MAX_CONNECTION_TYPES];
xg_session(tcp_connection* connection, connection_type type);
void remove_connection(tcp_connection* connection)
{
for (uint32 i = 0; i < (uint32)connection_type::MAX_CONNECTION_TYPES; i++)
{
if (connections[i] == connection)
{
connections[i] = nullptr;
}
}
}
bool has_connection()
{
for (uint32 i = 0; i < (uint32)connection_type::MAX_CONNECTION_TYPES; i++)
{
if (connections[i])
{
return true;
}
}
return false;
}
};
struct xg_session_pool : std::vector<xg_session*>
{
uint32 session_count;
xg_session_pool();
xg_session* spawn_session(tcp_connection* connection, connection_type type);
};
void init_user_session_pool(uint32 max_session_count);
}
}

View File

@ -16,6 +16,7 @@ namespace server
{
// public
asio::io_context io_context;
std::chrono::time_point<std::chrono::steady_clock> server_time;
volatile e_server_status server_status;

View File

@ -15,6 +15,7 @@ namespace server
{
// public
extern asio::io_context io_context;
extern std::chrono::time_point<std::chrono::steady_clock> server_time;
extern volatile enum class e_server_status server_status;
void main_loop();

View File

@ -4,13 +4,14 @@
#include "core/network/network_service.h"
#include "core/network/timer.h"
#include "core/network/xg_session.h"
#include "crossgate/xg_session.h"
#include "mmo_server.h"
#include "xg_crypto.h"
#include "xg_packet.h"
#include "crossgate/xg_crypto.h"
#include "crossgate/xg_packet.h"
#pragma warning(push)
#pragma warning(disable : 26444)
@ -122,7 +123,7 @@ namespace mmo_server
auto accept_handler = [](core::tcp_connection* new_connection)
{
printf("connection %d accepted\n", new_connection->id);
auto session = core::xg_session_pool.spawn_session(new_connection, core::connection_type::CONNECTION_TYPE_GAME);
auto session = crossgate::xg_session_pool.spawn_session(new_connection, crossgate::connection_type::CONNECTION_TYPE_GAME);
if (!session)
{
@ -130,22 +131,20 @@ namespace mmo_server
}
};
auto receive_handler = [](core::byte_buffer& payload)
auto receive_handler = [](core::byte_buffer& payload) -> bool
{
crossgate::decrypt_message(payload);
return crossgate::decrypt_message(payload);
};
auto send_handler = [](core::byte_buffer& payload)
auto send_handler = [](core::byte_buffer& payload) -> bool
{
crossgate::encrypt_message(payload);
return crossgate::encrypt_message(payload);
};
unsigned short port = 9030;
uint32 max_session_count = 300;
core::init_user_session_pool(max_session_count);
crossgate::init_user_session_pool(max_session_count);
core::spawn_network_service("127.0.0.1", port, 300, accept_handler, receive_handler, send_handler);
//core::spawn_network_service("127.0.0.1", port + 1, 300, accept_handler);
@ -165,11 +164,13 @@ namespace mmo_server
core::start_network();
/*
core::async_after(200s, []()
{
printf("server network stopped.\n");
core::stop_network();
});
*/
//char packet4[] = "MLVlll6KdKyJmGKKII5pnmuNyMUp31qWQ7QqzcfGII5pnmuNN8X5wcMqzCuyJMAX2";
//char packet[] = "CmMMlxipiG42g1E";
@ -177,38 +178,48 @@ namespace mmo_server
//char packet2[] = R"(CharList 0 jason|0\\z241400\\z1\\z15\\z0\\z0\\z0\\z15\\z0\\z0\\z100\\z0\\z2\\zjason\\z2\\zÓÎÃñ\\z2\\z106002\\z-1| )";
//char packet[] = "ClientLogin 0 block ";
//char packet3[] = "FC ";
//char packet[] = "CmMMlxipiG42g1E";
//char packet[] = "QWHrI4t3y0x4gnZO+XBw+LGL7XYV3o5Fi98-507yuCnzU0T7YZRHP8OxQsbzdM9K-6fC9EnlhJ-eRRlhU0d4ZsWJzgBDs4Z1WPkbKs2kDNb47dw8Ff8w0tH3WMcheib0TxHZ1t0ZOrch9ID2nvd7xiZzTZHagPNmLT8RrtGLGXNAOzPph-w3eSC-HQps2DIekTuaxcYng1vgpYIgAZ8Tj9P2YjLMtU+Szf-1adkDOAcQstXdz3TukE85NMHYWfoHTv0lyhYeUk1qechP9j6FSj11vvX8HPEcvJyNLVhJI-o35jBF64unpAR+XsY1zfn3-ElvdsB7ZgXZDk7lkXoNQ6sbjmB1ath9brzXbJLzXdQb3mmDrRQ3F+4fjkiwoGn8hhzuxgLUb9BlXRc9PafSzn+C0HI5cSHLfyyoBI+41G5gQOr9-xzuxlPUb9BlXT49PaeDzn8C0mBExTCAagCAI8ZLc7W1qX5Rs0KATXAAO2Mc53Ip440JozG443chGFi-cBHklsg4kfAhEMIAyNOBlHrh3Ydz1os-c4sE-JDF9BDkhJSdGoN5LuLL3gopnMvN4DEQK7OevOQIGiO-0m3jc8t8bLhQWvUi4nse6zz7UwzdPN2wM9j95maFs6vA2EmW81VvOB5LoLDXMgIwWsE5FA44OR13216pPgyv2Lyxn6PUZLQoWYgjfYic9GY2c96MInI+OEVvSmqv3ccSysTev-4FxLjNpQDZDtG7wVyQRr3GZDBaHLFujbmI6vbvR6HeRCWzasfEcSa8gsNpZdlRC58Ce2e2JwSCdt+m50g8r22PSYCArfE8Gh87Wr3nnO4yQJSYNzBzIWV4TjEfhUwSefAmA5yd0oDzp0Ty4lHPQE9xEBJxfP1+eNGzQnwd5B1RSlWUifBr-j4A64GteBZPRZJy8Js5aQX4uJgWYCoVveOmZTAFfxWpr-cVJg3WYz6knLrpnUeFja544skgZILFG5+BKeBoUB42hoNjIeAlNwoHBRJemHwL5HPIzRWSW+9LOcHk1Z61KRU9sSBlq+oC-lf9ArCI7rk1U1v1GxngdFR+salmFfcMLX50HmY8NuQW5K9jjsUkFFan";
char packet[] = "s7Oar2m1BIPYpdaZ1eXOVKDYpotoD5GWg-i3gjin0a3ddKFVX-TgJZBGp2PRbDC0VavRTa08l9drNWsItjIDQA";
//char packet[] = "eys-ewCrJKFSxY8OgB6CmT1TyPLPj1DMR2j85zoOSMqHnBHQGDkykUM7ckq3bpc1lSJorvUnhmBMh-olkZctmB8GrYSps0hvDHe-H66wzSo3fKWgB++75g";
//char packet[] = "eyM3e-ijJJlKxYcGgBZ6mTVLyOrHj0jER2D05zIGSMJ-nAnIGGeYkS07zNl3FjzELZUalXxUVO3xRCNZhC2Pvv9MZXuxobNA7Gev-6awxQonbIWYB+eb";
//char packet[] = R"(CharList 0 jason|0\\z241400\\z1\\z15\\z0\\z0\\z0\\z15\\z0\\z0\\z100\\z0\\z12\\zjason\\z2\\z¼ûÏ°´«½ÌÊ¿\\z2\\z106002\\z-1| )";
/*
char packet_de[] = "FsV1lm6adLyZmHKaINgpnXWZnAmdIAg";
core::byte_buffer buf_de(4096);
buf_de.write(packet_de, sizeof(packet_de) - 1);
crossgate::decrypt_message(buf_de);
printf("string:%s\n", buf_de.data());
char packet[] = "Echo nr ";
core::byte_buffer buf(4096);
buf.write(packet, sizeof(packet) - 1);
crossgate::decrypt_message(buf);
//crossgate::encrypt_message(buf);
//big5ToUtf8((char*)buf.data(), buf.wpos);
//printf("string:%s", buf.data());
//crossgate::decrypt_message(buf);
crossgate::encrypt_message(buf);
printf("string:%s\n", buf.data());
//*/
core::async_every(1000ms, []()
{
core::server_time = std::chrono::steady_clock::now();
if (core::server_status == core::e_server_status::running)
{
for (auto& session : core::xg_session_pool)
for (auto session : crossgate::xg_session_pool)
{
if (session)
{
core::packet_queue& packets = session->connections[0]->rqueue;
core::packet_queue& packets = session->rqueue;
if (!packets.begin_read())
{
continue;
}
session->activate();
while (packets.has_next())
{
core::packet* packet = packets.dequeue();
crossgate::xg_dispatch_packet(std::move(*packet));
crossgate::xg_dispatch_packet(session, std::move(*packet));
//std::string packet_str((char*)packet->data, packet->length);

View File

@ -9,7 +9,7 @@ namespace server
char mapping_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
/*
char char9_str[] = {
0x43, 0xd0, 0x84, 0x91, 0xc3, 0x24, 0xcd, 0x1c,
0x3a, 0x20, 0x60, 0x80, 0x50, 0x13, 0x66, 0xce,
@ -22,7 +22,7 @@ namespace server
0x3d, 0xc6, 0x80, 0x61, 0x43, 0xe3, 0x4c, 0x8a,
0x2d, 0x62, 0xf0, 0x01, 0x01, 0x10, 0x00
};
*/
int weird_kernel1[] =
{
@ -136,7 +136,7 @@ namespace server
}
// decrypt stage 4
uint64 remove_conditional_compression(uint8* dst, uint64 dst_size, const uint8* src, uint64 length)
uint64 decompress_message(uint8* dst, uint64 dst_size, const uint8* src, uint64 length)
{
int read_counter = 0;
const uint8* read_buffer = 0;
@ -171,6 +171,21 @@ namespace server
return hi + lo;
};
/*
std::vector<uint16> buffer_9bits(4096);
uint64 buffer_9bits_index = 0;
{
read_counter = 0;
read_buffer = src;
read_length = length; // message_size - 1
for (int index = 0; index < length; index++)
{
uint16 bits_read = read_9bits(9);
buffer_9bits[index] = bits_read;
}
}
*/
//input variables
read_counter = 0;
@ -179,7 +194,7 @@ namespace server
uint8 dictionary_indices[512];
dictionary_entry dictionary_entries[256];
uint8 dictionary_size = 0;
uint16 dictionary_size = 0;
memset(dictionary_indices, 0, 512);
memset(dictionary_entries, 0, sizeof(dictionary_entry) * 256);
@ -198,7 +213,7 @@ namespace server
for (int index = 0; index < length; index++)
{
int bits_read = read_9bits(9);
int bits_read = read_9bits(9); // buffer_9bits[buffer_9bits_index++]; //
int last_char_or_something = bits_read;
if (bits_read == 0x100)
@ -226,7 +241,8 @@ namespace server
{
while ((unsigned int)next_char9 < 512)
{
const dictionary_entry& curr_entry = dictionary_entries[next_char9 - 0x101];
uint16 entry_index = next_char9 - 0x101;
const dictionary_entry& curr_entry = dictionary_entries[entry_index];
char_stack[char_stack_size++] = curr_entry.char9_right;
next_char9 = curr_entry.char9_left;
@ -289,15 +305,26 @@ namespace server
return bytes_decoded;
}
void decrypt_message(core::byte_buffer& payload)
bool decrypt_message(core::byte_buffer& payload)
{
uint8* buffer = payload.data() + payload.rpos;
uint64 payload_size = payload.rend - payload.rpos;
if (payload_size == 1)
{
printf("catch bug\n");
}
// 6 bit to 8 bit string
uint64 decrypted_size = util_64to256(buffer, buffer, mapping_table, payload_size);
if (!decrypted_size)
{
printf("bad message\n");
return false;
}
decrypted_size--; // -1 for checksum
decrypted_size = remove_salt(buffer, buffer, decrypted_size);
@ -306,7 +333,7 @@ namespace server
uint8 workbuf[4096];
if (buffer[0] % 2)
{
decrypted_size = remove_conditional_compression(workbuf, sizeof(workbuf), buffer + 1, decrypted_size);
decrypted_size = decompress_message(workbuf, sizeof(workbuf), buffer + 1, decrypted_size);
memcpy(buffer, workbuf, decrypted_size);
}
@ -314,9 +341,10 @@ namespace server
payload.rpos++;
payload.rend += decrypted_size - payload_size;
return true;
}
uint64 apply_conditional_compression(uint8* dst, uint64 dst_size, const uint8* src, uint64 length)
uint64 compress_message(uint8* dst, uint64 dst_size, const uint8* src, uint64 length)
{
int write_counter = 0;
uint8* write_buffer = 0;
@ -361,9 +389,9 @@ namespace server
return result;
};
unsigned char dictionary_indices[512];
uint8 dictionary_indices[512];
dictionary_entry dictionary_entries[256];
unsigned char dictionary_size = 0;
uint16 dictionary_size = 0;
memset(dictionary_indices, 0, 512);
memset(dictionary_entries, 0, sizeof(dictionary_entry) * 256);
@ -521,7 +549,7 @@ namespace server
//uint64 result = out_int;
}
return 0;
return length + 1;
}
int util_256to64(uint8* dst, uint8* src, char* table, uint64 length)
@ -550,31 +578,30 @@ namespace server
}
void encrypt_message(core::byte_buffer& payload)
bool encrypt_message(core::byte_buffer& payload)
{
uint8* buffer = payload.data() + payload.rpos;
const uint64 payload_size = payload.rend - payload.rpos;
if (payload.free_space() < payload_size)
{
printf("encrypt_message: not enough space\n");
return false;
}
uint64 encrypted_size = payload_size + 1; // packet_length padding
char header = (char)encrypted_size;
if (encrypted_size >= 100)
{
if (encrypted_size % 2 == 0)
{
header = encrypted_size;
header = encrypted_size + 1;
}
/*
*(_BYTE*)message_work_buffer2 = checksum;
message_length = odd_length_encrypt(
(char*)message_work_buffer2 + 1,
3 * buffer_size - 1,
(unsigned __int8*)message,
strlen(message));
*/
uint8 workbuf[4096];
encrypted_size = apply_conditional_compression(workbuf + 1, sizeof(workbuf) - 1, buffer, encrypted_size);
encrypted_size = compress_message(workbuf, sizeof(workbuf), buffer, payload_size);
/*
char char9_str[] = {
@ -591,7 +618,7 @@ char char9_str[] = {
};
*/
//workbuf[0] = header;
memcpy(buffer, workbuf, encrypted_size + 1);
memmove(buffer + 1, workbuf, encrypted_size);
}
else
{
@ -609,16 +636,17 @@ char char9_str[] = {
encrypted_size++; // null terminator;
uint8 workbuf[4096];
memset(workbuf, 0, 4096);
uint8 checksum = apply_conditional_bit_reverse(buffer, buffer, encrypted_size);
apply_salt_and_add_checksum(workbuf, buffer, encrypted_size, checksum);
encrypted_size = apply_salt_and_add_checksum(workbuf, buffer, encrypted_size, checksum);
encrypted_size++; // add checksum;
encrypted_size = util_256to64(buffer, workbuf, mapping_table, encrypted_size);
buffer[encrypted_size++] = '\n';
buffer[encrypted_size] = '\0';
buffer[encrypted_size] = '\n';
//buffer[encrypted_size] = '\0';
payload.rend += encrypted_size - payload_size;
payload.wpos = payload.rend;
payload.wpos = payload.rend + 1;
return true;
}
}
}

View File

@ -0,0 +1,40 @@
#include "xg_packet.h"
namespace server
{
namespace crossgate
{
#define add_opcode_entry(opcode, opstring, handler) \
{ opcode, opstring, sizeof(opstring) / sizeof(char) - 1, handler }
opcode_entry xg_opcode_table[XG_OPCODE_COUNT] =
{
add_opcode_entry(XG_FC, "FC", &xg_session::handle_fc),
add_opcode_entry(XG_ECHO, "Echo", &xg_session::handle_echo),
add_opcode_entry(XG_CLIENT_LOGIN, "ClientLogin", &xg_session::handle_client_login),
add_opcode_entry(XG_CHAR_LIST, "CharList", &xg_session::handle_char_list),
add_opcode_entry(XG_CHAR_LOGIN, "CharLogin", &xg_session::handle_char_login),
add_opcode_entry(XG_CHAR_LOGOUT, "CharLogout", &xg_session::handle_char_logout),
};
void xg_dispatch_packet(xg_session* session, core::packet&& packet)
{
xg_packet xg_packet(std::move(packet));
for (uint32 i = 0; i < XG_OPCODE_COUNT; i++)
{
auto opstring = xg_opcode_table[i].opstring;
auto opstring_size = xg_opcode_table[i].opstring_size;
if (!strncmp((char*)packet.data, opstring, opstring_size))
{
auto handler = xg_opcode_table[i].handler;
(session->*handler)(&xg_packet);
return;
}
}
printf("Unhandled packet:%s\n", xg_packet.data);
}
}
}

View File

@ -0,0 +1,47 @@
#pragma once
//#include "core/network/packet_queue.h"
#include "crossgate/xg_session.h"
namespace server
{
namespace crossgate
{
struct xg_packet : public core::packet
{
xg_packet(core::packet&& packet) :
core::packet(packet)
{}
};
struct opcode_entry
{
enum xg_opcode opcode;
const char* opstring;
uint32 opstring_size;
void (xg_session::*handler)(xg_packet* packet);
};
enum xg_opcode : uint16
{
XG_FC,
XG_ECHO,
XG_CLIENT_LOGIN,
XG_CHAR_LIST,
XG_CHAR_LOGIN,
XG_CHAR_LOGOUT,
XG_OPCODE_COUNT
};
extern opcode_entry xg_opcode_table[XG_OPCODE_COUNT];
template<typename T, size_t N>
int mystrncmp(const T* a, const T(&b)[N])
{
return _tcsnccmp(a, b, N - 1);
}
void xg_dispatch_packet(xg_session* session, core::packet&& packet);
}
}

View File

@ -0,0 +1,200 @@
#pragma once
#include "core/shared.h"
#include "core/network/timer.h"
#include "crossgate/xg_session.h"
#include "crossgate/xg_packet.h"
namespace server
{
namespace crossgate
{
struct xg_session_pool xg_session_pool;
xg_session::xg_session(core::tcp_connection* connection, connection_type type) :
connections{}
{
connections[(uint32)type] = connection;
connection->rqueue = &rqueue;
connection->wqueue = &wqueue;
connection->wsignal = &signal;
}
xg_session_pool::xg_session_pool() :
session_count(0)
{}
xg_session* xg_session_pool::spawn_session(core::tcp_connection* connection, connection_type type)
{
for (int id = 0; id < this->size(); id++)
{
auto& new_session = this->at(id);
if (!new_session)
{
this->session_count++;
new_session = new xg_session(connection, type);
new_session->id = id;
return new_session;
}
}
return nullptr;
}
void init_user_session_pool(uint32 max_session_count)
{
core::async_every(1000ms, []()
{
int sessions_purged = 0;
for (auto& session : xg_session_pool)
{
if (session)
{
uint32 id = session->id;
auto inactive_seconds = std::chrono::duration_cast<std::chrono::seconds>(core::server_time - session->last_active);
if (inactive_seconds.count() > 10)
{
delete session;
session = nullptr;
xg_session_pool.session_count--;
sessions_purged++;
}
//if (session->marked_for_delete)
//{
//}
}
}
if (sessions_purged)
{
printf("%d sessions purged.\n", sessions_purged);
}
});
xg_session_pool.resize(max_session_count);
}
void xg_session::handle_echo(xg_packet* packet)
{
if (!send_raw(R"(Echo nr )"))
{
printf("handle_echo failed.\n");
}
printf("handle_echo!\n");
}
void xg_session::handle_fc(xg_packet* packet)
{
printf("handle_fc!\n");
}
void xg_session::handle_client_login(xg_packet* packet)
{
enum status_code
{
success = 0,
wrong_login_or_banned = 1,
refuse = 2
};
if (!send_raw(R"(ClientLogin 0 block )"))
{
printf("handle_client_login failed.\n");
}
printf("handle_client_login!\n");
}
void xg_session::handle_char_list(xg_packet* packet)
{
enum fields
{
name = 0,
something = 1,
portrait = 2,
level = 3,
vitality = 4,
strength = 5,
toughness = 6,
quickness = 7,
magic = 8,
fire = 9,
wind = 10,
earth = 11,
water = 12,
};
if (!send_raw(R"(CharList 0 rarecheese|0\\z241401\\z1\\z15\\z0\\z0\\z0\\z15\\z0\\z0\\z100\\z0\\z12\\zrarecheese\\z2\\z见习传教士\\z2\\z106002\\z-1| )"))
{
printf("handle_char_list failed.\n");
}
printf("handle_char_list!\n");
}
void xg_session::handle_char_login(xg_packet* packet)
{
send_raw(R"(PRV 3|5|100|0 )");
send_raw(R"(CharLogin successful )");
send_raw(R"(LI 3I3 1JayvY 1 0 )");
send_raw(R"(CC 0 hV p J c 6 0 0 0 0 -1 )");
send_raw(R"(MN 城西医院\\z0 )");
send_raw(R"(CP 1|155|155|185|185|15|0|0|0|15|50|50|50|0|16|1|23|23|23|107|107|60|100|100|0|0|0|5000|0|rarecheese|| )");
send_raw(R"(CP2 1|0|0|0|0|0|0|0|0|0|0|100|0|0|0|0|241400|10|100| )");
send_raw(R"(CJ 1 见习传教士 )");
send_raw(R"(CS 0|||||||||||1|||||||||||2|||||||||||3|||||||||||4|||||||||||5|||||||||||6|||||||||||7|||||||||||8|||||||||||9|||||||||||10|||||||||||11|||||||||||12|||||||||||13|||||||||||14||||||||||| )");
send_raw(R"(TITLE 敬畏的寂静|0|17|见习传教士|1|161|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| )");
send_raw(R"(I 7|出生水晶|0|$4等级\S1\\n$4耐久\S1000/1000\S$0类别\S水晶\\n\\n\\n\\n\\n\\n\\n$4初期装备的水晶\\n\\n$1放地上便会消失\S\\n$1无法用宠物邮件发送\S\\n|27511|1|2|0|1|184|9200|22|0||8|沾着泪水的信|0|$4等级\S1\\n$0类别\S未知\\n\\n\\n\\n\\n\\n\\n$4\\n\\n$1放地上便会消失\S\\n$1无法用宠物邮件发送\S\\n|26579|1|0|0|1|56|22238|26|0||9|时间水晶Lv6|0|$4等级\S1\\n$4耐久\S0001/0001\S$0类别\S未知\\n能恢复作业时间的水晶恢复后的小时数与水晶等级相等。\\n\\n\\n\\n\\n$4能恢复作业时间的水 晶,恢复后的小时数与水晶等级相等。\\n\\n$1放地上便会消失\S\\n$1无法用宠物邮件发送\S\\n|99123|1|0|0|1|56|22693|26|1||10| 随意工作卡|0|$4等级\S1\\n$4耐久\S0005/0005\S$0类别\S未知\\n\\n\\n\\n\\n\\n\\n$4\\n\\n|27487|1|0|0|1|25|22022|26|0||11|生命回复药水(200)|0|$4等级\S3\\n$0类别\S药品\\n恢复目标生命值约200点\\n\\n\\n\\n\\n\\n$4回复生命力200点的药\\n\\n|26218|1|1|93|3|25|15608|43|20||12|传送羽毛-西医|0|$4等级\S1\\n$4耐久\S0004/0005\S$0类别\S未知\\n\\n\\n\\n\\n\\n\\n$4瞬间就传送到西医院的神奇羽毛。\\n\\n|27828|1|0|0|1|25|18779|26|0||13|僧侣适性检查合格证|0|$4等级\S1\\n$0类别\S未知\\n\\n\\n\\n\\n\\n\\n$4传教士职业的就职推荐信\\n\\n$1放地上便会消失\S\\n$1无法用宠物邮件发送\S\\n|27881|0|0|0|1|56|18106|26|0||14|报酬的银币|0|$4等级\S1\\n$0类别\S未知\\n\\n\\n\\n\\n\\n\\n$4法兰王国的银币\S\S\\n\\n$1放地上便会消失\S\\n$1无法用宠物邮件发送\S\\n|26573|0|0|72|1|56|18786|26|0| )");
send_raw(R"(EP 0 0 )");
send_raw(R"(KP 0 1|101321|4|93|93|99|99|1|16|1|48|40|34|101|100|24|0|40|60|0|10|1|新手红螳螂||0|0| )");
send_raw(R"(KP2 0 1|2|9|4|5|3|25|0|45|-10|0|0|0|0|0|0|1| )");
send_raw(R"(PT 0 0|7300|攻击|能以普通物理攻击给与打击|0|1|1141|0|1|7400|防御|能防守来自物理攻击的打击|0|1|72|1|2|407|气功弹\SLV8|给予对象前后列位置一体或数体的伤害,依等级改变攻击数。|40|1|117|2|3|1238|明净止水-|集中精神回复一定比例的体力,技 能和最大生命值越高回复比例上限越高(注意和回复力无关),使用后将无法闪躲物理攻击。\S|135|1|72|3| )");
send_raw(R"(FS 0 )");
send_raw(R"(MC 0 hV 0 0 p k bFX agh 0 )");
send_raw(R"(AB ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| )");
send_raw(R"(ABG ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| )");
send_raw(R"(C 1|3I3|12|6|0|106002|1|0|rarecheese|\\z\\z|0|0|0|敬畏的寂静|0 )");
send_raw(R"(C 2|1tq|10|5|4|14088|1|0|伯舒医师|\\z\\z|0|0|0||0 37|1ty|10|17|4|14088|1|0|姆涅医师|\\z\\z|0|0|0||0 2|1ti|12|5|4|14090|1|0|实习药剂师吉可|\\z\\z|0|0|0||0 29|1xH|16|9|6|14151|1|0|实习生蜜雅|\\z\\z|0|0|0||0 )");
send_raw(R"(BT 5Co 0 )");
send_raw(R"(POS 0 )");
send_raw(R"(AL 1 0|0|0|0|0|0|0|0|0|0| )");
send_raw(R"(IP 127.0.0.1 )");
send_raw(R"(MAC Y O )");
send_raw(R"(EF 0 0 )");
send_raw(R"(TK -1 P|欢迎来到芝士的魔力宝贝服务器~ 4 0 )");
/*
send_raw(R"(TK -1 P|感谢购买大灰狼魔力。wow335.taobao.com 4 0 )");
send_raw(R"(TK -1 P|[版本申明]GMSV\SAvaritia\SFeb\S\S1\S2014\S共享版 4 0 )");
send_raw(R"(TK -1 P|本服务端仅供研究使用,请勿用作商业用途。 4 0 )");
send_raw(R"(TK -1 P|项目主页\S&\S交流论坛http://www.cgdev.me/ 4 0 )");
send_raw(R"(STK GA\SLua引擎运行正常。 )");
send_raw(R"(STK [二键魔力公告]可用\S/help\S指令查看当前可用LuaTalk指令 )");
*/
//send_raw(R"()");
/*
*/
}
void xg_session::handle_char_logout(xg_packet* packet)
{
send_raw(R"(CharLogout successful )");
printf("handle_char_logout!\n");
signal.fire(core::signal_code::shutdown);
marked_for_delete = true;
}
}
}

View File

@ -0,0 +1,98 @@
#pragma once
#include "core/network/connection.h"
#include "core/network/session.h"
namespace server
{
namespace crossgate
{
static const uint32 max_session_count = 300;
extern struct xg_session_pool xg_session_pool;
enum class connection_type : uint8
{
CONNECTION_TYPE_GAME = 0,
CONNECTION_TYPE_MAIL = 1,
MAX_CONNECTION_TYPES,
};
struct xg_packet;
struct xg_session : public core::session
{
core::tcp_connection* connections[(uint32)connection_type::MAX_CONNECTION_TYPES];
xg_session(core::tcp_connection* connection, connection_type type);
/*
void remove_connection(tcp_connection* connection)
{
for (uint32 i = 0; i < (uint32)connection_type::MAX_CONNECTION_TYPES; i++)
{
if (connections[i] == connection)
{
connections[i] = nullptr;
}
}
}
bool has_connection()
{
for (uint32 i = 0; i < (uint32)connection_type::MAX_CONNECTION_TYPES; i++)
{
if (connections[i])
{
return true;
}
}
return false;
}
*/
void shutdown_connection()
{
signal.fire(core::signal_code::shutdown);
}
bool enqueue_response(uint8* packet_data, uint32 packet_size)
{
if (!wqueue.enqueue(packet_data, packet_size))
{
assert(false);
printf("enqueue failed.\n");
return false;
}
signal.fire();
return true;
}
#define send_raw(str) enqueue_response((uint8*)str, sizeof(str) - 1)
void handle_echo(xg_packet* packet);
void handle_fc(xg_packet* packet);
void handle_client_login(xg_packet* packet);
void handle_char_list(xg_packet* packet);
void handle_char_login(xg_packet* packet);
void handle_char_logout(xg_packet* packet);
};
struct xg_session_pool : std::vector<xg_session*>
{
uint32 session_count;
xg_session_pool();
xg_session* spawn_session(core::tcp_connection* connection, connection_type type);
};
void init_user_session_pool(uint32 max_session_count);
}
}

View File

@ -1,174 +0,0 @@
#pragma once
namespace server
{
namespace crossgate
{
struct xg_packet : public core::packet
{
xg_packet(core::packet&& packet) :
core::packet(packet)
{}
};
#define send_raw(str) enqueue_response((uint8*)str, sizeof(str) - 1)
void handle_echo(xg_packet* packet)
{
auto connection = packet->connection;
if (!connection->send_raw("Echo nr "))
{
printf("handle_echo failed.\n");
}
printf("handle_echo!\n");
}
void handle_fc(xg_packet* packet)
{
printf("handle_fc!\n");
}
void handle_client_login(xg_packet* packet)
{
enum status_code
{
success = 0,
wrong_login_or_banned = 1,
refuse = 2
};
auto connection = packet->connection;
if (!connection->send_raw("ClientLogin 0 block "))
{
printf("handle_client_login failed.\n");
}
printf("handle_client_login!\n");
}
void handle_char_list(xg_packet* packet)
{
enum fields
{
name = 0,
something = 1,
portrait = 2,
level = 3,
vitality = 4,
strength = 5,
toughness = 6,
quickness = 7,
magic = 8,
fire = 9,
wind = 10,
earth = 11,
water = 12,
};
auto connection = packet->connection;
if (!connection->send_raw(R"(CharList 0 jason|0\\z241400\\z2\\z15\\z0\\z0\\z0\\z15\\z0\\z0\\z100\\z0\\z2\\zjason\\z2\\z游民\\z2\\z106002\\z-1| )"))
{
printf("handle_char_list failed.\n");
}
printf("handle_char_list!\n");
}
void handle_char_login(xg_packet* packet)
{
auto connection = packet->connection;
connection->send_raw(R"(LI 3I3 1JayvY 1 0 )");
connection->send_raw(R"(CC 0 hV p J c 6 0 0 0 0 -1 )");
connection->send_raw(R"(MN 城西医院\\z0 )");
connection->send_raw(R"(CP 1|155|155|185|185|15|0|0|0|15|50|50|50|0|16|1|23|23|23|107|107|60|100|100|0|0|0|5000|0|jason|| )");
connection->send_raw(R"(CP2 1|0|0|0|0|0|0|0|0|0|0|100|0|0|0|0|241400|10|100| )");
connection->send_raw(R"(CJ 1 见习传教士 )");
connection->send_raw(R"(CS 0|||||||||||1|||||||||||2|||||||||||3|||||||||||4|||||||||||5|||||||||||6|||||||||||7|||||||||||8|||||||||||9|||||||||||10|||||||||||11|||||||||||12|||||||||||13|||||||||||14||||||||||| )");
connection->send_raw(R"(TITLE 敬畏的寂静|0|17|见习传教士|1|161||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||)");
connection->send_raw(R"(I )");
connection->send_raw(R"(EP 0 0 )");
connection->send_raw(R"(KP 0 1|101321|4|93|93|99|99|1|16|1|48|40|34|101|100|24|0|40|60|0|10|1|新手红螳螂||0|0| )");
connection->send_raw(R"(KP2 0 1|2|9|4|5|3|25|0|45|-10|0|0|0|0|0|0|1| )");
connection->send_raw(R"(PT 0 0|7300|攻击|能以普通物理攻击给与打击|0|1|1141|0|1|7400|防御|能防守来自物理攻击的打击|0|1|72|1|2|407|气功弹\SLV8|给予对象前后列位置一体或数体的伤害,依等级改变攻击数。|40|1|117|2|3|1238|明净止水-|集中精神回复一定比例的体力,技 能和最大生命值越高回复比例上限越高(注意和回复力无关),使用后将无法闪躲物理攻击。\S|135|1|72|3|)");
connection->send_raw(R"(FS 0 )");
connection->send_raw(R"(MC 0 hV 0 0 p k bFX agh 0 )");
connection->send_raw(R"(AB |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||)");
connection->send_raw(R"(ABG |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||)");
connection->send_raw(R"(C 1|3I3|12|6|0|106002|1|0|jason|\\z\\z|0|0|0|敬畏的寂静|0 )");
connection->send_raw(R"(C 2|1tq|10|5|4|14088|1|0|伯舒医师|\\z\\z|0|0|0||0 37|1ty|10|17|4|14088|1|0|姆涅医师|\\z\\z|0|0|0||0 2|1ti|12|5|4|14090|1|0|实习药剂师吉可|\\z\\z|0|0|0||0 29|1xH|16|9|6|14151|1|0|实习生蜜雅|\\z\\z|0|0|0||0)");
connection->send_raw(R"(BT 5Co 0 )");
connection->send_raw(R"(POS 0 )");
connection->send_raw(R"(AL 1 0|0|0|0|0|0|0|0|0|0| )");
connection->send_raw(R"(IP 127.0.0.1 )");
connection->send_raw(R"(MAC Y O )");
connection->send_raw(R"(EF 0 0 )");
connection->send_raw(R"(TK -1 P|感谢购买大灰狼魔力。wow335.taobao.com 4 0 )");
connection->send_raw(R"(TK -1 P|[版本申明]GMSV\SAvaritia\SFeb\S\S1\S2014\S共享版 4 0 )");
connection->send_raw(R"(TK -1 P|本服务端仅供研究使用,请勿用作商业用途。 4 0 )");
connection->send_raw(R"(TK -1 P|项目主页\S&\S交流论坛http://www.cgdev.me/ 4 0 )");
connection->send_raw(R"(STK GA\SLua引擎运行正常。 )");
connection->send_raw(R"(STK [二键魔力公告]可用\S/help\S指令查看当前可用LuaTalk指令 )");
//connection->send_raw(R"()");
}
struct opcode_entry
{
enum xg_opcode opcode;
const char* opstring;
uint32 opstring_size;
void (*handler)(xg_packet* packet);
};
enum xg_opcode : uint16
{
XG_FC,
XG_ECHO,
XG_CLIENT_LOGIN,
XG_CHAR_LIST,
XG_CHAR_LOGIN,
XG_OPCODE_COUNT
};
#define add_opcode_entry(opcode, opstring, handler) \
{ opcode, opstring, sizeof(opstring) / sizeof(char) - 1, handler }
opcode_entry xg_opcode_table[XG_OPCODE_COUNT] =
{
add_opcode_entry(XG_FC, "FC", &handle_fc),
add_opcode_entry(XG_ECHO, "Echo", &handle_echo),
add_opcode_entry(XG_CLIENT_LOGIN, "ClientLogin", &handle_client_login),
add_opcode_entry(XG_CHAR_LIST, "CharList", &handle_char_list),
add_opcode_entry(XG_CHAR_LOGIN, "CharLogin", &handle_char_login),
};
template<typename T, size_t N>
int mystrncmp(const T* a, const T(&b)[N])
{
return _tcsnccmp(a, b, N - 1);
}
void xg_dispatch_packet(core::packet&& packet)
{
xg_packet xg_packet(std::move(packet));
for (uint32 i = 0; i < XG_OPCODE_COUNT; i++)
{
auto opstring = xg_opcode_table[i].opstring;
auto opstring_size = xg_opcode_table[i].opstring_size;
if (!strncmp((char*)packet.data, opstring, opstring_size))
{
auto handler = xg_opcode_table[i].handler;
handler(&xg_packet);
return;
}
}
printf("Unhandled packet:%s\n", xg_packet.data);
}
}
}