mirror of
https://github.com/iriselia/xgmsv.git
synced 2025-04-07 10:38:26 +08:00
.
This commit is contained in:
parent
64b2793519
commit
8765bd3e29
@ -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);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
155
Source/core/core/network/packet_queue.h
Normal file
155
Source/core/core/network/packet_queue.h
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
32
Source/core/core/network/session.h
Normal file
32
Source/core/core/network/session.h
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
40
Source/xgmsv/crossgate/xg_packet.cpp
Normal file
40
Source/xgmsv/crossgate/xg_packet.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
47
Source/xgmsv/crossgate/xg_packet.h
Normal file
47
Source/xgmsv/crossgate/xg_packet.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
200
Source/xgmsv/crossgate/xg_session.cpp
Normal file
200
Source/xgmsv/crossgate/xg_session.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
98
Source/xgmsv/crossgate/xg_session.h
Normal file
98
Source/xgmsv/crossgate/xg_session.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user