Networking Overhaul: Modern packets, buffers, handshake, dispatch & security hardening
See Readme
This commit is contained in:
@@ -1,276 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
static LPBUFFER normalized_buffer_pool[32] = { NULL, };
|
||||
|
||||
#define DEFAULT_POOL_SIZE 8192
|
||||
|
||||
// internal function forward
|
||||
void buffer_realloc(LPBUFFER& buffer, int length);
|
||||
|
||||
static int buffer_get_pool_index(int size) {
|
||||
int i;
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if ((1 << i) >= size) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // too big... not pooled
|
||||
}
|
||||
static int buffer_get_exac_pool_index(int size) {
|
||||
int i;
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if ((1 << i) == size) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // too big... not pooled
|
||||
}
|
||||
static void buffer_pool_free ()
|
||||
{
|
||||
for (int i = 31; i >= 0; i--)
|
||||
{
|
||||
if (normalized_buffer_pool[i] != NULL)
|
||||
{
|
||||
LPBUFFER next;
|
||||
for (LPBUFFER p = normalized_buffer_pool[i]; p != NULL; p = next)
|
||||
{
|
||||
next = p->next;
|
||||
free(p->mem_data);
|
||||
free(p);
|
||||
}
|
||||
normalized_buffer_pool[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
static bool buffer_larger_pool_free (int n)
|
||||
{
|
||||
for (int i = 31; i > n; i--)
|
||||
{
|
||||
if (normalized_buffer_pool[i] != NULL)
|
||||
{
|
||||
LPBUFFER buffer = normalized_buffer_pool[i];
|
||||
LPBUFFER next = buffer->next;
|
||||
free(buffer->mem_data);
|
||||
free(buffer);
|
||||
normalized_buffer_pool[i] = next;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool safe_create(char** pdata, int number)
|
||||
{
|
||||
if (!((*pdata) = (char *) calloc (number, sizeof(char))))
|
||||
{
|
||||
sys_err("calloc failed [%d] %s", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LPBUFFER buffer_new(int size)
|
||||
{
|
||||
if (size < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LPBUFFER buffer = NULL;
|
||||
int pool_index = buffer_get_pool_index(size);
|
||||
if (pool_index >= 0) {
|
||||
BUFFER** buffer_pool = normalized_buffer_pool + pool_index;
|
||||
size = 1 << pool_index;
|
||||
|
||||
if (*buffer_pool) {
|
||||
buffer = *buffer_pool;
|
||||
*buffer_pool = buffer->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
CREATE(buffer, BUFFER, 1);
|
||||
buffer->mem_size = size;
|
||||
if (!safe_create(&buffer->mem_data, size))
|
||||
{
|
||||
if (!buffer_larger_pool_free(pool_index))
|
||||
buffer_pool_free();
|
||||
CREATE(buffer->mem_data, char, size);
|
||||
sys_err ("buffer pool free success.");
|
||||
}
|
||||
}
|
||||
assert(buffer != NULL);
|
||||
assert(buffer->mem_size == size);
|
||||
assert(buffer->mem_data != NULL);
|
||||
|
||||
buffer_reset(buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void buffer_delete(LPBUFFER buffer)
|
||||
{
|
||||
if (buffer == NULL) {
|
||||
return;
|
||||
}
|
||||
buffer_reset(buffer);
|
||||
|
||||
int size = buffer->mem_size;
|
||||
|
||||
int pool_index = buffer_get_exac_pool_index(size);
|
||||
if (pool_index >= 0) {
|
||||
BUFFER** buffer_pool = normalized_buffer_pool + pool_index;
|
||||
buffer->next = *buffer_pool;
|
||||
*buffer_pool = buffer;
|
||||
}
|
||||
else {
|
||||
free(buffer->mem_data);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD buffer_size(LPBUFFER buffer)
|
||||
{
|
||||
return (buffer->length);
|
||||
}
|
||||
|
||||
void buffer_reset(LPBUFFER buffer)
|
||||
{
|
||||
buffer->read_point = buffer->mem_data;
|
||||
buffer->write_point = buffer->mem_data;
|
||||
buffer->write_point_pos = 0;
|
||||
buffer->length = 0;
|
||||
buffer->next = NULL;
|
||||
buffer->flag = 0;
|
||||
}
|
||||
|
||||
void buffer_write(LPBUFFER& buffer, const void *src, int length)
|
||||
{
|
||||
if (buffer->write_point_pos + length >= buffer->mem_size)
|
||||
buffer_realloc(buffer, buffer->mem_size + length + MIN(10240, length));
|
||||
|
||||
thecore_memcpy(buffer->write_point, src, length);
|
||||
buffer_write_proceed(buffer, length);
|
||||
}
|
||||
|
||||
void buffer_read(LPBUFFER buffer, void * buf, int bytes)
|
||||
{
|
||||
thecore_memcpy(buf, buffer->read_point, bytes);
|
||||
buffer_read_proceed(buffer, bytes);
|
||||
}
|
||||
|
||||
BYTE buffer_byte(LPBUFFER buffer)
|
||||
{
|
||||
BYTE val = *(BYTE *) buffer->read_point;
|
||||
buffer_read_proceed(buffer, sizeof(BYTE));
|
||||
return val;
|
||||
}
|
||||
|
||||
WORD buffer_word(LPBUFFER buffer)
|
||||
{
|
||||
WORD val = *(WORD *) buffer->read_point;
|
||||
buffer_read_proceed(buffer, sizeof(WORD));
|
||||
return val;
|
||||
}
|
||||
|
||||
DWORD buffer_dword(LPBUFFER buffer)
|
||||
{
|
||||
DWORD val = *(DWORD *) buffer->read_point;
|
||||
buffer_read_proceed(buffer, sizeof(DWORD));
|
||||
return val;
|
||||
}
|
||||
|
||||
const void * buffer_read_peek(LPBUFFER buffer)
|
||||
{
|
||||
return (const void *) buffer->read_point;
|
||||
}
|
||||
|
||||
void buffer_read_proceed(LPBUFFER buffer, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
if (length < 0)
|
||||
sys_err("buffer_proceed: length argument lower than zero (length: %d)", length);
|
||||
else if (length > buffer->length)
|
||||
{
|
||||
sys_err("buffer_proceed: length argument bigger than buffer (length: %d, buffer: %d)", length, buffer->length);
|
||||
length = buffer->length;
|
||||
}
|
||||
|
||||
if (length < buffer->length)
|
||||
{
|
||||
if (buffer->read_point + length - buffer->mem_data > buffer->mem_size)
|
||||
{
|
||||
sys_err("buffer_read_proceed: buffer overflow! length %d read_point %d", length, buffer->read_point - buffer->mem_data);
|
||||
abort();
|
||||
}
|
||||
|
||||
buffer->read_point += length;
|
||||
buffer->length -= length;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_reset(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void * buffer_write_peek(LPBUFFER buffer)
|
||||
{
|
||||
return (buffer->write_point);
|
||||
}
|
||||
|
||||
void buffer_write_proceed(LPBUFFER buffer, int length)
|
||||
{
|
||||
buffer->length += length;
|
||||
buffer->write_point += length;
|
||||
buffer->write_point_pos += length;
|
||||
}
|
||||
|
||||
int buffer_has_space(LPBUFFER buffer)
|
||||
{
|
||||
return (buffer->mem_size - buffer->write_point_pos);
|
||||
}
|
||||
|
||||
void buffer_adjust_size(LPBUFFER& buffer, int add_size)
|
||||
{
|
||||
if (buffer->mem_size >= buffer->write_point_pos + add_size)
|
||||
return;
|
||||
|
||||
sys_log(0, "buffer_adjust %d current %d/%d", add_size, buffer->length, buffer->mem_size);
|
||||
buffer_realloc(buffer, buffer->mem_size + add_size);
|
||||
}
|
||||
|
||||
void buffer_realloc(LPBUFFER& buffer, int length)
|
||||
{
|
||||
int i, read_point_pos;
|
||||
LPBUFFER temp;
|
||||
|
||||
assert(length >= 0 && "buffer_realloc: length is lower than zero");
|
||||
|
||||
if (buffer->mem_size >= length)
|
||||
return;
|
||||
|
||||
i = length - buffer->mem_size;
|
||||
|
||||
if (i <= 0)
|
||||
return;
|
||||
|
||||
temp = buffer_new (length);
|
||||
sys_log(0, "reallocating buffer to %d, current %d", temp->mem_size, buffer->mem_size);
|
||||
thecore_memcpy(temp->mem_data, buffer->mem_data, buffer->mem_size);
|
||||
|
||||
read_point_pos = buffer->read_point - buffer->mem_data;
|
||||
|
||||
temp->write_point = temp->mem_data + buffer->write_point_pos;
|
||||
temp->write_point_pos = buffer->write_point_pos;
|
||||
temp->read_point = temp->mem_data + read_point_pos;
|
||||
temp->flag = buffer->flag;
|
||||
temp->next = NULL;
|
||||
temp->length = buffer->length;
|
||||
|
||||
buffer_delete(buffer);
|
||||
buffer = temp;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define SAFE_BUFFER_DELETE(buf) { if(buf != NULL) { buffer_delete(buf); buf = NULL; } }
|
||||
|
||||
typedef struct buffer BUFFER;
|
||||
typedef struct buffer * LPBUFFER;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
struct buffer * next;
|
||||
|
||||
char * write_point;
|
||||
int write_point_pos;
|
||||
|
||||
const char * read_point;
|
||||
int length;
|
||||
|
||||
char * mem_data;
|
||||
int mem_size;
|
||||
|
||||
long flag;
|
||||
};
|
||||
|
||||
LPBUFFER buffer_new(int size);
|
||||
void buffer_delete(LPBUFFER buffer);
|
||||
void buffer_reset(LPBUFFER buffer);
|
||||
|
||||
DWORD buffer_size(LPBUFFER buffer);
|
||||
int buffer_has_space(LPBUFFER buffer);
|
||||
|
||||
void buffer_write (LPBUFFER& buffer, const void* src, int length);
|
||||
void buffer_read(LPBUFFER buffer, void * buf, int bytes);
|
||||
BYTE buffer_get_byte(LPBUFFER buffer);
|
||||
WORD buffer_get_word(LPBUFFER buffer);
|
||||
DWORD buffer_get_dword(LPBUFFER buffer);
|
||||
|
||||
const void* buffer_read_peek(LPBUFFER buffer);
|
||||
void buffer_read_proceed(LPBUFFER buffer, int length);
|
||||
|
||||
void* buffer_write_peek(LPBUFFER buffer);
|
||||
void buffer_write_proceed(LPBUFFER buffer, int length);
|
||||
|
||||
void buffer_adjust_size(LPBUFFER& buffer, int add_size);
|
||||
191
src/libthecore/ring_buffer.h
Normal file
191
src/libthecore/ring_buffer.h
Normal file
@@ -0,0 +1,191 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
explicit RingBuffer(size_t initialCapacity = 0)
|
||||
{
|
||||
if (initialCapacity > 0)
|
||||
m_data.resize(initialCapacity);
|
||||
}
|
||||
|
||||
~RingBuffer() = default;
|
||||
|
||||
// Non-copyable, movable
|
||||
RingBuffer(const RingBuffer&) = delete;
|
||||
RingBuffer& operator=(const RingBuffer&) = delete;
|
||||
RingBuffer(RingBuffer&&) noexcept = default;
|
||||
RingBuffer& operator=(RingBuffer&&) noexcept = default;
|
||||
|
||||
// --- Capacity ---
|
||||
|
||||
size_t ReadableBytes() const { return m_writePos - m_readPos; }
|
||||
size_t WritableBytes() const { return m_data.size() - m_writePos; }
|
||||
size_t Capacity() const { return m_data.size(); }
|
||||
|
||||
void Reserve(size_t capacity)
|
||||
{
|
||||
if (capacity > m_data.size())
|
||||
{
|
||||
Compact();
|
||||
m_data.resize(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureWritable(size_t len)
|
||||
{
|
||||
if (WritableBytes() >= len)
|
||||
return;
|
||||
|
||||
// Try compaction first
|
||||
Compact();
|
||||
if (WritableBytes() >= len)
|
||||
return;
|
||||
|
||||
// Must grow
|
||||
size_t needed = m_writePos + len;
|
||||
size_t newSize = m_data.size();
|
||||
if (newSize == 0)
|
||||
newSize = 1024;
|
||||
while (newSize < needed)
|
||||
newSize *= 2;
|
||||
|
||||
m_data.resize(newSize);
|
||||
}
|
||||
|
||||
// --- Write operations ---
|
||||
|
||||
void Write(const void* data, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
assert(data != nullptr);
|
||||
EnsureWritable(len);
|
||||
std::memcpy(m_data.data() + m_writePos, data, len);
|
||||
m_writePos += len;
|
||||
}
|
||||
|
||||
// Direct write access for socket recv()
|
||||
uint8_t* WritePtr()
|
||||
{
|
||||
return m_data.data() + m_writePos;
|
||||
}
|
||||
|
||||
void CommitWrite(size_t len)
|
||||
{
|
||||
assert(m_writePos + len <= m_data.size());
|
||||
m_writePos += len;
|
||||
}
|
||||
|
||||
// --- Read operations ---
|
||||
|
||||
bool HasBytes(size_t n) const { return ReadableBytes() >= n; }
|
||||
|
||||
bool Peek(void* dest, size_t len) const
|
||||
{
|
||||
if (ReadableBytes() < len)
|
||||
return false;
|
||||
|
||||
std::memcpy(dest, m_data.data() + m_readPos, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Peek at a specific offset from read position (non-consuming)
|
||||
bool PeekAt(size_t offset, void* dest, size_t len) const
|
||||
{
|
||||
if (ReadableBytes() < offset + len)
|
||||
return false;
|
||||
|
||||
std::memcpy(dest, m_data.data() + m_readPos + offset, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Read(void* dest, size_t len)
|
||||
{
|
||||
if (!Peek(dest, len))
|
||||
return false;
|
||||
|
||||
m_readPos += len;
|
||||
MaybeCompact();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Discard bytes without reading them
|
||||
bool Discard(size_t len)
|
||||
{
|
||||
if (ReadableBytes() < len)
|
||||
return false;
|
||||
|
||||
m_readPos += len;
|
||||
MaybeCompact();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Direct read access for socket send() and packet processing
|
||||
const uint8_t* ReadPtr() const
|
||||
{
|
||||
return m_data.data() + m_readPos;
|
||||
}
|
||||
|
||||
size_t ReadPos() const { return m_readPos; }
|
||||
size_t WritePos() const { return m_writePos; }
|
||||
|
||||
// --- Encryption support ---
|
||||
// Get writable pointer to already-written data at a specific position
|
||||
// Used for in-place encryption of data that was just written
|
||||
uint8_t* DataAt(size_t pos)
|
||||
{
|
||||
assert(pos < m_data.size());
|
||||
return m_data.data() + pos;
|
||||
}
|
||||
|
||||
// --- Reset ---
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_readPos = 0;
|
||||
m_writePos = 0;
|
||||
}
|
||||
|
||||
// --- Compaction ---
|
||||
|
||||
void Compact()
|
||||
{
|
||||
if (m_readPos == 0)
|
||||
return;
|
||||
|
||||
size_t readable = ReadableBytes();
|
||||
if (readable > 0)
|
||||
std::memmove(m_data.data(), m_data.data() + m_readPos, readable);
|
||||
|
||||
m_readPos = 0;
|
||||
m_writePos = readable;
|
||||
}
|
||||
|
||||
private:
|
||||
void MaybeCompact()
|
||||
{
|
||||
// Compact when read position passes halfway and there's no readable data
|
||||
// or when read position is more than half the buffer
|
||||
if (m_readPos == m_writePos)
|
||||
{
|
||||
m_readPos = 0;
|
||||
m_writePos = 0;
|
||||
}
|
||||
else if (m_readPos > m_data.size() / 2)
|
||||
{
|
||||
Compact();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> m_data;
|
||||
size_t m_readPos = 0;
|
||||
size_t m_writePos = 0;
|
||||
};
|
||||
@@ -10,16 +10,6 @@ void socket_timeout(socket_t s, long sec, long usec);
|
||||
void socket_reuse(socket_t s);
|
||||
void socket_keepalive(socket_t s);
|
||||
|
||||
int socket_udp_read(socket_t desc, char * read_point, size_t space_left, struct sockaddr * from, socklen_t * fromlen)
|
||||
{
|
||||
/*
|
||||
ssize_t recvfrom(int s, void * buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen);
|
||||
*/
|
||||
ssize_t ret;
|
||||
ret = recvfrom(desc, read_point, space_left, 0, from, fromlen);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int socket_read(socket_t desc, char* read_point, size_t space_left)
|
||||
{
|
||||
int ret;
|
||||
@@ -198,11 +188,6 @@ int socket_tcp_bind(const char * ip, int port)
|
||||
return socket_bind(ip, port, SOCK_STREAM);
|
||||
}
|
||||
|
||||
int socket_udp_bind(const char * ip, int port)
|
||||
{
|
||||
return socket_bind(ip, port, SOCK_DGRAM);
|
||||
}
|
||||
|
||||
void socket_close(socket_t s)
|
||||
{
|
||||
#ifdef OS_WINDOWS
|
||||
@@ -235,6 +220,7 @@ socket_t socket_accept(socket_t s, struct sockaddr_in *peer)
|
||||
socket_nonblock(desc);
|
||||
socket_lingeroff(desc);
|
||||
socket_nodelay(desc);
|
||||
socket_keepalive(desc);
|
||||
return (desc);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ typedef int socklen_t;
|
||||
int socket_read(socket_t desc, char* read_point, size_t space_left);
|
||||
int socket_write(socket_t desc, const char *data, size_t length);
|
||||
|
||||
int socket_udp_read(socket_t desc, char * read_point, size_t space_left, struct sockaddr * from, socklen_t * fromlen);
|
||||
int socket_tcp_bind(const char * ip, int port);
|
||||
int socket_udp_bind(const char * ip, int port);
|
||||
|
||||
socket_t socket_accept(socket_t s, struct sockaddr_in *peer);
|
||||
void socket_close(socket_t s);
|
||||
|
||||
@@ -117,7 +117,7 @@ inline double rint(double x)
|
||||
#include "socket.h"
|
||||
#include "kstbl.h"
|
||||
#include "hangul.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include "signal.h"
|
||||
#include "log.h"
|
||||
#include "main.h"
|
||||
|
||||
Reference in New Issue
Block a user