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

View File

@ -4,219 +4,13 @@
#include "asio/read.hpp" #include "asio/read.hpp"
#include "core/network/timer.h" #include "core/network/timer.h"
#include "core/network/packet_queue.h"
#include "core/network/byte_buffer.h"
namespace server namespace server
{ {
namespace core 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 struct tcp_connection
{ {
int id; int id;
@ -228,29 +22,14 @@ namespace server
byte_buffer rbuffer; byte_buffer rbuffer;
byte_buffer wbuffer; byte_buffer wbuffer;
struct xg_session* parent; packet_queue* rqueue;
packet_queue* wqueue;
packet_queue rqueue; async_signal* wsignal;
packet_queue wqueue;
async_signal wsignal;
tcp_connection(asio::ip::tcp::socket&& new_socket); tcp_connection(asio::ip::tcp::socket&& new_socket);
void shutdown_and_close(); void mark_for_delete();
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;
}
//template<typename buffer_t> //template<typename buffer_t>
//auto async_recv(tcp_connection& connection, buffer_t buffer); //auto async_recv(tcp_connection& connection, buffer_t buffer);
@ -297,7 +76,7 @@ namespace server
{ {
while (socket.is_open()) while (socket.is_open())
{ {
packet_queue& packets = wqueue; packet_queue& packets = *wqueue;
if (packets.begin_read()) if (packets.begin_read())
{ {
@ -307,12 +86,13 @@ namespace server
if (wbuffer.free_space() < packet->length * 2) if (wbuffer.free_space() < packet->length * 2)
{ {
assert(false); packets.requeue(packet);
break;
} }
uint8* packet_data = wbuffer.write(packet->data, packet->length); uint8* packet_data = wbuffer.write(packet->data, packet->length);
wbuffer.rpos = packet_data - wbuffer.data(); //wbuffer.rpos = packet_data - wbuffer.data();
wbuffer.rend = wbuffer.rpos + packet->length; //wbuffer.rend = wbuffer.rpos + packet->length;
//crossgate::xg_dispatch_packet(std::move(*packet)); //crossgate::xg_dispatch_packet(std::move(*packet));
send_handler(wbuffer); send_handler(wbuffer);
@ -320,7 +100,7 @@ namespace server
//std::string packet_str((char*)packet->data, packet->length); //std::string packet_str((char*)packet->data, packet->length);
//packet_str = crossgate::decrypt_message(packet_str); //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() //xg_dispatch_packet()
} }
packets.end_read(); packets.end_read();
@ -334,19 +114,107 @@ namespace server
} }
else else
{ {
co_await wsignal; co_await *wsignal;
if (wsignal->val == signal_code::shutdown)
{
break;
}
} }
} }
} }
catch (const std::exception& exception) catch (const std::exception& exception)
{ {
//shutdown_and_close();
//printf("connection %d marked for delete.\n", id); //printf("connection %d marked for delete.\n", id);
printf("exception: %s", exception.what()); 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> template<typename connection_t, typename buffer_t>
struct async_send_frame 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> template<typename connection_t, typename buffer_t>
struct async_recv_frame struct async_recv_frame
{ {
@ -473,7 +274,11 @@ namespace server
connection.socket.async_receive(buffer, [this, coro](auto error_code, size_t bytes_read) connection.socket.async_receive(buffer, [this, coro](auto error_code, size_t bytes_read)
{ {
this->error_code = error_code; 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; return_value = (uint32)bytes_read;
coro.resume(); coro.resume();
}); });
@ -483,13 +288,20 @@ namespace server
{ {
if (error_code) if (error_code)
{ {
throw asio::system_error(error_code); return_value = -1;
//throw asio::system_error(error_code);
} }
return return_value; 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> template<typename buffer_t>
auto async_recv(tcp_connection& connection, buffer_t buffer) 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 "asio/steady_timer.hpp"
#include "core/shared.h"
namespace server namespace server
{ {
namespace core namespace core
@ -50,16 +52,23 @@ namespace server
} }
}; };
enum class signal_code
{
no_error = 0,
shutdown = 1
};
struct async_signal_frame struct async_signal_frame
{ {
asio::steady_timer timer; 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() ~async_signal_frame()
{ {
timer.cancel(); fire(signal_code::shutdown);
} }
bool await_ready() bool await_ready()
@ -70,25 +79,39 @@ namespace server
void await_suspend(std::experimental::coroutine_handle<> coro) void await_suspend(std::experimental::coroutine_handle<> coro)
{ {
timer.expires_at(std::chrono::steady_clock::time_point::max()); 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() void await_resume()
{ {
switch (error_code.value()) switch (val)
{ {
case 995: case signal_code::no_error:
// signal fired by calling timer.cancel_one()
break; break;
//case 995:
// // signal fired by calling timer.cancel_one() or timer.cancel()
// break;
default: 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(); timer.cancel_one();
} }
void shutdown()
{
val = signal_code::shutdown;
timer.cancel();
}
}; };
typedef async_signal_frame async_signal; 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 // public
asio::io_context io_context; asio::io_context io_context;
std::chrono::time_point<std::chrono::steady_clock> server_time;
volatile e_server_status server_status; volatile e_server_status server_status;

View File

@ -15,6 +15,7 @@ namespace server
{ {
// public // public
extern asio::io_context io_context; 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; extern volatile enum class e_server_status server_status;
void main_loop(); void main_loop();

View File

@ -4,13 +4,14 @@
#include "core/network/network_service.h" #include "core/network/network_service.h"
#include "core/network/timer.h" #include "core/network/timer.h"
#include "core/network/xg_session.h"
#include "crossgate/xg_session.h"
#include "mmo_server.h" #include "mmo_server.h"
#include "xg_crypto.h" #include "crossgate/xg_crypto.h"
#include "xg_packet.h" #include "crossgate/xg_packet.h"
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 26444) #pragma warning(disable : 26444)
@ -122,7 +123,7 @@ namespace mmo_server
auto accept_handler = [](core::tcp_connection* new_connection) auto accept_handler = [](core::tcp_connection* new_connection)
{ {
printf("connection %d accepted\n", new_connection->id); 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) 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; unsigned short port = 9030;
uint32 max_session_count = 300; 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, 300, accept_handler, receive_handler, send_handler);
//core::spawn_network_service("127.0.0.1", port + 1, 300, accept_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::start_network();
/*
core::async_after(200s, []() core::async_after(200s, []()
{ {
printf("server network stopped.\n"); printf("server network stopped.\n");
core::stop_network(); core::stop_network();
}); });
*/
//char packet4[] = "MLVlll6KdKyJmGKKII5pnmuNyMUp31qWQ7QqzcfGII5pnmuNN8X5wcMqzCuyJMAX2"; //char packet4[] = "MLVlll6KdKyJmGKKII5pnmuNyMUp31qWQ7QqzcfGII5pnmuNN8X5wcMqzCuyJMAX2";
//char packet[] = "CmMMlxipiG42g1E"; //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 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 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[] = "eys-ewCrJKFSxY8OgB6CmT1TyPLPj1DMR2j85zoOSMqHnBHQGDkykUM7ckq3bpc1lSJorvUnhmBMh-olkZctmB8GrYSps0hvDHe-H66wzSo3fKWgB++75g";
char packet[] = "s7Oar2m1BIPYpdaZ1eXOVKDYpotoD5GWg-i3gjin0a3ddKFVX-TgJZBGp2PRbDC0VavRTa08l9drNWsItjIDQA"; //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); core::byte_buffer buf(4096);
buf.write(packet, sizeof(packet) - 1); buf.write(packet, sizeof(packet) - 1);
crossgate::decrypt_message(buf); //crossgate::decrypt_message(buf);
//crossgate::encrypt_message(buf); crossgate::encrypt_message(buf);
printf("string:%s\n", buf.data());
//big5ToUtf8((char*)buf.data(), buf.wpos); //*/
//printf("string:%s", buf.data());
core::async_every(1000ms, []() core::async_every(1000ms, []()
{ {
core::server_time = std::chrono::steady_clock::now();
if (core::server_status == core::e_server_status::running) 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) if (session)
{ {
core::packet_queue& packets = session->connections[0]->rqueue; core::packet_queue& packets = session->rqueue;
if (!packets.begin_read()) if (!packets.begin_read())
{ {
continue; continue;
} }
session->activate();
while (packets.has_next()) while (packets.has_next())
{ {
core::packet* packet = packets.dequeue(); 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); //std::string packet_str((char*)packet->data, packet->length);

View File

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