mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2025-04-20 01:43:12 +02:00
Update brynet to the latest.
This commit is contained in:
parent
8c483b4f8e
commit
d4ccc6775d
@ -85,22 +85,16 @@ void HTTPServer::initialize() {
|
||||
delete listenBuilder;
|
||||
|
||||
listenBuilder = new wrapper::HttpListenerBuilder();
|
||||
listenBuilder->configureService(service);
|
||||
listenBuilder->WithService(service);
|
||||
|
||||
listenBuilder->configureSocketOptions({
|
||||
[](TcpSocket &socket) {
|
||||
listenBuilder->AddSocketProcess([](TcpSocket &socket) {
|
||||
socket.setNodelay();
|
||||
socket.setNonblock();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
listenBuilder->configureConnectionOptions({ AddSocketOption::WithMaxRecvBufferSize(1024) });
|
||||
listenBuilder->WithAddr(false, "0.0.0.0", p_port);
|
||||
|
||||
listenBuilder->configureListen([p_port](wrapper::BuildListenConfig builder) {
|
||||
builder.setAddr(false, "0.0.0.0", p_port);
|
||||
});
|
||||
|
||||
listenBuilder->configureEnterCallback([this](const HttpSession::Ptr &httpSession, HttpSessionHandlers &handlers) {
|
||||
listenBuilder->WithEnterCallback([this](const HttpSession::Ptr &httpSession, HttpSessionHandlers &handlers) {
|
||||
handlers.setHttpCallback([this](const HTTPParser &httpParser, const HttpSession::Ptr &session){ this->httpEnterCallbackDefault(httpParser, session); });
|
||||
handlers.setWSCallback([this](const HttpSession::Ptr &httpSession, WebSocketFormat::WebSocketFrameType opcode, const std::string &payload){ this->wsEnterCallbackDefault(httpSession, opcode, payload); });
|
||||
handlers.setClosedCallback([this](const HttpSession::Ptr &session){ this->closedCallbackDefault(session); });
|
||||
|
@ -1,4 +1,4 @@
|
||||
RapidJSON 0ccdbf364c577803e2a751f5aededce935314313
|
||||
brynet b0d13e7419628d0f7051a2bb310daaf8a506e08b
|
||||
brynet a63ac30364641000ccf8f831eea864aa98f1d50d
|
||||
rapidxml 1.13
|
||||
maddy adb1a910d4aadea09cb7b200f2ec204f61214596
|
@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define BRYNET_VERSION 1009000
|
||||
#define BRYNET_VERSION 1010000
|
||||
|
@ -11,20 +11,20 @@
|
||||
namespace brynet { namespace base {
|
||||
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
using BrynetAny = std::any;
|
||||
using BrynetAny = std::any;
|
||||
|
||||
template<typename T>
|
||||
auto cast(const BrynetAny& ud)
|
||||
{
|
||||
return std::any_cast<T>(&ud);
|
||||
}
|
||||
template<typename T>
|
||||
auto cast(const BrynetAny& ud)
|
||||
{
|
||||
return std::any_cast<T>(&ud);
|
||||
}
|
||||
#else
|
||||
using BrynetAny = int64_t;
|
||||
template<typename T>
|
||||
const T* cast(const BrynetAny& ud)
|
||||
{
|
||||
return static_cast<const T*>(&ud);
|
||||
}
|
||||
using BrynetAny = int64_t;
|
||||
template<typename T>
|
||||
const T* cast(const BrynetAny& ud)
|
||||
{
|
||||
return static_cast<const T*>(&ud);
|
||||
}
|
||||
#endif
|
||||
|
||||
} }
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,47 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdbool>
|
||||
#include <cstdio>
|
||||
#include <signal.h>
|
||||
|
||||
#include <brynet/base/Platform.hpp>
|
||||
#include <cstdbool>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
static bool app_kbhit()
|
||||
{
|
||||
static bool app_kbhit()
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
return _kbhit();
|
||||
return _kbhit();
|
||||
#else
|
||||
struct termios oldt;
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
auto newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
const auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
||||
struct termios oldt;
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
auto newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
const auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
||||
|
||||
const auto ch = getchar();
|
||||
const auto ch = getchar();
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
||||
|
||||
if (ch != EOF)
|
||||
{
|
||||
ungetc(ch, stdin);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
if (ch != EOF)
|
||||
{
|
||||
ungetc(ch, stdin);
|
||||
return true;
|
||||
}
|
||||
|
||||
} }
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,129 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdbool>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
struct array_s
|
||||
struct array_s
|
||||
{
|
||||
void* buffer;
|
||||
size_t buffer_size;
|
||||
size_t element_size;
|
||||
size_t element_num;
|
||||
};
|
||||
|
||||
static void array_delete(struct array_s* self)
|
||||
{
|
||||
if (self == nullptr)
|
||||
{
|
||||
void* buffer;
|
||||
size_t buffer_size;
|
||||
size_t element_size;
|
||||
size_t element_num;
|
||||
};
|
||||
|
||||
static void array_delete(struct array_s* self)
|
||||
{
|
||||
if (self == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->buffer != nullptr)
|
||||
{
|
||||
free(self->buffer);
|
||||
self->buffer = nullptr;
|
||||
}
|
||||
|
||||
self->element_num = 0;
|
||||
free(self);
|
||||
self = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
static struct array_s* array_new(size_t num, size_t element_size)
|
||||
if (self->buffer != nullptr)
|
||||
{
|
||||
auto ret = (struct array_s*)malloc(sizeof(struct array_s));
|
||||
if (ret == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto buffer_size = num * element_size;
|
||||
|
||||
ret->buffer_size = 0;
|
||||
ret->element_size = 0;
|
||||
ret->element_num = 0;
|
||||
ret->buffer = malloc(buffer_size);
|
||||
|
||||
if (ret->buffer != nullptr)
|
||||
{
|
||||
ret->element_size = element_size;
|
||||
ret->element_num = num;
|
||||
ret->buffer_size = buffer_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
array_delete(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
free(self->buffer);
|
||||
self->buffer = nullptr;
|
||||
}
|
||||
|
||||
static void* array_at(struct array_s* self, size_t index)
|
||||
self->element_num = 0;
|
||||
free(self);
|
||||
self = nullptr;
|
||||
}
|
||||
|
||||
static struct array_s* array_new(size_t num, size_t element_size)
|
||||
{
|
||||
auto ret = (struct array_s*) malloc(sizeof(struct array_s));
|
||||
if (ret == nullptr)
|
||||
{
|
||||
void* ret = nullptr;
|
||||
|
||||
if (index < self->element_num)
|
||||
{
|
||||
ret = (char*)(self->buffer) + (index * self->element_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool array_set(struct array_s* self, size_t index, const void* data)
|
||||
{
|
||||
void* old_data = array_at(self, index);
|
||||
const auto buffer_size = num * element_size;
|
||||
|
||||
if (old_data != nullptr)
|
||||
{
|
||||
memcpy(old_data, data, self->element_size);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ret->buffer_size = 0;
|
||||
ret->element_size = 0;
|
||||
ret->element_num = 0;
|
||||
ret->buffer = malloc(buffer_size);
|
||||
|
||||
if (ret->buffer != nullptr)
|
||||
{
|
||||
ret->element_size = element_size;
|
||||
ret->element_num = num;
|
||||
ret->buffer_size = buffer_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
array_delete(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
static bool array_increase(struct array_s* self, size_t increase_num)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* array_at(struct array_s* self, size_t index)
|
||||
{
|
||||
void* ret = nullptr;
|
||||
|
||||
if (index < self->element_num)
|
||||
{
|
||||
if (increase_num == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto new_buffer_size = self->buffer_size + increase_num * self->element_size;
|
||||
auto new_buffer = malloc(new_buffer_size);
|
||||
|
||||
if (new_buffer != nullptr)
|
||||
{
|
||||
memcpy(new_buffer, self->buffer, self->buffer_size);
|
||||
free(self->buffer);
|
||||
self->buffer = new_buffer;
|
||||
self->element_num += increase_num;
|
||||
self->buffer_size = new_buffer_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
ret = (char*) (self->buffer) + (index * self->element_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
static size_t array_num(const struct array_s* self)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool array_set(struct array_s* self, size_t index, const void* data)
|
||||
{
|
||||
void* old_data = array_at(self, index);
|
||||
|
||||
if (old_data != nullptr)
|
||||
{
|
||||
return self->element_num;
|
||||
memcpy(old_data, data, self->element_size);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool array_increase(struct array_s* self, size_t increase_num)
|
||||
{
|
||||
if (increase_num == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} }
|
||||
const auto new_buffer_size = self->buffer_size + increase_num * self->element_size;
|
||||
auto new_buffer = malloc(new_buffer_size);
|
||||
|
||||
if (new_buffer != nullptr)
|
||||
{
|
||||
memcpy(new_buffer, self->buffer, self->buffer_size);
|
||||
free(self->buffer);
|
||||
self->buffer = new_buffer;
|
||||
self->element_num += increase_num;
|
||||
self->buffer_size = new_buffer_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t array_num(const struct array_s* self)
|
||||
{
|
||||
return self->element_num;
|
||||
}
|
||||
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,189 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdbool>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
struct buffer_s
|
||||
struct buffer_s
|
||||
{
|
||||
char* data;
|
||||
size_t data_len;
|
||||
|
||||
size_t write_pos;
|
||||
size_t read_pos;
|
||||
};
|
||||
|
||||
static void buffer_delete(struct buffer_s* self)
|
||||
{
|
||||
if (self == nullptr)
|
||||
{
|
||||
char* data;
|
||||
size_t data_len;
|
||||
|
||||
size_t write_pos;
|
||||
size_t read_pos;
|
||||
};
|
||||
|
||||
static void buffer_delete(struct buffer_s* self)
|
||||
{
|
||||
if (self == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->data != nullptr)
|
||||
{
|
||||
free(self->data);
|
||||
self->data = nullptr;
|
||||
}
|
||||
|
||||
free(self);
|
||||
self = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
static struct buffer_s* buffer_new(size_t buffer_size)
|
||||
if (self->data != nullptr)
|
||||
{
|
||||
struct buffer_s* ret = (struct buffer_s*)malloc(sizeof(struct buffer_s));
|
||||
if (ret == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
free(self->data);
|
||||
self->data = nullptr;
|
||||
}
|
||||
|
||||
ret->data_len = 0;
|
||||
ret->read_pos = 0;
|
||||
ret->write_pos = 0;
|
||||
ret->data = (char*)malloc(sizeof(char) * buffer_size);
|
||||
free(self);
|
||||
self = nullptr;
|
||||
}
|
||||
|
||||
if (ret->data != nullptr)
|
||||
static struct buffer_s* buffer_new(size_t buffer_size)
|
||||
{
|
||||
struct buffer_s* ret = (struct buffer_s*) malloc(sizeof(struct buffer_s));
|
||||
if (ret == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret->data_len = 0;
|
||||
ret->read_pos = 0;
|
||||
ret->write_pos = 0;
|
||||
ret->data = (char*) malloc(sizeof(char) * buffer_size);
|
||||
|
||||
if (ret->data != nullptr)
|
||||
{
|
||||
ret->data_len = buffer_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_delete(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t buffer_getreadvalidcount(struct buffer_s* self)
|
||||
{
|
||||
return self->write_pos - self->read_pos;
|
||||
}
|
||||
|
||||
static void buffer_adjustto_head(struct buffer_s* self)
|
||||
{
|
||||
if (self->read_pos == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto len = buffer_getreadvalidcount(self);
|
||||
if (len > 0)
|
||||
{
|
||||
memmove(self->data, self->data + self->read_pos, len);
|
||||
}
|
||||
|
||||
self->read_pos = 0;
|
||||
self->write_pos = len;
|
||||
}
|
||||
|
||||
static void buffer_init(struct buffer_s* self)
|
||||
{
|
||||
self->read_pos = 0;
|
||||
self->write_pos = 0;
|
||||
}
|
||||
|
||||
static size_t buffer_getwritepos(struct buffer_s* self)
|
||||
{
|
||||
return self->write_pos;
|
||||
}
|
||||
|
||||
static size_t buffer_getreadpos(struct buffer_s* self)
|
||||
{
|
||||
return self->read_pos;
|
||||
}
|
||||
|
||||
static bool buffer_addwritepos(struct buffer_s* self, size_t value)
|
||||
{
|
||||
const size_t temp = self->write_pos + value;
|
||||
if (temp <= self->data_len)
|
||||
{
|
||||
self->write_pos = temp;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool buffer_addreadpos(struct buffer_s* self, size_t value)
|
||||
{
|
||||
const size_t temp = self->read_pos + value;
|
||||
if (temp <= self->data_len)
|
||||
{
|
||||
self->read_pos = temp;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t buffer_getwritevalidcount(struct buffer_s* self)
|
||||
{
|
||||
return self->data_len - self->write_pos;
|
||||
}
|
||||
|
||||
static size_t buffer_getsize(struct buffer_s* self)
|
||||
{
|
||||
return self->data_len;
|
||||
}
|
||||
|
||||
static char* buffer_getwriteptr(struct buffer_s* self)
|
||||
{
|
||||
if (self->write_pos < self->data_len)
|
||||
{
|
||||
return self->data + self->write_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static char* buffer_getreadptr(struct buffer_s* self)
|
||||
{
|
||||
if (self->read_pos < self->data_len)
|
||||
{
|
||||
return self->data + self->read_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool buffer_write(struct buffer_s* self, const char* data, size_t len)
|
||||
{
|
||||
bool write_ret = true;
|
||||
|
||||
if (buffer_getwritevalidcount(self) >= len)
|
||||
{
|
||||
memcpy(buffer_getwriteptr(self), data, len);
|
||||
buffer_addwritepos(self, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t left_len = self->data_len - buffer_getreadvalidcount(self);
|
||||
if (left_len >= len)
|
||||
{
|
||||
ret->data_len = buffer_size;
|
||||
buffer_adjustto_head(self);
|
||||
buffer_write(self, data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_delete(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t buffer_getreadvalidcount(struct buffer_s* self)
|
||||
{
|
||||
return self->write_pos - self->read_pos;
|
||||
}
|
||||
|
||||
static void buffer_adjustto_head(struct buffer_s* self)
|
||||
{
|
||||
if (self->read_pos == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto len = buffer_getreadvalidcount(self);
|
||||
if (len > 0)
|
||||
{
|
||||
memmove(self->data, self->data + self->read_pos, len);
|
||||
}
|
||||
|
||||
self->read_pos = 0;
|
||||
self->write_pos = len;
|
||||
}
|
||||
|
||||
static void buffer_init(struct buffer_s* self)
|
||||
{
|
||||
self->read_pos = 0;
|
||||
self->write_pos = 0;
|
||||
}
|
||||
|
||||
static size_t buffer_getwritepos(struct buffer_s* self)
|
||||
{
|
||||
return self->write_pos;
|
||||
}
|
||||
|
||||
static size_t buffer_getreadpos(struct buffer_s* self)
|
||||
{
|
||||
return self->read_pos;
|
||||
}
|
||||
|
||||
static bool buffer_addwritepos(struct buffer_s* self, size_t value)
|
||||
{
|
||||
const size_t temp = self->write_pos + value;
|
||||
if (temp <= self->data_len)
|
||||
{
|
||||
self->write_pos = temp;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
write_ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool buffer_addreadpos(struct buffer_s* self, size_t value)
|
||||
{
|
||||
const size_t temp = self->read_pos + value;
|
||||
if (temp <= self->data_len)
|
||||
{
|
||||
self->read_pos = temp;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return write_ret;
|
||||
}
|
||||
|
||||
static size_t buffer_getwritevalidcount(struct buffer_s* self)
|
||||
{
|
||||
return self->data_len - self->write_pos;
|
||||
}
|
||||
|
||||
static size_t buffer_getsize(struct buffer_s* self)
|
||||
{
|
||||
return self->data_len;
|
||||
}
|
||||
|
||||
static char* buffer_getwriteptr(struct buffer_s* self)
|
||||
{
|
||||
if (self->write_pos < self->data_len)
|
||||
{
|
||||
return self->data + self->write_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static char* buffer_getreadptr(struct buffer_s* self)
|
||||
{
|
||||
if (self->read_pos < self->data_len)
|
||||
{
|
||||
return self->data + self->read_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool buffer_write(struct buffer_s* self, const char* data, size_t len)
|
||||
{
|
||||
bool write_ret = true;
|
||||
|
||||
if (buffer_getwritevalidcount(self) >= len)
|
||||
{
|
||||
/* Ö±½ÓдÈë */
|
||||
memcpy(buffer_getwriteptr(self), data, len);
|
||||
buffer_addwritepos(self, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t left_len = self->data_len - buffer_getreadvalidcount(self);
|
||||
if (left_len >= len)
|
||||
{
|
||||
buffer_adjustto_head(self);
|
||||
buffer_write(self, data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
write_ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return write_ret;
|
||||
}
|
||||
|
||||
} }
|
||||
}}// namespace brynet::base
|
||||
|
@ -13,4 +13,4 @@
|
||||
#if (__cplusplus >= 201703L || \
|
||||
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
|
||||
#define BRYNET_HAVE_LANG_CXX17 1
|
||||
#endif
|
||||
#endif
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
class NonCopyable
|
||||
{
|
||||
public:
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
const NonCopyable& operator=(const NonCopyable&) = delete;
|
||||
class NonCopyable
|
||||
{
|
||||
public:
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
const NonCopyable& operator=(const NonCopyable&) = delete;
|
||||
|
||||
protected:
|
||||
NonCopyable() = default;
|
||||
~NonCopyable() = default;
|
||||
};
|
||||
protected:
|
||||
NonCopyable() = default;
|
||||
~NonCopyable() = default;
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,435 +1,432 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstdbool>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/endian/Endian.hpp>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
class BasePacketWriter : public NonCopyable
|
||||
class BasePacketWriter : public NonCopyable
|
||||
{
|
||||
public:
|
||||
BasePacketWriter(char* buffer,
|
||||
size_t len,
|
||||
bool useBigEndian = false,
|
||||
bool isAutoMalloc = false)
|
||||
: mIsAutoMalloc(isAutoMalloc),
|
||||
mBigEndian(useBigEndian)
|
||||
{
|
||||
public:
|
||||
BasePacketWriter(char* buffer,
|
||||
size_t len,
|
||||
bool useBigEndian = false,
|
||||
bool isAutoMalloc = false)
|
||||
:
|
||||
mIsAutoMalloc(isAutoMalloc),
|
||||
mBigEndian(useBigEndian)
|
||||
mMaxLen = len;
|
||||
mPos = 0;
|
||||
mBuffer = buffer;
|
||||
mMallocBuffer = nullptr;
|
||||
}
|
||||
|
||||
virtual ~BasePacketWriter()
|
||||
{
|
||||
if (mMallocBuffer != nullptr)
|
||||
{
|
||||
mMaxLen = len;
|
||||
mPos = 0;
|
||||
mBuffer = buffer;
|
||||
free(mMallocBuffer);
|
||||
mMallocBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
mPos = 0;
|
||||
}
|
||||
|
||||
size_t getMaxLen() const
|
||||
{
|
||||
return mMaxLen;
|
||||
}
|
||||
|
||||
size_t getPos() const
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
|
||||
const char* getData() const
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
bool isAutoGrow() const
|
||||
{
|
||||
return mIsAutoMalloc;
|
||||
}
|
||||
|
||||
bool writeBool(bool value)
|
||||
{
|
||||
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeINT8(int8_t value)
|
||||
{
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeUINT8(uint8_t value)
|
||||
{
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeINT16(int16_t value)
|
||||
{
|
||||
value = endian::hostToNetwork16(value, mBigEndian);
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeUINT16(uint16_t value)
|
||||
{
|
||||
value = endian::hostToNetwork16(value, mBigEndian);
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeINT32(int32_t value)
|
||||
{
|
||||
value = endian::hostToNetwork32(value, mBigEndian);
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeUINT32(uint32_t value)
|
||||
{
|
||||
value = endian::hostToNetwork32(value, mBigEndian);
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeINT64(int64_t value)
|
||||
{
|
||||
value = endian::hostToNetwork64(value, mBigEndian);
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
bool writeUINT64(uint64_t value)
|
||||
{
|
||||
value = endian::hostToNetwork64(value, mBigEndian);
|
||||
return writeBuffer((char*) &value, sizeof(value));
|
||||
}
|
||||
|
||||
bool writeBinary(const std::string& binary)
|
||||
{
|
||||
return writeBuffer(binary.c_str(), binary.size());
|
||||
}
|
||||
bool writeBinary(const char* binary, size_t binaryLen)
|
||||
{
|
||||
return writeBuffer(binary, binaryLen);
|
||||
}
|
||||
bool writeBuffer(const char* buffer, size_t len)
|
||||
{
|
||||
growBuffer(len);
|
||||
|
||||
if (mMaxLen < (mPos + len))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(mBuffer + mPos, buffer, len);
|
||||
mPos += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
BasePacketWriter& operator<<(const bool& v)
|
||||
{
|
||||
writeBool(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const uint8_t& v)
|
||||
{
|
||||
writeUINT8(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const int8_t& v)
|
||||
{
|
||||
writeINT8(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const int16_t& v)
|
||||
{
|
||||
writeINT16(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const uint16_t& v)
|
||||
{
|
||||
writeUINT16(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const int32_t& v)
|
||||
{
|
||||
writeINT32(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const uint32_t& v)
|
||||
{
|
||||
writeUINT32(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const int64_t& v)
|
||||
{
|
||||
writeINT64(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const uint64_t& v)
|
||||
{
|
||||
writeUINT64(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const char* const& v)
|
||||
{
|
||||
writeBinary(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter& operator<<(const std::string& v)
|
||||
{
|
||||
writeBinary(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// 为了避免直接<<导致没有指定字节序导致隐藏BUG,因为此函数设置为私有
|
||||
template<typename T>
|
||||
BasePacketWriter& operator<<(const T& v)
|
||||
{
|
||||
static_assert(!std::is_pointer<T>::value, "T must is't a pointer");
|
||||
static_assert(std::is_class<T>::value, "T must a class or struct type");
|
||||
static_assert(std::is_pod<T>::value, "T must a pod type");
|
||||
writeBuffer((const char*) &v, sizeof(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Arg1, typename... Args>
|
||||
void writev(const Arg1& arg1, const Args&... args)
|
||||
{
|
||||
this->operator<<(arg1);
|
||||
writev(args...);
|
||||
}
|
||||
|
||||
void writev()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void growBuffer(size_t len)
|
||||
{
|
||||
if (!mIsAutoMalloc || (mPos + len) <= mMaxLen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto newBuffer = (char*) malloc(mMaxLen + len);
|
||||
if (newBuffer == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(newBuffer, mBuffer, mPos);
|
||||
|
||||
if (mMallocBuffer != nullptr)
|
||||
{
|
||||
free(mMallocBuffer);
|
||||
mMallocBuffer = nullptr;
|
||||
}
|
||||
|
||||
virtual ~BasePacketWriter()
|
||||
{
|
||||
if (mMallocBuffer != nullptr)
|
||||
{
|
||||
free(mMallocBuffer);
|
||||
mMallocBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
mMaxLen += len;
|
||||
mMallocBuffer = newBuffer;
|
||||
mBuffer = newBuffer;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
mPos = 0;
|
||||
}
|
||||
protected:
|
||||
const bool mIsAutoMalloc;
|
||||
bool mBigEndian;
|
||||
size_t mPos;
|
||||
size_t mMaxLen;
|
||||
char* mBuffer;
|
||||
char* mMallocBuffer;
|
||||
};
|
||||
|
||||
size_t getMaxLen() const
|
||||
{
|
||||
return mMaxLen;
|
||||
}
|
||||
|
||||
size_t getPos() const
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
|
||||
const char* getData() const
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
bool isAutoGrow() const
|
||||
{
|
||||
return mIsAutoMalloc;
|
||||
}
|
||||
|
||||
bool writeBool(bool value)
|
||||
{
|
||||
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeINT8(int8_t value)
|
||||
{
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeUINT8(uint8_t value)
|
||||
{
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeINT16(int16_t value)
|
||||
{
|
||||
value = endian::hostToNetwork16(value, mBigEndian);
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeUINT16(uint16_t value)
|
||||
{
|
||||
value = endian::hostToNetwork16(value, mBigEndian);
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeINT32(int32_t value)
|
||||
{
|
||||
value = endian::hostToNetwork32(value, mBigEndian);
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeUINT32(uint32_t value)
|
||||
{
|
||||
value = endian::hostToNetwork32(value, mBigEndian);
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeINT64(int64_t value)
|
||||
{
|
||||
value = endian::hostToNetwork64(value, mBigEndian);
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
bool writeUINT64(uint64_t value)
|
||||
{
|
||||
value = endian::hostToNetwork64(value, mBigEndian);
|
||||
return writeBuffer((char*)&value, sizeof(value));
|
||||
}
|
||||
|
||||
bool writeBinary(const std::string& binary)
|
||||
{
|
||||
return writeBuffer(binary.c_str(), binary.size());
|
||||
}
|
||||
bool writeBinary(const char* binary, size_t binaryLen)
|
||||
{
|
||||
return writeBuffer(binary, binaryLen);
|
||||
}
|
||||
bool writeBuffer(const char* buffer, size_t len)
|
||||
{
|
||||
growBuffer(len);
|
||||
|
||||
if (mMaxLen < (mPos + len))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(mBuffer + mPos, buffer, len);
|
||||
mPos += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
BasePacketWriter & operator << (const bool &v)
|
||||
{
|
||||
writeBool(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const uint8_t &v)
|
||||
{
|
||||
writeUINT8(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const int8_t &v)
|
||||
{
|
||||
writeINT8(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const int16_t &v)
|
||||
{
|
||||
writeINT16(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const uint16_t &v)
|
||||
{
|
||||
writeUINT16(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const int32_t &v)
|
||||
{
|
||||
writeINT32(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const uint32_t &v)
|
||||
{
|
||||
writeUINT32(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const int64_t &v)
|
||||
{
|
||||
writeINT64(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const uint64_t &v)
|
||||
{
|
||||
writeUINT64(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const char* const &v)
|
||||
{
|
||||
writeBinary(v);
|
||||
return *this;
|
||||
}
|
||||
BasePacketWriter & operator << (const std::string &v)
|
||||
{
|
||||
writeBinary(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// 为了避免直接<<导致没有指定字节序导致隐藏BUG,因为此函数设置为私有
|
||||
template<typename T>
|
||||
BasePacketWriter & operator << (const T& v)
|
||||
{
|
||||
static_assert(!std::is_pointer<T>::value, "T must is't a pointer");
|
||||
static_assert(std::is_class <T>::value, "T must a class or struct type");
|
||||
static_assert(std::is_pod <T>::value, "T must a pod type");
|
||||
writeBuffer((const char*)&v, sizeof(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Arg1, typename... Args>
|
||||
void writev(const Arg1& arg1, const Args&... args)
|
||||
{
|
||||
this->operator<<(arg1);
|
||||
writev(args...);
|
||||
}
|
||||
|
||||
void writev()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void growBuffer(size_t len)
|
||||
{
|
||||
if (!mIsAutoMalloc || (mPos + len) <= mMaxLen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto newBuffer = (char*)malloc(mMaxLen + len);
|
||||
if (newBuffer == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(newBuffer, mBuffer, mPos);
|
||||
|
||||
if (mMallocBuffer != nullptr)
|
||||
{
|
||||
free(mMallocBuffer);
|
||||
mMallocBuffer = nullptr;
|
||||
}
|
||||
|
||||
mMaxLen += len;
|
||||
mMallocBuffer = newBuffer;
|
||||
mBuffer = newBuffer;
|
||||
}
|
||||
|
||||
protected:
|
||||
const bool mIsAutoMalloc;
|
||||
bool mBigEndian;
|
||||
size_t mPos;
|
||||
size_t mMaxLen;
|
||||
char* mBuffer;
|
||||
char* mMallocBuffer;
|
||||
};
|
||||
|
||||
class BasePacketReader
|
||||
class BasePacketReader
|
||||
{
|
||||
public:
|
||||
BasePacketReader(const char* buffer,
|
||||
size_t len,
|
||||
bool useBigEndian = false)
|
||||
: mBigEndian(useBigEndian),
|
||||
mSize(len)
|
||||
{
|
||||
public:
|
||||
BasePacketReader(const char* buffer,
|
||||
size_t len,
|
||||
bool useBigEndian = false) :
|
||||
mBigEndian(useBigEndian),
|
||||
mSize(len)
|
||||
{
|
||||
mPos = 0;
|
||||
mSavedPos = 0;
|
||||
mBuffer = buffer;
|
||||
}
|
||||
mPos = 0;
|
||||
mSavedPos = 0;
|
||||
mBuffer = buffer;
|
||||
}
|
||||
|
||||
virtual ~BasePacketReader() = default;
|
||||
virtual ~BasePacketReader() = default;
|
||||
|
||||
void useBigEndian()
|
||||
{
|
||||
mBigEndian = true;
|
||||
}
|
||||
|
||||
void useLittleEndian()
|
||||
{
|
||||
mBigEndian = false;
|
||||
}
|
||||
|
||||
void savePos()
|
||||
{
|
||||
mSavedPos = mPos;
|
||||
}
|
||||
|
||||
size_t savedPos() const
|
||||
{
|
||||
return mSavedPos;
|
||||
}
|
||||
|
||||
size_t getLeft() const
|
||||
{
|
||||
if (mPos > mSize)
|
||||
{
|
||||
throw std::out_of_range("current pos is greater than max len");
|
||||
}
|
||||
return mSize - mPos;
|
||||
}
|
||||
|
||||
bool enough(size_t len) const
|
||||
{
|
||||
if (mPos > mSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (mSize - mPos) >= len;
|
||||
}
|
||||
|
||||
const char* begin() const
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
const char* currentBuffer() const
|
||||
{
|
||||
return mBuffer+mPos;
|
||||
}
|
||||
|
||||
void consumeAll()
|
||||
{
|
||||
mPos = mSize;
|
||||
savePos();
|
||||
}
|
||||
|
||||
size_t currentPos() const
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void addPos(size_t diff)
|
||||
{
|
||||
const auto tmpPos = mPos + diff;
|
||||
if (tmpPos > mSize)
|
||||
{
|
||||
throw std::out_of_range("diff is to big");
|
||||
}
|
||||
|
||||
mPos = tmpPos;
|
||||
}
|
||||
|
||||
bool readBool()
|
||||
{
|
||||
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
||||
bool value = false;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
int8_t readINT8()
|
||||
{
|
||||
int8_t value = 0;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
uint8_t readUINT8()
|
||||
{
|
||||
uint8_t value = 0;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
int16_t readINT16()
|
||||
{
|
||||
int16_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost16(value, mBigEndian);
|
||||
}
|
||||
uint16_t readUINT16()
|
||||
{
|
||||
uint16_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost16(value, mBigEndian);
|
||||
}
|
||||
int32_t readINT32()
|
||||
{
|
||||
int32_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost32(value, mBigEndian);
|
||||
}
|
||||
uint32_t readUINT32()
|
||||
{
|
||||
uint32_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost32(value, mBigEndian);
|
||||
}
|
||||
int64_t readINT64()
|
||||
{
|
||||
int64_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost64(value, mBigEndian);
|
||||
}
|
||||
uint64_t readUINT64()
|
||||
{
|
||||
uint64_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost64(value, mBigEndian);
|
||||
}
|
||||
|
||||
private:
|
||||
// 为了避免直接read(uintXXX)导致没有指定字节序造成隐患BUG,因为此函数设置为私有
|
||||
template<typename T>
|
||||
void read(T& value)
|
||||
{
|
||||
static_assert(std::is_same<T, typename std::remove_pointer<T>::type>::value,
|
||||
"T must a normal type");
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"T must a pod type");
|
||||
|
||||
if ((mPos + sizeof(value)) > mSize)
|
||||
{
|
||||
throw std::out_of_range("T size is to big");
|
||||
}
|
||||
|
||||
value = *(T*)(mBuffer + mPos);
|
||||
mPos += sizeof(value);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mBigEndian;
|
||||
const size_t mSize;
|
||||
const char* mBuffer;
|
||||
size_t mPos;
|
||||
size_t mSavedPos;
|
||||
};
|
||||
|
||||
template<size_t SIZE>
|
||||
class AutoMallocPacket : public BasePacketWriter
|
||||
void useBigEndian()
|
||||
{
|
||||
public:
|
||||
explicit AutoMallocPacket(bool useBigEndian = false,
|
||||
bool isAutoMalloc = false)
|
||||
:
|
||||
BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc)
|
||||
{}
|
||||
private:
|
||||
char mData[SIZE];
|
||||
};
|
||||
mBigEndian = true;
|
||||
}
|
||||
|
||||
using BigPacket = AutoMallocPacket<32 * 1024>;
|
||||
void useLittleEndian()
|
||||
{
|
||||
mBigEndian = false;
|
||||
}
|
||||
|
||||
} }
|
||||
void savePos()
|
||||
{
|
||||
mSavedPos = mPos;
|
||||
}
|
||||
|
||||
size_t savedPos() const
|
||||
{
|
||||
return mSavedPos;
|
||||
}
|
||||
|
||||
size_t getLeft() const
|
||||
{
|
||||
if (mPos > mSize)
|
||||
{
|
||||
throw std::out_of_range("current pos is greater than max len");
|
||||
}
|
||||
return mSize - mPos;
|
||||
}
|
||||
|
||||
bool enough(size_t len) const
|
||||
{
|
||||
if (mPos > mSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (mSize - mPos) >= len;
|
||||
}
|
||||
|
||||
const char* begin() const
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
const char* currentBuffer() const
|
||||
{
|
||||
return mBuffer + mPos;
|
||||
}
|
||||
|
||||
void consumeAll()
|
||||
{
|
||||
mPos = mSize;
|
||||
savePos();
|
||||
}
|
||||
|
||||
size_t currentPos() const
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void addPos(size_t diff)
|
||||
{
|
||||
const auto tmpPos = mPos + diff;
|
||||
if (tmpPos > mSize)
|
||||
{
|
||||
throw std::out_of_range("diff is to big");
|
||||
}
|
||||
|
||||
mPos = tmpPos;
|
||||
}
|
||||
|
||||
bool readBool()
|
||||
{
|
||||
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
||||
bool value = false;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
int8_t readINT8()
|
||||
{
|
||||
int8_t value = 0;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
uint8_t readUINT8()
|
||||
{
|
||||
uint8_t value = 0;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
int16_t readINT16()
|
||||
{
|
||||
int16_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost16(value, mBigEndian);
|
||||
}
|
||||
uint16_t readUINT16()
|
||||
{
|
||||
uint16_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost16(value, mBigEndian);
|
||||
}
|
||||
int32_t readINT32()
|
||||
{
|
||||
int32_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost32(value, mBigEndian);
|
||||
}
|
||||
uint32_t readUINT32()
|
||||
{
|
||||
uint32_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost32(value, mBigEndian);
|
||||
}
|
||||
int64_t readINT64()
|
||||
{
|
||||
int64_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost64(value, mBigEndian);
|
||||
}
|
||||
uint64_t readUINT64()
|
||||
{
|
||||
uint64_t value = 0;
|
||||
read(value);
|
||||
return endian::networkToHost64(value, mBigEndian);
|
||||
}
|
||||
|
||||
private:
|
||||
// 为了避免直接read(uintXXX)导致没有指定字节序造成隐患BUG,因为此函数设置为私有
|
||||
template<typename T>
|
||||
void read(T& value)
|
||||
{
|
||||
static_assert(std::is_same<T, typename std::remove_pointer<T>::type>::value,
|
||||
"T must a normal type");
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"T must a pod type");
|
||||
|
||||
if ((mPos + sizeof(value)) > mSize)
|
||||
{
|
||||
throw std::out_of_range("T size is to big");
|
||||
}
|
||||
|
||||
value = *(T*) (mBuffer + mPos);
|
||||
mPos += sizeof(value);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mBigEndian;
|
||||
const size_t mSize;
|
||||
const char* mBuffer;
|
||||
size_t mPos;
|
||||
size_t mSavedPos;
|
||||
};
|
||||
|
||||
template<size_t SIZE>
|
||||
class AutoMallocPacket : public BasePacketWriter
|
||||
{
|
||||
public:
|
||||
explicit AutoMallocPacket(bool useBigEndian = false,
|
||||
bool isAutoMalloc = false)
|
||||
: BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc)
|
||||
{}
|
||||
|
||||
private:
|
||||
char mData[SIZE];
|
||||
};
|
||||
|
||||
using BigPacket = AutoMallocPacket<32 * 1024>;
|
||||
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,175 +1,169 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdbool>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include <brynet/base/Array.hpp>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
struct stack_s
|
||||
{
|
||||
struct array_s* array;
|
||||
size_t element_size;
|
||||
struct stack_s
|
||||
{
|
||||
struct array_s* array;
|
||||
size_t element_size;
|
||||
|
||||
size_t element_num;
|
||||
size_t front; /* 栈底 */
|
||||
size_t num; /* 栈有效元素大小 */
|
||||
};
|
||||
size_t element_num;
|
||||
size_t front;
|
||||
size_t num;
|
||||
};
|
||||
|
||||
static void stack_delete(struct stack_s* self)
|
||||
static void stack_delete(struct stack_s* self)
|
||||
{
|
||||
if (self == nullptr)
|
||||
{
|
||||
if (self == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->array != nullptr)
|
||||
{
|
||||
array_delete(self->array);
|
||||
self->array = nullptr;
|
||||
}
|
||||
|
||||
self->element_num = 0;
|
||||
self->front = 0;
|
||||
self->num = 0;
|
||||
free(self);
|
||||
self = nullptr;
|
||||
}
|
||||
|
||||
static struct stack_s* stack_new(size_t num, size_t element_size)
|
||||
{
|
||||
struct stack_s* ret = (struct stack_s*) malloc(sizeof(struct stack_s));
|
||||
if (ret == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret->element_size = 0;
|
||||
ret->element_num = 0;
|
||||
ret->front = 0;
|
||||
ret->num = 0;
|
||||
ret->array = array_new(num, element_size);
|
||||
|
||||
if (ret->array != nullptr)
|
||||
{
|
||||
ret->element_size = element_size;
|
||||
ret->element_num = num;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack_delete(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stack_init(struct stack_s* self)
|
||||
{
|
||||
self->front = 0;
|
||||
self->num = 0;
|
||||
}
|
||||
|
||||
static size_t stack_num(struct stack_s* self)
|
||||
{
|
||||
return self->num;
|
||||
}
|
||||
|
||||
static bool stack_increase(struct stack_s* self, size_t increase_num)
|
||||
{
|
||||
struct array_s* tmp = array_new(self->element_num + increase_num,
|
||||
self->element_size);
|
||||
if (tmp == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
size_t current_num = self->element_num;
|
||||
size_t current_stack_num = stack_num(self);
|
||||
for (size_t i = 0; i < current_stack_num; ++i)
|
||||
{
|
||||
return;
|
||||
array_set(tmp, i, array_at(self->array, (self->front + i) % current_num));
|
||||
}
|
||||
|
||||
if (self->array != nullptr)
|
||||
{
|
||||
array_delete(self->array);
|
||||
self->array = nullptr;
|
||||
}
|
||||
|
||||
self->element_num = 0;
|
||||
self->front = 0;
|
||||
self->num = 0;
|
||||
free(self);
|
||||
self = nullptr;
|
||||
array_delete(self->array);
|
||||
self->array = tmp;
|
||||
self->element_num = array_num(self->array);
|
||||
}
|
||||
|
||||
static struct stack_s* stack_new(size_t num, size_t element_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t stack_size(struct stack_s* self)
|
||||
{
|
||||
return self->element_num;
|
||||
}
|
||||
|
||||
static bool stack_isfull(struct stack_s* self)
|
||||
{
|
||||
return (self->num == self->element_num);
|
||||
}
|
||||
|
||||
static bool stack_push(struct stack_s* self, const void* data)
|
||||
{
|
||||
if (stack_isfull(self))
|
||||
{
|
||||
struct stack_s* ret = (struct stack_s*)malloc(sizeof(struct stack_s));
|
||||
if (ret == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret->element_size = 0;
|
||||
ret->element_num = 0;
|
||||
ret->front = 0;
|
||||
ret->num = 0;
|
||||
ret->array = array_new(num, element_size);
|
||||
|
||||
if (ret->array != nullptr)
|
||||
{
|
||||
ret->element_size = element_size;
|
||||
ret->element_num = num;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack_delete(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
stack_increase(self, stack_size(self));
|
||||
}
|
||||
|
||||
static void stack_init(struct stack_s* self)
|
||||
if (stack_isfull(self))
|
||||
{
|
||||
self->front = 0;
|
||||
self->num = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t stack_num(struct stack_s* self)
|
||||
array_set(self->array, (self->front + self->num) % self->element_num, data);
|
||||
self->num++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void* stack_front(struct stack_s* self)
|
||||
{
|
||||
void* ret = nullptr;
|
||||
|
||||
if (stack_num(self) > 0)
|
||||
{
|
||||
return self->num;
|
||||
ret = array_at(self->array, self->front);
|
||||
}
|
||||
|
||||
static bool stack_increase(struct stack_s* self, size_t increase_num)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* stack_popfront(struct stack_s* self)
|
||||
{
|
||||
void* ret = stack_front(self);
|
||||
|
||||
if (ret != nullptr)
|
||||
{
|
||||
struct array_s* tmp = array_new(self->element_num + increase_num,
|
||||
self->element_size);
|
||||
if (tmp == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
size_t current_num = self->element_num;
|
||||
size_t current_stack_num = stack_num(self);
|
||||
for (size_t i = 0; i < current_stack_num; ++i)
|
||||
{
|
||||
array_set(tmp, i, array_at(self->array, (self->front + i) % current_num));
|
||||
}
|
||||
|
||||
self->front = 0;
|
||||
array_delete(self->array);
|
||||
self->array = tmp;
|
||||
self->element_num = array_num(self->array);
|
||||
}
|
||||
|
||||
return true;
|
||||
self->num--;
|
||||
self->front++;
|
||||
self->front %= self->element_num;
|
||||
}
|
||||
|
||||
static size_t stack_size(struct stack_s* self)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* stack_popback(struct stack_s* self)
|
||||
{
|
||||
void* ret = nullptr;
|
||||
|
||||
if (stack_num(self) > 0)
|
||||
{
|
||||
return self->element_num;
|
||||
self->num--;
|
||||
ret = array_at(self->array, (self->front + self->num) % self->element_num);
|
||||
}
|
||||
|
||||
static bool stack_isfull(struct stack_s* self)
|
||||
{
|
||||
return (self->num == self->element_num);
|
||||
}
|
||||
|
||||
/* stack的stack_push会在空间不足的时候自动增长(通过stack_increase) */
|
||||
static bool stack_push(struct stack_s* self, const void* data)
|
||||
{
|
||||
if (stack_isfull(self))
|
||||
{
|
||||
stack_increase(self, stack_size(self));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (stack_isfull(self))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
array_set(self->array, (self->front + self->num) % self->element_num, data);
|
||||
self->num++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void* stack_front(struct stack_s* self)
|
||||
{
|
||||
void* ret = nullptr;
|
||||
|
||||
if (stack_num(self) > 0)
|
||||
{
|
||||
ret = array_at(self->array, self->front);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* stack_popfront(struct stack_s* self)
|
||||
{
|
||||
void* ret = stack_front(self);
|
||||
|
||||
if (ret != nullptr)
|
||||
{
|
||||
self->num--;
|
||||
self->front++;
|
||||
self->front %= self->element_num;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* stack_popback(struct stack_s* self)
|
||||
{
|
||||
void* ret = nullptr;
|
||||
|
||||
if (stack_num(self) > 0)
|
||||
{
|
||||
self->num--;
|
||||
ret = array_at(self->array, (self->front + self->num) % self->element_num);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} }
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,167 +1,165 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
class TimerMgr;
|
||||
class TimerMgr;
|
||||
|
||||
class Timer final
|
||||
class Timer final
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<Timer>;
|
||||
using WeakPtr = std::weak_ptr<Timer>;
|
||||
using Callback = std::function<void(void)>;
|
||||
|
||||
Timer(std::chrono::steady_clock::time_point startTime,
|
||||
std::chrono::nanoseconds lastTime,
|
||||
Callback&& callback) BRYNET_NOEXCEPT
|
||||
: mCallback(std::move(callback)),
|
||||
mStartTime(startTime),
|
||||
mLastTime(lastTime)
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<Timer>;
|
||||
using WeakPtr = std::weak_ptr<Timer>;
|
||||
using Callback = std::function<void(void)>;
|
||||
}
|
||||
|
||||
Timer(std::chrono::steady_clock::time_point startTime,
|
||||
std::chrono::nanoseconds lastTime,
|
||||
Callback&& callback) BRYNET_NOEXCEPT
|
||||
:
|
||||
mCallback(std::move(callback)),
|
||||
mStartTime(startTime),
|
||||
mLastTime(lastTime)
|
||||
{
|
||||
}
|
||||
|
||||
const std::chrono::steady_clock::time_point& getStartTime() const
|
||||
{
|
||||
return mStartTime;
|
||||
}
|
||||
|
||||
const std::chrono::nanoseconds& getLastTime() const
|
||||
{
|
||||
return mLastTime;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds getLeftTime() const
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
return getLastTime() - (now - getStartTime());
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
std::call_once(mExecuteOnceFlag, [this]() {
|
||||
mCallback = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void operator() ()
|
||||
{
|
||||
Callback callback;
|
||||
std::call_once(mExecuteOnceFlag, [&callback, this]() {
|
||||
callback = std::move(mCallback);
|
||||
mCallback = nullptr;
|
||||
});
|
||||
|
||||
if (callback != nullptr)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::once_flag mExecuteOnceFlag;
|
||||
Callback mCallback;
|
||||
const std::chrono::steady_clock::time_point mStartTime;
|
||||
const std::chrono::nanoseconds mLastTime;
|
||||
|
||||
friend class TimerMgr;
|
||||
};
|
||||
|
||||
class TimerMgr final
|
||||
const std::chrono::steady_clock::time_point& getStartTime() const
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<TimerMgr>;
|
||||
return mStartTime;
|
||||
}
|
||||
|
||||
template<typename F, typename ...TArgs>
|
||||
Timer::WeakPtr addTimer(
|
||||
const std::chrono::nanoseconds& getLastTime() const
|
||||
{
|
||||
return mLastTime;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds getLeftTime() const
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
return getLastTime() - (now - getStartTime());
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
std::call_once(mExecuteOnceFlag, [this]() {
|
||||
mCallback = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void operator()()
|
||||
{
|
||||
Callback callback;
|
||||
std::call_once(mExecuteOnceFlag, [&callback, this]() {
|
||||
callback = std::move(mCallback);
|
||||
mCallback = nullptr;
|
||||
});
|
||||
|
||||
if (callback != nullptr)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::once_flag mExecuteOnceFlag;
|
||||
Callback mCallback;
|
||||
const std::chrono::steady_clock::time_point mStartTime;
|
||||
const std::chrono::nanoseconds mLastTime;
|
||||
|
||||
friend class TimerMgr;
|
||||
};
|
||||
|
||||
class TimerMgr final
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<TimerMgr>;
|
||||
|
||||
template<typename F, typename... TArgs>
|
||||
Timer::WeakPtr addTimer(
|
||||
std::chrono::nanoseconds timeout,
|
||||
F&& callback,
|
||||
TArgs&& ...args)
|
||||
{
|
||||
auto timer = std::make_shared<Timer>(
|
||||
F&& callback,
|
||||
TArgs&&... args)
|
||||
{
|
||||
auto timer = std::make_shared<Timer>(
|
||||
std::chrono::steady_clock::now(),
|
||||
std::chrono::nanoseconds(timeout),
|
||||
std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...));
|
||||
mTimers.push(timer);
|
||||
mTimers.push(timer);
|
||||
|
||||
return timer;
|
||||
}
|
||||
return timer;
|
||||
}
|
||||
|
||||
void addTimer(const Timer::Ptr& timer)
|
||||
void addTimer(const Timer::Ptr& timer)
|
||||
{
|
||||
mTimers.push(timer);
|
||||
}
|
||||
|
||||
void schedule()
|
||||
{
|
||||
while (!mTimers.empty())
|
||||
{
|
||||
mTimers.push(timer);
|
||||
}
|
||||
|
||||
void schedule()
|
||||
{
|
||||
while (!mTimers.empty())
|
||||
auto tmp = mTimers.top();
|
||||
if (tmp->getLeftTime() > std::chrono::nanoseconds::zero())
|
||||
{
|
||||
auto tmp = mTimers.top();
|
||||
if (tmp->getLeftTime() > std::chrono::nanoseconds::zero())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
mTimers.pop();
|
||||
(*tmp)();
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return mTimers.empty();
|
||||
}
|
||||
|
||||
// if timer empty, return zero
|
||||
std::chrono::nanoseconds nearLeftTime() const
|
||||
{
|
||||
if (mTimers.empty())
|
||||
{
|
||||
return std::chrono::nanoseconds::zero();
|
||||
break;
|
||||
}
|
||||
|
||||
auto result = mTimers.top()->getLeftTime();
|
||||
if (result < std::chrono::nanoseconds::zero())
|
||||
{
|
||||
return std::chrono::nanoseconds::zero();
|
||||
}
|
||||
mTimers.pop();
|
||||
(*tmp)();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
bool isEmpty() const
|
||||
{
|
||||
return mTimers.empty();
|
||||
}
|
||||
|
||||
// if timer empty, return zero
|
||||
std::chrono::nanoseconds nearLeftTime() const
|
||||
{
|
||||
if (mTimers.empty())
|
||||
{
|
||||
return std::chrono::nanoseconds::zero();
|
||||
}
|
||||
|
||||
void clear()
|
||||
auto result = mTimers.top()->getLeftTime();
|
||||
if (result < std::chrono::nanoseconds::zero())
|
||||
{
|
||||
while (!mTimers.empty())
|
||||
{
|
||||
mTimers.pop();
|
||||
}
|
||||
return std::chrono::nanoseconds::zero();
|
||||
}
|
||||
|
||||
private:
|
||||
class CompareTimer
|
||||
{
|
||||
public:
|
||||
bool operator() (const Timer::Ptr& left,
|
||||
const Timer::Ptr& right) const
|
||||
{
|
||||
const auto startDiff = left->getStartTime() - right->getStartTime();
|
||||
const auto lastDiff = left->getLastTime() - right->getLastTime();
|
||||
const auto diff = startDiff.count() + lastDiff.count();
|
||||
return diff > 0;
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
std::priority_queue<Timer::Ptr, std::vector<Timer::Ptr>, CompareTimer> mTimers;
|
||||
void clear()
|
||||
{
|
||||
while (!mTimers.empty())
|
||||
{
|
||||
mTimers.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class CompareTimer
|
||||
{
|
||||
public:
|
||||
bool operator()(const Timer::Ptr& left,
|
||||
const Timer::Ptr& right) const
|
||||
{
|
||||
const auto startDiff = left->getStartTime() - right->getStartTime();
|
||||
const auto lastDiff = left->getLastTime() - right->getLastTime();
|
||||
const auto diff = startDiff.count() + lastDiff.count();
|
||||
return diff > 0;
|
||||
}
|
||||
};
|
||||
|
||||
} }
|
||||
std::priority_queue<Timer::Ptr, std::vector<Timer::Ptr>, CompareTimer> mTimers;
|
||||
};
|
||||
|
||||
}}// namespace brynet::base
|
||||
|
@ -1,65 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
class WaitGroup : public NonCopyable
|
||||
class WaitGroup : public NonCopyable
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<WaitGroup> Ptr;
|
||||
|
||||
static Ptr Create()
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<WaitGroup> Ptr;
|
||||
|
||||
static Ptr Create()
|
||||
struct make_shared_enabler : public WaitGroup
|
||||
{
|
||||
struct make_shared_enabler : public WaitGroup {};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
|
||||
public:
|
||||
void add(int i = 1)
|
||||
{
|
||||
mCounter += i;
|
||||
}
|
||||
public:
|
||||
void add(int i = 1)
|
||||
{
|
||||
mCounter += i;
|
||||
}
|
||||
|
||||
void done()
|
||||
{
|
||||
mCounter--;
|
||||
mCond.notify_all();
|
||||
}
|
||||
void done()
|
||||
{
|
||||
mCounter--;
|
||||
mCond.notify_all();
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mMutex);
|
||||
mCond.wait(l, [&] { return mCounter <= 0; });
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mMutex);
|
||||
mCond.wait(l, [&] {
|
||||
return mCounter <= 0;
|
||||
});
|
||||
}
|
||||
|
||||
template<class Rep, class Period>
|
||||
void wait(const std::chrono::duration<Rep, Period>& timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mMutex);
|
||||
mCond.wait_for(l, timeout, [&] {
|
||||
return mCounter <= 0;
|
||||
});
|
||||
}
|
||||
template<class Rep, class Period>
|
||||
void wait(const std::chrono::duration<Rep, Period>& timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mMutex);
|
||||
mCond.wait_for(l, timeout, [&] {
|
||||
return mCounter <= 0;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
WaitGroup()
|
||||
:
|
||||
mCounter(0)
|
||||
{
|
||||
}
|
||||
private:
|
||||
WaitGroup()
|
||||
: mCounter(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~WaitGroup() = default;
|
||||
virtual ~WaitGroup() = default;
|
||||
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
std::atomic<int> mCounter;
|
||||
std::condition_variable mCond;
|
||||
};
|
||||
} }
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
std::atomic<int> mCounter;
|
||||
std::condition_variable mCond;
|
||||
};
|
||||
}}// namespace brynet::base
|
||||
|
@ -5,101 +5,106 @@
|
||||
|
||||
namespace brynet { namespace base { namespace crypto {
|
||||
|
||||
static const std::string base64_chars =
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
static bool is_base64(unsigned char c)
|
||||
static bool is_base64(unsigned char c)
|
||||
{
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
|
||||
{
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--)
|
||||
{
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
|
||||
{
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (i = 0; (i < 4); i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3)
|
||||
{
|
||||
for (j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while ((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
for (i = 0; (i < 4); i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::string base64_decode(std::string const& encoded_string)
|
||||
if (i)
|
||||
{
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
for (j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i == 4) {
|
||||
for (i = 0; i < 4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
while ((i++ < 3))
|
||||
ret += '=';
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 4; j++)
|
||||
char_array_4[j] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
static std::string base64_decode(std::string const& encoded_string)
|
||||
{
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
|
||||
{
|
||||
char_array_4[i++] = encoded_string[in_];
|
||||
in_++;
|
||||
if (i == 4)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} } }
|
||||
if (i)
|
||||
{
|
||||
for (j = i; j < 4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}}}// namespace brynet::base::crypto
|
||||
|
||||
#endif
|
@ -116,8 +116,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <memory.h>
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
#include <stdio.h>
|
||||
@ -174,48 +174,47 @@
|
||||
// Define variable types
|
||||
|
||||
#ifndef UINT_8
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#ifdef _MSC_VER// Compiling with Microsoft compiler
|
||||
#define UINT_8 unsigned __int8
|
||||
#else // !_MSC_VER
|
||||
#else// !_MSC_VER
|
||||
#define UINT_8 unsigned char
|
||||
#endif // _MSC_VER
|
||||
#endif// _MSC_VER
|
||||
#endif
|
||||
|
||||
#ifndef UINT_32
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#ifdef _MSC_VER// Compiling with Microsoft compiler
|
||||
#define UINT_32 unsigned __int32
|
||||
#else // !_MSC_VER
|
||||
#else// !_MSC_VER
|
||||
#if (ULONG_MAX == 0xFFFFFFFFUL)
|
||||
#define UINT_32 unsigned long
|
||||
#else
|
||||
#define UINT_32 unsigned int
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
#endif // UINT_32
|
||||
#endif// _MSC_VER
|
||||
#endif// UINT_32
|
||||
|
||||
#ifndef INT_64
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#ifdef _MSC_VER// Compiling with Microsoft compiler
|
||||
#define INT_64 __int64
|
||||
#else // !_MSC_VER
|
||||
#else// !_MSC_VER
|
||||
#define INT_64 long long
|
||||
#endif // _MSC_VER
|
||||
#endif // INT_64
|
||||
#endif// _MSC_VER
|
||||
#endif// INT_64
|
||||
|
||||
#ifndef UINT_64
|
||||
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||
#ifdef _MSC_VER// Compiling with Microsoft compiler
|
||||
#define UINT_64 unsigned __int64
|
||||
#else // !_MSC_VER
|
||||
#else// !_MSC_VER
|
||||
#define UINT_64 unsigned long long
|
||||
#endif // _MSC_VER
|
||||
#endif // UINT_64
|
||||
#endif// _MSC_VER
|
||||
#endif// UINT_64
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Declare SHA-1 workspace
|
||||
|
||||
typedef union
|
||||
{
|
||||
UINT_8 c[64];
|
||||
UINT_32 l[16];
|
||||
typedef union {
|
||||
UINT_8 c[64];
|
||||
UINT_32 l[16];
|
||||
} SHA1_WORKSPACE_BLOCK;
|
||||
|
||||
|
||||
@ -224,49 +223,70 @@ typedef union
|
||||
// Rotate p_val32 by p_nBits bits to the left
|
||||
#ifndef ROL32
|
||||
#ifdef _MSC_VER
|
||||
#define ROL32(p_val32,p_nBits) _rotl(p_val32,p_nBits)
|
||||
#define ROL32(p_val32, p_nBits) _rotl(p_val32, p_nBits)
|
||||
#else
|
||||
#define ROL32(p_val32,p_nBits) (((p_val32)<<(p_nBits))|((p_val32)>>(32-(p_nBits))))
|
||||
#define ROL32(p_val32, p_nBits) (((p_val32) << (p_nBits)) | ((p_val32) >> (32 - (p_nBits))))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_LITTLE_ENDIAN
|
||||
#define SHABLK0(i) (m_block->l[i] = \
|
||||
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
|
||||
(ROL32(m_block->l[i], 24) & 0xFF00FF00) | (ROL32(m_block->l[i], 8) & 0x00FF00FF))
|
||||
#else
|
||||
#define SHABLK0(i) (m_block->l[i])
|
||||
#endif
|
||||
|
||||
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ \
|
||||
m_block->l[(i+8)&15] ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
|
||||
#define SHABLK(i) (m_block->l[i & 15] = ROL32(m_block->l[(i + 13) & 15] ^ \
|
||||
m_block->l[(i + 8) & 15] ^ m_block->l[(i + 2) & 15] ^ m_block->l[i & 15], \
|
||||
1))
|
||||
|
||||
// SHA-1 rounds
|
||||
#define S_R0(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);}
|
||||
#define S_R1(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);}
|
||||
#define S_R2(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5);w=ROL32(w,30);}
|
||||
#define S_R3(v,w,x,y,z,i) {z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5);w=ROL32(w,30);}
|
||||
#define S_R4(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5);w=ROL32(w,30);}
|
||||
#define S_R0(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += ((w & (x ^ y)) ^ y) + SHABLK0(i) + 0x5A827999 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define S_R1(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += ((w & (x ^ y)) ^ y) + SHABLK(i) + 0x5A827999 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define S_R2(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += (w ^ x ^ y) + SHABLK(i) + 0x6ED9EBA1 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define S_R3(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += (((w | x) & y) | (w & x)) + SHABLK(i) + 0x8F1BBCDC + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define S_R4(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += (w ^ x ^ y) + SHABLK(i) + 0xCA62C1D6 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
|
||||
|
||||
class CSHA1
|
||||
{
|
||||
public:
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Different formats for ReportHash(Stl)
|
||||
enum REPORT_TYPE
|
||||
{
|
||||
REPORT_HEX = 0,
|
||||
REPORT_DIGIT = 1,
|
||||
REPORT_HEX_SHORT = 2
|
||||
};
|
||||
// Different formats for ReportHash(Stl)
|
||||
enum REPORT_TYPE
|
||||
{
|
||||
REPORT_HEX = 0,
|
||||
REPORT_DIGIT = 1,
|
||||
REPORT_HEX_SHORT = 2
|
||||
};
|
||||
#endif
|
||||
|
||||
// Constructor and destructor
|
||||
// Constructor and destructor
|
||||
CSHA1()
|
||||
{
|
||||
(void)m_reserved0;
|
||||
(void)m_reserved1;
|
||||
m_block = (SHA1_WORKSPACE_BLOCK*)m_workspace;
|
||||
(void) m_reserved0;
|
||||
(void) m_reserved1;
|
||||
m_block = (SHA1_WORKSPACE_BLOCK*) m_workspace;
|
||||
|
||||
Reset();
|
||||
}
|
||||
@ -291,13 +311,13 @@ public:
|
||||
m_count[1] = 0;
|
||||
}
|
||||
|
||||
// Hash in binary data and strings
|
||||
// Hash in binary data and strings
|
||||
void Update(const UINT_8* pbData, UINT_32 uLen)
|
||||
{
|
||||
UINT_32 j = ((m_count[0] >> 3) & 0x3F);
|
||||
|
||||
if ((m_count[0] += (uLen << 3)) < (uLen << 3))
|
||||
++m_count[1]; // Overflow
|
||||
++m_count[1];// Overflow
|
||||
|
||||
m_count[1] += (uLen >> 29);
|
||||
|
||||
@ -313,23 +333,30 @@ public:
|
||||
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
else
|
||||
i = 0;
|
||||
|
||||
if ((uLen - i) != 0)
|
||||
memcpy(&m_buffer[j], &pbData[i], uLen - i);
|
||||
}
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Hash in file contents
|
||||
// Hash in file contents
|
||||
bool HashFile(const TCHAR* tszFileName)
|
||||
{
|
||||
if (tszFileName == NULL) return false;
|
||||
if (tszFileName == NULL)
|
||||
return false;
|
||||
|
||||
FILE* fpIn = _tfopen(tszFileName, _T("rb"));
|
||||
if (fpIn == NULL) return false;
|
||||
if (fpIn == NULL)
|
||||
return false;
|
||||
|
||||
UINT_8* pbData = new UINT_8[SHA1_MAX_FILE_BUFFER];
|
||||
if (pbData == NULL) { fclose(fpIn); return false; }
|
||||
if (pbData == NULL)
|
||||
{
|
||||
fclose(fpIn);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bSuccess = true;
|
||||
while (true)
|
||||
@ -341,7 +368,8 @@ public:
|
||||
|
||||
if (uRead < SHA1_MAX_FILE_BUFFER)
|
||||
{
|
||||
if (feof(fpIn) == 0) bSuccess = false;
|
||||
if (feof(fpIn) == 0)
|
||||
bSuccess = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -352,7 +380,7 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finalize hash; call it before using ReportHash(Stl)
|
||||
// Finalize hash; call it before using ReportHash(Stl)
|
||||
void Final()
|
||||
{
|
||||
UINT_32 i;
|
||||
@ -360,20 +388,23 @@ public:
|
||||
UINT_8 pbFinalCount[8];
|
||||
for (i = 0; i < 8; ++i)
|
||||
pbFinalCount[i] = static_cast<UINT_8>((m_count[((i >= 4) ? 0 : 1)] >>
|
||||
((3 - (i & 3)) * 8)) & 0xFF); // Endian independent
|
||||
((3 - (i & 3)) * 8)) &
|
||||
0xFF);// Endian independent
|
||||
|
||||
Update((UINT_8*)"\200", 1);
|
||||
Update((UINT_8*) "\200", 1);
|
||||
|
||||
while ((m_count[0] & 504) != 448)
|
||||
Update((UINT_8*)"\0", 1);
|
||||
Update((UINT_8*) "\0", 1);
|
||||
|
||||
Update(pbFinalCount, 8); // Cause a Transform()
|
||||
Update(pbFinalCount, 8);// Cause a Transform()
|
||||
|
||||
for (i = 0; i < 20; ++i)
|
||||
m_digest[i] = static_cast<UINT_8>((m_state[i >> 2] >> ((3 -
|
||||
(i & 3)) * 8)) & 0xFF);
|
||||
(i & 3)) *
|
||||
8)) &
|
||||
0xFF);
|
||||
|
||||
// Wipe variables for security reasons
|
||||
// Wipe variables for security reasons
|
||||
#ifdef SHA1_WIPE_VARIABLES
|
||||
memset(m_buffer, 0, 64);
|
||||
memset(m_state, 0, 20);
|
||||
@ -386,7 +417,8 @@ public:
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
bool ReportHash(TCHAR* tszReport, REPORT_TYPE rtReportType = REPORT_HEX) const
|
||||
{
|
||||
if (tszReport == NULL) return false;
|
||||
if (tszReport == NULL)
|
||||
return false;
|
||||
|
||||
TCHAR tszTemp[16];
|
||||
|
||||
@ -413,7 +445,8 @@ public:
|
||||
_tcscat(tszReport, tszTemp);
|
||||
}
|
||||
}
|
||||
else return false;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -421,25 +454,27 @@ public:
|
||||
|
||||
#ifdef SHA1_STL_FUNCTIONS
|
||||
bool ReportHashStl(std::basic_string<TCHAR>& strOut, REPORT_TYPE rtReportType =
|
||||
REPORT_HEX) const
|
||||
REPORT_HEX) const
|
||||
{
|
||||
TCHAR tszOut[84];
|
||||
const bool bResult = ReportHash(tszOut, rtReportType);
|
||||
if (bResult) strOut = tszOut;
|
||||
if (bResult)
|
||||
strOut = tszOut;
|
||||
return bResult;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the raw message digest (20 bytes)
|
||||
// Get the raw message digest (20 bytes)
|
||||
bool GetHash(UINT_8* pbDest20) const
|
||||
{
|
||||
if (pbDest20 == NULL) return false;
|
||||
if (pbDest20 == NULL)
|
||||
return false;
|
||||
memcpy(pbDest20, m_digest, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Private SHA-1 transformation
|
||||
// Private SHA-1 transformation
|
||||
void Transform(UINT_32* pState, const UINT_8* pBuffer)
|
||||
{
|
||||
UINT_32 a = pState[0], b = pState[1], c = pState[2], d = pState[3], e = pState[4];
|
||||
@ -447,26 +482,86 @@ private:
|
||||
memcpy(m_block, pBuffer, 64);
|
||||
|
||||
// 4 rounds of 20 operations each, loop unrolled
|
||||
S_R0(a, b, c, d, e, 0); S_R0(e, a, b, c, d, 1); S_R0(d, e, a, b, c, 2); S_R0(c, d, e, a, b, 3);
|
||||
S_R0(b, c, d, e, a, 4); S_R0(a, b, c, d, e, 5); S_R0(e, a, b, c, d, 6); S_R0(d, e, a, b, c, 7);
|
||||
S_R0(c, d, e, a, b, 8); S_R0(b, c, d, e, a, 9); S_R0(a, b, c, d, e, 10); S_R0(e, a, b, c, d, 11);
|
||||
S_R0(d, e, a, b, c, 12); S_R0(c, d, e, a, b, 13); S_R0(b, c, d, e, a, 14); S_R0(a, b, c, d, e, 15);
|
||||
S_R1(e, a, b, c, d, 16); S_R1(d, e, a, b, c, 17); S_R1(c, d, e, a, b, 18); S_R1(b, c, d, e, a, 19);
|
||||
S_R2(a, b, c, d, e, 20); S_R2(e, a, b, c, d, 21); S_R2(d, e, a, b, c, 22); S_R2(c, d, e, a, b, 23);
|
||||
S_R2(b, c, d, e, a, 24); S_R2(a, b, c, d, e, 25); S_R2(e, a, b, c, d, 26); S_R2(d, e, a, b, c, 27);
|
||||
S_R2(c, d, e, a, b, 28); S_R2(b, c, d, e, a, 29); S_R2(a, b, c, d, e, 30); S_R2(e, a, b, c, d, 31);
|
||||
S_R2(d, e, a, b, c, 32); S_R2(c, d, e, a, b, 33); S_R2(b, c, d, e, a, 34); S_R2(a, b, c, d, e, 35);
|
||||
S_R2(e, a, b, c, d, 36); S_R2(d, e, a, b, c, 37); S_R2(c, d, e, a, b, 38); S_R2(b, c, d, e, a, 39);
|
||||
S_R3(a, b, c, d, e, 40); S_R3(e, a, b, c, d, 41); S_R3(d, e, a, b, c, 42); S_R3(c, d, e, a, b, 43);
|
||||
S_R3(b, c, d, e, a, 44); S_R3(a, b, c, d, e, 45); S_R3(e, a, b, c, d, 46); S_R3(d, e, a, b, c, 47);
|
||||
S_R3(c, d, e, a, b, 48); S_R3(b, c, d, e, a, 49); S_R3(a, b, c, d, e, 50); S_R3(e, a, b, c, d, 51);
|
||||
S_R3(d, e, a, b, c, 52); S_R3(c, d, e, a, b, 53); S_R3(b, c, d, e, a, 54); S_R3(a, b, c, d, e, 55);
|
||||
S_R3(e, a, b, c, d, 56); S_R3(d, e, a, b, c, 57); S_R3(c, d, e, a, b, 58); S_R3(b, c, d, e, a, 59);
|
||||
S_R4(a, b, c, d, e, 60); S_R4(e, a, b, c, d, 61); S_R4(d, e, a, b, c, 62); S_R4(c, d, e, a, b, 63);
|
||||
S_R4(b, c, d, e, a, 64); S_R4(a, b, c, d, e, 65); S_R4(e, a, b, c, d, 66); S_R4(d, e, a, b, c, 67);
|
||||
S_R4(c, d, e, a, b, 68); S_R4(b, c, d, e, a, 69); S_R4(a, b, c, d, e, 70); S_R4(e, a, b, c, d, 71);
|
||||
S_R4(d, e, a, b, c, 72); S_R4(c, d, e, a, b, 73); S_R4(b, c, d, e, a, 74); S_R4(a, b, c, d, e, 75);
|
||||
S_R4(e, a, b, c, d, 76); S_R4(d, e, a, b, c, 77); S_R4(c, d, e, a, b, 78); S_R4(b, c, d, e, a, 79);
|
||||
S_R0(a, b, c, d, e, 0);
|
||||
S_R0(e, a, b, c, d, 1);
|
||||
S_R0(d, e, a, b, c, 2);
|
||||
S_R0(c, d, e, a, b, 3);
|
||||
S_R0(b, c, d, e, a, 4);
|
||||
S_R0(a, b, c, d, e, 5);
|
||||
S_R0(e, a, b, c, d, 6);
|
||||
S_R0(d, e, a, b, c, 7);
|
||||
S_R0(c, d, e, a, b, 8);
|
||||
S_R0(b, c, d, e, a, 9);
|
||||
S_R0(a, b, c, d, e, 10);
|
||||
S_R0(e, a, b, c, d, 11);
|
||||
S_R0(d, e, a, b, c, 12);
|
||||
S_R0(c, d, e, a, b, 13);
|
||||
S_R0(b, c, d, e, a, 14);
|
||||
S_R0(a, b, c, d, e, 15);
|
||||
S_R1(e, a, b, c, d, 16);
|
||||
S_R1(d, e, a, b, c, 17);
|
||||
S_R1(c, d, e, a, b, 18);
|
||||
S_R1(b, c, d, e, a, 19);
|
||||
S_R2(a, b, c, d, e, 20);
|
||||
S_R2(e, a, b, c, d, 21);
|
||||
S_R2(d, e, a, b, c, 22);
|
||||
S_R2(c, d, e, a, b, 23);
|
||||
S_R2(b, c, d, e, a, 24);
|
||||
S_R2(a, b, c, d, e, 25);
|
||||
S_R2(e, a, b, c, d, 26);
|
||||
S_R2(d, e, a, b, c, 27);
|
||||
S_R2(c, d, e, a, b, 28);
|
||||
S_R2(b, c, d, e, a, 29);
|
||||
S_R2(a, b, c, d, e, 30);
|
||||
S_R2(e, a, b, c, d, 31);
|
||||
S_R2(d, e, a, b, c, 32);
|
||||
S_R2(c, d, e, a, b, 33);
|
||||
S_R2(b, c, d, e, a, 34);
|
||||
S_R2(a, b, c, d, e, 35);
|
||||
S_R2(e, a, b, c, d, 36);
|
||||
S_R2(d, e, a, b, c, 37);
|
||||
S_R2(c, d, e, a, b, 38);
|
||||
S_R2(b, c, d, e, a, 39);
|
||||
S_R3(a, b, c, d, e, 40);
|
||||
S_R3(e, a, b, c, d, 41);
|
||||
S_R3(d, e, a, b, c, 42);
|
||||
S_R3(c, d, e, a, b, 43);
|
||||
S_R3(b, c, d, e, a, 44);
|
||||
S_R3(a, b, c, d, e, 45);
|
||||
S_R3(e, a, b, c, d, 46);
|
||||
S_R3(d, e, a, b, c, 47);
|
||||
S_R3(c, d, e, a, b, 48);
|
||||
S_R3(b, c, d, e, a, 49);
|
||||
S_R3(a, b, c, d, e, 50);
|
||||
S_R3(e, a, b, c, d, 51);
|
||||
S_R3(d, e, a, b, c, 52);
|
||||
S_R3(c, d, e, a, b, 53);
|
||||
S_R3(b, c, d, e, a, 54);
|
||||
S_R3(a, b, c, d, e, 55);
|
||||
S_R3(e, a, b, c, d, 56);
|
||||
S_R3(d, e, a, b, c, 57);
|
||||
S_R3(c, d, e, a, b, 58);
|
||||
S_R3(b, c, d, e, a, 59);
|
||||
S_R4(a, b, c, d, e, 60);
|
||||
S_R4(e, a, b, c, d, 61);
|
||||
S_R4(d, e, a, b, c, 62);
|
||||
S_R4(c, d, e, a, b, 63);
|
||||
S_R4(b, c, d, e, a, 64);
|
||||
S_R4(a, b, c, d, e, 65);
|
||||
S_R4(e, a, b, c, d, 66);
|
||||
S_R4(d, e, a, b, c, 67);
|
||||
S_R4(c, d, e, a, b, 68);
|
||||
S_R4(b, c, d, e, a, 69);
|
||||
S_R4(a, b, c, d, e, 70);
|
||||
S_R4(e, a, b, c, d, 71);
|
||||
S_R4(d, e, a, b, c, 72);
|
||||
S_R4(c, d, e, a, b, 73);
|
||||
S_R4(b, c, d, e, a, 74);
|
||||
S_R4(a, b, c, d, e, 75);
|
||||
S_R4(e, a, b, c, d, 76);
|
||||
S_R4(d, e, a, b, c, 77);
|
||||
S_R4(c, d, e, a, b, 78);
|
||||
S_R4(b, c, d, e, a, 79);
|
||||
|
||||
// Add the working vars back into state
|
||||
pState[0] += a;
|
||||
@ -481,16 +576,16 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
// Member variables
|
||||
UINT_32 m_state[5];
|
||||
UINT_32 m_count[2];
|
||||
UINT_32 m_reserved0[1]; // Memory alignment padding
|
||||
UINT_8 m_buffer[64];
|
||||
UINT_8 m_digest[20];
|
||||
UINT_32 m_reserved1[3]; // Memory alignment padding
|
||||
// Member variables
|
||||
UINT_32 m_state[5];
|
||||
UINT_32 m_count[2];
|
||||
UINT_32 m_reserved0[1];// Memory alignment padding
|
||||
UINT_8 m_buffer[64];
|
||||
UINT_8 m_digest[20];
|
||||
UINT_32 m_reserved1[3];// Memory alignment padding
|
||||
|
||||
UINT_8 m_workspace[64];
|
||||
SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above
|
||||
UINT_8 m_workspace[64];
|
||||
SHA1_WORKSPACE_BLOCK* m_block;// SHA1 pointer to the byte array above
|
||||
};
|
||||
|
||||
#endif // SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||
#endif// SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||
|
@ -1,12 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdbool>
|
||||
#include <cstring>
|
||||
|
||||
#include <brynet/net/SocketLibTypes.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdbool>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef BRYNET_PLATFORM_LINUX
|
||||
#include <endian.h>
|
||||
@ -16,125 +14,125 @@
|
||||
|
||||
namespace brynet { namespace base { namespace endian {
|
||||
|
||||
inline uint64_t hl64ton(uint64_t hostValue)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint32_t high, low;
|
||||
inline uint64_t hl64ton(uint64_t hostValue)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint32_t high, low;
|
||||
|
||||
low = hostValue & 0xFFFFFFFF;
|
||||
high = (hostValue >> 32) & 0xFFFFFFFF;
|
||||
low = htonl(low);
|
||||
high = htonl(high);
|
||||
ret = low;
|
||||
ret <<= 32;
|
||||
ret |= high;
|
||||
low = hostValue & 0xFFFFFFFF;
|
||||
high = (hostValue >> 32) & 0xFFFFFFFF;
|
||||
low = htonl(low);
|
||||
high = htonl(high);
|
||||
ret = low;
|
||||
ret <<= 32;
|
||||
ret |= high;
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline uint64_t ntohl64(uint64_t netValue)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint32_t high, low;
|
||||
inline uint64_t ntohl64(uint64_t netValue)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint32_t high, low;
|
||||
|
||||
low = netValue & 0xFFFFFFFF;
|
||||
high = (netValue >> 32) & 0xFFFFFFFF;
|
||||
low = ntohl(low);
|
||||
high = ntohl(high);
|
||||
ret = low;
|
||||
ret <<= 32;
|
||||
ret |= high;
|
||||
low = netValue & 0xFFFFFFFF;
|
||||
high = (netValue >> 32) & 0xFFFFFFFF;
|
||||
low = ntohl(low);
|
||||
high = ntohl(high);
|
||||
ret = low;
|
||||
ret <<= 32;
|
||||
ret |= high;
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||
{
|
||||
return convert ? hl64ton(host64) : host64;
|
||||
}
|
||||
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||
{
|
||||
return convert ? htonl(host32) : host32;
|
||||
}
|
||||
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||
{
|
||||
return convert ? hl64ton(host64) : host64;
|
||||
}
|
||||
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||
{
|
||||
return convert ? htonl(host32) : host32;
|
||||
}
|
||||
|
||||
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||
{
|
||||
return convert ? htons(host16) : host16;
|
||||
}
|
||||
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||
{
|
||||
return convert ? htons(host16) : host16;
|
||||
}
|
||||
|
||||
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl64(net64) : net64;
|
||||
}
|
||||
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl64(net64) : net64;
|
||||
}
|
||||
|
||||
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl(net32) : net32;
|
||||
}
|
||||
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl(net32) : net32;
|
||||
}
|
||||
|
||||
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||
{
|
||||
return convert ? ntohs(net16) : net16;
|
||||
}
|
||||
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||
{
|
||||
return convert ? ntohs(net16) : net16;
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||
{
|
||||
return convert ? htobe64(host64) : host64;
|
||||
}
|
||||
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||
{
|
||||
return convert ? htobe32(host32) : host32;
|
||||
}
|
||||
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||
{
|
||||
return convert ? htobe64(host64) : host64;
|
||||
}
|
||||
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||
{
|
||||
return convert ? htobe32(host32) : host32;
|
||||
}
|
||||
|
||||
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||
{
|
||||
return convert ? htobe16(host16) : host16;
|
||||
}
|
||||
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||
{
|
||||
return convert ? htobe16(host16) : host16;
|
||||
}
|
||||
|
||||
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||
{
|
||||
return convert ? be64toh(net64) : net64;
|
||||
}
|
||||
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||
{
|
||||
return convert ? be64toh(net64) : net64;
|
||||
}
|
||||
|
||||
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||
{
|
||||
return convert ? be32toh(net32) : net32;
|
||||
}
|
||||
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||
{
|
||||
return convert ? be32toh(net32) : net32;
|
||||
}
|
||||
|
||||
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||
{
|
||||
return convert ? be16toh(net16) : net16;
|
||||
}
|
||||
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||
{
|
||||
return convert ? be16toh(net16) : net16;
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||
{
|
||||
return convert ? hl64ton(host64) : host64;
|
||||
}
|
||||
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||
{
|
||||
return convert ? htonl(host32) : host32;
|
||||
}
|
||||
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||
{
|
||||
return convert ? hl64ton(host64) : host64;
|
||||
}
|
||||
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||
{
|
||||
return convert ? htonl(host32) : host32;
|
||||
}
|
||||
|
||||
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||
{
|
||||
return convert ? htons(host16) : host16;
|
||||
}
|
||||
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||
{
|
||||
return convert ? htons(host16) : host16;
|
||||
}
|
||||
|
||||
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl64(net64) : net64;
|
||||
}
|
||||
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl64(net64) : net64;
|
||||
}
|
||||
|
||||
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl(net32) : net32;
|
||||
}
|
||||
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||
{
|
||||
return convert ? ntohl(net32) : net32;
|
||||
}
|
||||
|
||||
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||
{
|
||||
return convert ? ntohs(net16) : net16;
|
||||
}
|
||||
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||
{
|
||||
return convert ? ntohs(net16) : net16;
|
||||
}
|
||||
#endif
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::base::endian
|
@ -4,86 +4,38 @@
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class ConnectOption final
|
||||
using ConnectOption = detail::ConnectOption;
|
||||
class AsyncConnector : public detail::AsyncConnectorDetail,
|
||||
public std::enable_shared_from_this<AsyncConnector>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<AsyncConnector>;
|
||||
|
||||
void startWorkerThread()
|
||||
{
|
||||
public:
|
||||
using CompletedCallback = std::function<void(TcpSocket::Ptr)>;
|
||||
using ProcessTcpSocketCallback = std::function<void(TcpSocket&)>;
|
||||
using FailedCallback = std::function<void()>;
|
||||
using ConnectOptionFunc = detail::ConnectOptionFunc;
|
||||
detail::AsyncConnectorDetail::startWorkerThread();
|
||||
}
|
||||
|
||||
static ConnectOptionFunc WithAddr(const std::string& ip, int port)
|
||||
{
|
||||
return [ip, port](detail::ConnectOptionsInfo& option) {
|
||||
option.ip = ip;
|
||||
option.port = port;
|
||||
};
|
||||
}
|
||||
static ConnectOptionFunc WithTimeout(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
return [timeout](detail::ConnectOptionsInfo& option) {
|
||||
option.timeout = timeout;
|
||||
};
|
||||
}
|
||||
static ConnectOptionFunc WithCompletedCallback(CompletedCallback callback)
|
||||
{
|
||||
return [callback](detail::ConnectOptionsInfo& option) {
|
||||
option.completedCallback = callback;
|
||||
};
|
||||
}
|
||||
static ConnectOptionFunc AddProcessTcpSocketCallback(ProcessTcpSocketCallback process)
|
||||
{
|
||||
return [process](detail::ConnectOptionsInfo& option) {
|
||||
option.processCallbacks.push_back(process);
|
||||
};
|
||||
}
|
||||
static ConnectOptionFunc WithFailedCallback(FailedCallback callback)
|
||||
{
|
||||
return [callback](detail::ConnectOptionsInfo& option) {
|
||||
option.faledCallback = callback;
|
||||
};
|
||||
}
|
||||
|
||||
static std::chrono::nanoseconds ExtractTimeout(const std::vector<ConnectOptionFunc>& options)
|
||||
{
|
||||
detail::ConnectOptionsInfo option;
|
||||
for (const auto& func : options)
|
||||
{
|
||||
func(option);
|
||||
}
|
||||
return option.timeout;
|
||||
}
|
||||
};
|
||||
|
||||
class AsyncConnector : public detail::AsyncConnectorDetail,
|
||||
public std::enable_shared_from_this<AsyncConnector>
|
||||
void stopWorkerThread()
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<AsyncConnector>;
|
||||
detail::AsyncConnectorDetail::stopWorkerThread();
|
||||
}
|
||||
|
||||
void startWorkerThread()
|
||||
void asyncConnect(const ConnectOption& option)
|
||||
{
|
||||
detail::AsyncConnectorDetail::asyncConnect(option);
|
||||
}
|
||||
|
||||
static Ptr Create()
|
||||
{
|
||||
class make_shared_enabler : public AsyncConnector
|
||||
{
|
||||
detail::AsyncConnectorDetail::startWorkerThread();
|
||||
}
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
|
||||
void stopWorkerThread()
|
||||
{
|
||||
detail::AsyncConnectorDetail::stopWorkerThread();
|
||||
}
|
||||
private:
|
||||
AsyncConnector() = default;
|
||||
};
|
||||
|
||||
void asyncConnect(const std::vector<detail::ConnectOptionFunc>& options)
|
||||
{
|
||||
detail::AsyncConnectorDetail::asyncConnect(options);
|
||||
}
|
||||
|
||||
static Ptr Create()
|
||||
{
|
||||
class make_shared_enabler : public AsyncConnector {};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
|
||||
private:
|
||||
AsyncConnector() = default;
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
@ -2,19 +2,19 @@
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class EventLoop;
|
||||
class EventLoop;
|
||||
|
||||
class Channel
|
||||
{
|
||||
public:
|
||||
virtual ~Channel() = default;
|
||||
class Channel
|
||||
{
|
||||
public:
|
||||
virtual ~Channel() = default;
|
||||
|
||||
private:
|
||||
virtual void canSend() = 0;
|
||||
virtual void canRecv() = 0;
|
||||
virtual void onClose() = 0;
|
||||
private:
|
||||
virtual void canSend() = 0;
|
||||
virtual void canRecv(bool willClose) = 0;
|
||||
virtual void onClose() = 0;
|
||||
|
||||
friend class EventLoop;
|
||||
};
|
||||
friend class EventLoop;
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
@ -3,53 +3,54 @@
|
||||
#include <brynet/base/Platform.hpp>
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
#include <winsock2.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <winsock2.h>
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
#include <unistd.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/unistd.h>
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
#include <unistd.h>
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace brynet { namespace net { namespace current_thread {
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
using THREAD_ID_TYPE = DWORD;
|
||||
using THREAD_ID_TYPE = DWORD;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
using THREAD_ID_TYPE = int;
|
||||
using THREAD_ID_TYPE = int;
|
||||
#endif
|
||||
|
||||
static THREAD_ID_TYPE& tid()
|
||||
static THREAD_ID_TYPE& tid()
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
static __declspec(thread) THREAD_ID_TYPE cachedTid = 0;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
static __thread THREAD_ID_TYPE cachedTid = 0;
|
||||
#endif
|
||||
|
||||
if (cachedTid == 0)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
static __declspec(thread) THREAD_ID_TYPE cachedTid = 0;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
static __thread THREAD_ID_TYPE cachedTid = 0;
|
||||
#endif
|
||||
|
||||
if (cachedTid == 0)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
cachedTid = GetCurrentThreadId();
|
||||
cachedTid = GetCurrentThreadId();
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
|
||||
cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
// warning: 'syscall' is deprecated:
|
||||
// first deprecated in macOS 10.12 - syscall(2) is unsupported;
|
||||
// please switch to a supported interface.
|
||||
uint64_t tid64;
|
||||
pthread_threadid_np(NULL, &tid64);
|
||||
cachedTid = (pid_t)tid64;
|
||||
// warning: 'syscall' is deprecated:
|
||||
// first deprecated in macOS 10.12 - syscall(2) is unsupported;
|
||||
// please switch to a supported interface.
|
||||
uint64_t tid64;
|
||||
pthread_threadid_np(NULL, &tid64);
|
||||
cachedTid = (pid_t) tid64;
|
||||
#endif
|
||||
}
|
||||
|
||||
return cachedTid;
|
||||
}
|
||||
|
||||
} } }
|
||||
return cachedTid;
|
||||
}
|
||||
|
||||
}}}// namespace brynet::net::current_thread
|
||||
|
@ -1,444 +1,444 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/Timer.hpp>
|
||||
#include <brynet/net/Channel.hpp>
|
||||
#include <brynet/net/CurrentThread.hpp>
|
||||
#include <brynet/net/Exception.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/net/detail/WakeupChannel.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <brynet/base/Timer.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/net/SocketLibFunction.hpp>
|
||||
#include <brynet/net/CurrentThread.hpp>
|
||||
|
||||
#include <brynet/net/Channel.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/net/Exception.hpp>
|
||||
#include <brynet/net/detail/WakeupChannel.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class Channel;
|
||||
class TcpConnection;
|
||||
using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
|
||||
class Channel;
|
||||
class TcpConnection;
|
||||
using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
|
||||
|
||||
class EventLoop : public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<EventLoop>;
|
||||
using UserFunctor = std::function<void(void)>;
|
||||
class EventLoop : public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<EventLoop>;
|
||||
using UserFunctor = std::function<void(void)>;
|
||||
|
||||
public:
|
||||
EventLoop()
|
||||
public:
|
||||
EventLoop()
|
||||
BRYNET_NOEXCEPT
|
||||
:
|
||||
:
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
mIOCP(CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)),
|
||||
mWakeupChannel(std::make_unique<detail::WakeupChannel>(mIOCP))
|
||||
mIOCP(CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)),
|
||||
mWakeupChannel(std::make_unique<detail::WakeupChannel>(mIOCP))
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
mEpollFd(epoll_create(1))
|
||||
mEpollFd(epoll_create(1))
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
mKqueueFd(kqueue())
|
||||
mKqueueFd(kqueue())
|
||||
#endif
|
||||
{
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
mPGetQueuedCompletionStatusEx = NULL;
|
||||
auto kernel32_module = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32_module != NULL) {
|
||||
mPGetQueuedCompletionStatusEx = reinterpret_cast<sGetQueuedCompletionStatusEx>(GetProcAddress(
|
||||
mPGetQueuedCompletionStatusEx = NULL;
|
||||
auto kernel32_module = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32_module != NULL)
|
||||
{
|
||||
mPGetQueuedCompletionStatusEx = reinterpret_cast<sGetQueuedCompletionStatusEx>(GetProcAddress(
|
||||
kernel32_module,
|
||||
"GetQueuedCompletionStatusEx"));
|
||||
FreeLibrary(kernel32_module);
|
||||
}
|
||||
FreeLibrary(kernel32_module);
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
auto eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
mWakeupChannel.reset(new detail::WakeupChannel(eventfd));
|
||||
linkChannel(eventfd, mWakeupChannel.get());
|
||||
auto eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
mWakeupChannel.reset(new detail::WakeupChannel(eventfd));
|
||||
linkChannel(eventfd, mWakeupChannel.get());
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
const int NOTIFY_IDENT = 42; // Magic number we use for our filter ID.
|
||||
mWakeupChannel.reset(new detail::WakeupChannel(mKqueueFd, NOTIFY_IDENT));
|
||||
//Add user event
|
||||
struct kevent ev;
|
||||
EV_SET(&ev, NOTIFY_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
|
||||
const int NOTIFY_IDENT = 42;// Magic number we use for our filter ID.
|
||||
mWakeupChannel.reset(new detail::WakeupChannel(mKqueueFd, NOTIFY_IDENT));
|
||||
//Add user event
|
||||
struct kevent ev;
|
||||
EV_SET(&ev, NOTIFY_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
|
||||
|
||||
struct timespec timeout = { 0, 0 };
|
||||
kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout);
|
||||
struct timespec timeout = {0, 0};
|
||||
kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout);
|
||||
#endif
|
||||
|
||||
mIsAlreadyPostWakeup = false;
|
||||
mIsInBlock = true;
|
||||
mIsAlreadyPostWakeup = false;
|
||||
mIsInBlock = true;
|
||||
|
||||
reallocEventSize(1024);
|
||||
mSelfThreadID = -1;
|
||||
mTimer = std::make_shared<brynet::base::TimerMgr>();
|
||||
}
|
||||
reAllocEventSize(1024);
|
||||
mSelfThreadID = -1;
|
||||
mTimer = std::make_shared<brynet::base::TimerMgr>();
|
||||
}
|
||||
|
||||
virtual ~EventLoop() BRYNET_NOEXCEPT
|
||||
{
|
||||
virtual ~EventLoop() BRYNET_NOEXCEPT
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
CloseHandle(mIOCP);
|
||||
mIOCP = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(mIOCP);
|
||||
mIOCP = INVALID_HANDLE_VALUE;
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
close(mEpollFd);
|
||||
mEpollFd = -1;
|
||||
close(mEpollFd);
|
||||
mEpollFd = -1;
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
close(mKqueueFd);
|
||||
mKqueueFd = -1;
|
||||
close(mKqueueFd);
|
||||
mKqueueFd = -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void loop(int64_t milliseconds)
|
||||
{
|
||||
tryInitThreadID();
|
||||
void loop(int64_t milliseconds)
|
||||
{
|
||||
tryInitThreadID();
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(isInLoopThread());
|
||||
assert(isInLoopThread());
|
||||
#endif
|
||||
if (!isInLoopThread())
|
||||
{
|
||||
throw BrynetCommonException("only loop in io thread");
|
||||
}
|
||||
if (!isInLoopThread())
|
||||
{
|
||||
throw BrynetCommonException("only loop in io thread");
|
||||
}
|
||||
|
||||
if (!mAfterLoopFunctors.empty())
|
||||
{
|
||||
milliseconds = 0;
|
||||
}
|
||||
if (!mAfterLoopFunctors.empty())
|
||||
{
|
||||
milliseconds = 0;
|
||||
}
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
ULONG numComplete = 0;
|
||||
if (mPGetQueuedCompletionStatusEx != nullptr)
|
||||
ULONG numComplete = 0;
|
||||
if (mPGetQueuedCompletionStatusEx != nullptr)
|
||||
{
|
||||
if (!mPGetQueuedCompletionStatusEx(mIOCP,
|
||||
mEventEntries.data(),
|
||||
static_cast<ULONG>(mEventEntries.size()),
|
||||
&numComplete,
|
||||
static_cast<DWORD>(milliseconds),
|
||||
false))
|
||||
{
|
||||
if (!mPGetQueuedCompletionStatusEx(mIOCP,
|
||||
mEventEntries.data(),
|
||||
static_cast<ULONG>(mEventEntries.size()),
|
||||
&numComplete,
|
||||
static_cast<DWORD>(milliseconds),
|
||||
false))
|
||||
numComplete = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& e : mEventEntries)
|
||||
{
|
||||
const auto timeout = (numComplete == 0) ? static_cast<DWORD>(milliseconds) : 0;
|
||||
/* don't check the return value of GQCS */
|
||||
GetQueuedCompletionStatus(mIOCP,
|
||||
&e.dwNumberOfBytesTransferred,
|
||||
&e.lpCompletionKey,
|
||||
&e.lpOverlapped,
|
||||
timeout);
|
||||
if (e.lpOverlapped == nullptr)
|
||||
{
|
||||
numComplete = 0;
|
||||
break;
|
||||
}
|
||||
++numComplete;
|
||||
}
|
||||
}
|
||||
|
||||
mIsInBlock = false;
|
||||
|
||||
for (ULONG i = 0; i < numComplete; ++i)
|
||||
{
|
||||
auto channel = (Channel*) mEventEntries[i].lpCompletionKey;
|
||||
assert(channel != nullptr);
|
||||
const auto ovl = reinterpret_cast<const port::Win::OverlappedExt*>(mEventEntries[i].lpOverlapped);
|
||||
if (ovl->OP == port::Win::OverlappedType::OverlappedRecv)
|
||||
{
|
||||
channel->canRecv(false);
|
||||
}
|
||||
else if (ovl->OP == port::Win::OverlappedType::OverlappedSend)
|
||||
{
|
||||
channel->canSend();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& e : mEventEntries)
|
||||
{
|
||||
const auto timeout = (numComplete == 0) ? static_cast<DWORD>(milliseconds) : 0;
|
||||
/* don't check the return value of GQCS */
|
||||
GetQueuedCompletionStatus(mIOCP,
|
||||
&e.dwNumberOfBytesTransferred,
|
||||
&e.lpCompletionKey,
|
||||
&e.lpOverlapped,
|
||||
timeout);
|
||||
if (e.lpOverlapped == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++numComplete;
|
||||
}
|
||||
}
|
||||
|
||||
mIsInBlock = false;
|
||||
|
||||
for (ULONG i = 0; i < numComplete; ++i)
|
||||
{
|
||||
auto channel = (Channel*)mEventEntries[i].lpCompletionKey;
|
||||
assert(channel != nullptr);
|
||||
const auto ovl = reinterpret_cast<const port::Win::OverlappedExt*>(mEventEntries[i].lpOverlapped);
|
||||
if (ovl->OP == port::Win::OverlappedType::OverlappedRecv)
|
||||
{
|
||||
channel->canRecv();
|
||||
}
|
||||
else if (ovl->OP == port::Win::OverlappedType::OverlappedSend)
|
||||
{
|
||||
channel->canSend();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
int numComplete = epoll_wait(mEpollFd, mEventEntries.data(), mEventEntries.size(), milliseconds);
|
||||
int numComplete = epoll_wait(mEpollFd, mEventEntries.data(), mEventEntries.size(), milliseconds);
|
||||
|
||||
mIsInBlock = false;
|
||||
mIsInBlock = false;
|
||||
|
||||
for (int i = 0; i < numComplete; ++i)
|
||||
for (int i = 0; i < numComplete; ++i)
|
||||
{
|
||||
auto channel = (Channel*) (mEventEntries[i].data.ptr);
|
||||
auto event_data = mEventEntries[i].events;
|
||||
|
||||
if (event_data & EPOLLRDHUP)
|
||||
{
|
||||
auto channel = (Channel*)(mEventEntries[i].data.ptr);
|
||||
auto event_data = mEventEntries[i].events;
|
||||
|
||||
if (event_data & EPOLLRDHUP)
|
||||
{
|
||||
channel->canRecv();
|
||||
channel->onClose();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event_data & EPOLLIN)
|
||||
{
|
||||
channel->canRecv();
|
||||
}
|
||||
|
||||
if (event_data & EPOLLOUT)
|
||||
{
|
||||
channel->canSend();
|
||||
}
|
||||
channel->canRecv(true);
|
||||
channel->onClose();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event_data & EPOLLIN)
|
||||
{
|
||||
channel->canRecv(false);
|
||||
}
|
||||
|
||||
if (event_data & EPOLLOUT)
|
||||
{
|
||||
channel->canSend();
|
||||
}
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
struct timespec timeout = { milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000 };
|
||||
int numComplete = kevent(mKqueueFd, NULL, 0, mEventEntries.data(), mEventEntries.size(), &timeout);
|
||||
struct timespec timeout = {milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000};
|
||||
int numComplete = kevent(mKqueueFd, NULL, 0, mEventEntries.data(), mEventEntries.size(), &timeout);
|
||||
|
||||
mIsInBlock = false;
|
||||
mIsInBlock = false;
|
||||
|
||||
for (int i = 0; i < numComplete; ++i)
|
||||
for (int i = 0; i < numComplete; ++i)
|
||||
{
|
||||
auto channel = (Channel*) (mEventEntries[i].udata);
|
||||
const struct kevent& event = mEventEntries[i];
|
||||
|
||||
if (event.filter == EVFILT_USER)
|
||||
{
|
||||
auto channel = (Channel*)(mEventEntries[i].udata);
|
||||
const struct kevent& event = mEventEntries[i];
|
||||
|
||||
if (event.filter == EVFILT_USER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event.filter == EVFILT_READ)
|
||||
{
|
||||
channel->canRecv();
|
||||
}
|
||||
|
||||
if (event.filter == EVFILT_WRITE)
|
||||
{
|
||||
channel->canSend();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event.filter == EVFILT_READ)
|
||||
{
|
||||
channel->canRecv(false);
|
||||
}
|
||||
|
||||
if (event.filter == EVFILT_WRITE)
|
||||
{
|
||||
channel->canSend();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mIsAlreadyPostWakeup = false;
|
||||
mIsInBlock = true;
|
||||
mIsAlreadyPostWakeup = false;
|
||||
mIsInBlock = true;
|
||||
|
||||
processAsyncFunctors();
|
||||
processAfterLoopFunctors();
|
||||
processAsyncFunctors();
|
||||
processAfterLoopFunctors();
|
||||
|
||||
if (static_cast<size_t>(numComplete) == mEventEntries.size())
|
||||
{
|
||||
reallocEventSize(mEventEntries.size() + 128);
|
||||
}
|
||||
|
||||
mTimer->schedule();
|
||||
if (static_cast<size_t>(numComplete) == mEventEntries.size())
|
||||
{
|
||||
reAllocEventSize(mEventEntries.size() + 128);
|
||||
}
|
||||
|
||||
// loop指定毫秒数,但如果定时器不为空,则loop时间为当前最近定时器的剩余时间和milliseconds的较小值
|
||||
void loopCompareNearTimer(int64_t milliseconds)
|
||||
{
|
||||
tryInitThreadID();
|
||||
mTimer->schedule();
|
||||
}
|
||||
|
||||
// loop指定毫秒数,但如果定时器不为空,则loop时间为当前最近定时器的剩余时间和milliseconds的较小值
|
||||
void loopCompareNearTimer(int64_t milliseconds)
|
||||
{
|
||||
tryInitThreadID();
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(isInLoopThread());
|
||||
assert(isInLoopThread());
|
||||
#endif
|
||||
if (!isInLoopThread())
|
||||
{
|
||||
throw BrynetCommonException("only loop in IO thread");
|
||||
}
|
||||
|
||||
if (!mTimer->isEmpty())
|
||||
{
|
||||
auto nearTimeout = std::chrono::duration_cast<std::chrono::milliseconds>(mTimer->nearLeftTime());
|
||||
milliseconds = std::min<int64_t>(milliseconds, nearTimeout.count());
|
||||
}
|
||||
|
||||
loop(milliseconds);
|
||||
if (!isInLoopThread())
|
||||
{
|
||||
throw BrynetCommonException("only loop in IO thread");
|
||||
}
|
||||
|
||||
// 返回true表示实际发生了wakeup所需的操作(此返回值不代表接口本身操作成功与否,因为此函数永远成功)
|
||||
bool wakeup()
|
||||
if (!mTimer->isEmpty())
|
||||
{
|
||||
if (!isInLoopThread() && mIsInBlock && !mIsAlreadyPostWakeup.exchange(true))
|
||||
{
|
||||
return mWakeupChannel->wakeup();
|
||||
}
|
||||
|
||||
return false;
|
||||
auto nearTimeout = std::chrono::duration_cast<std::chrono::milliseconds>(mTimer->nearLeftTime());
|
||||
milliseconds = std::min<int64_t>(milliseconds, nearTimeout.count());
|
||||
}
|
||||
|
||||
void runAsyncFunctor(UserFunctor&& f)
|
||||
{
|
||||
if (isInLoopThread())
|
||||
{
|
||||
f();
|
||||
}
|
||||
else
|
||||
{
|
||||
pushAsyncFunctor(std::move(f));
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
void runFunctorAfterLoop(UserFunctor&& f)
|
||||
{
|
||||
assert(isInLoopThread());
|
||||
if (!isInLoopThread())
|
||||
{
|
||||
throw BrynetCommonException("only push after functor in io thread");
|
||||
}
|
||||
loop(milliseconds);
|
||||
}
|
||||
|
||||
mAfterLoopFunctors.emplace_back(std::move(f));
|
||||
}
|
||||
brynet::base::Timer::WeakPtr runAfter(std::chrono::nanoseconds timeout, UserFunctor&& callback)
|
||||
// 返回true表示实际发生了wakeup所需的操作(此返回值不代表接口本身操作成功与否,因为此函数永远成功)
|
||||
bool wakeup()
|
||||
{
|
||||
if (!isInLoopThread() && mIsInBlock && !mIsAlreadyPostWakeup.exchange(true))
|
||||
{
|
||||
auto timer = std::make_shared<brynet::base::Timer>(
|
||||
return mWakeupChannel->wakeup();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void runAsyncFunctor(UserFunctor&& f)
|
||||
{
|
||||
if (isInLoopThread())
|
||||
{
|
||||
f();
|
||||
}
|
||||
else
|
||||
{
|
||||
pushAsyncFunctor(std::move(f));
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
void runFunctorAfterLoop(UserFunctor&& f)
|
||||
{
|
||||
assert(isInLoopThread());
|
||||
if (!isInLoopThread())
|
||||
{
|
||||
throw BrynetCommonException("only push after functor in io thread");
|
||||
}
|
||||
|
||||
mAfterLoopFunctors.emplace_back(std::move(f));
|
||||
}
|
||||
brynet::base::Timer::WeakPtr runAfter(std::chrono::nanoseconds timeout, UserFunctor&& callback)
|
||||
{
|
||||
auto timer = std::make_shared<brynet::base::Timer>(
|
||||
std::chrono::steady_clock::now(),
|
||||
std::chrono::nanoseconds(timeout),
|
||||
std::move(callback));
|
||||
|
||||
if (isInLoopThread())
|
||||
{
|
||||
mTimer->addTimer(timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto timerMgr = mTimer;
|
||||
runAsyncFunctor([timerMgr, timer]() {
|
||||
timerMgr->addTimer(timer);
|
||||
});
|
||||
}
|
||||
|
||||
return timer;
|
||||
if (isInLoopThread())
|
||||
{
|
||||
mTimer->addTimer(timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto timerMgr = mTimer;
|
||||
runAsyncFunctor([timerMgr, timer]() {
|
||||
timerMgr->addTimer(timer);
|
||||
});
|
||||
}
|
||||
|
||||
inline bool isInLoopThread() const
|
||||
{
|
||||
return mSelfThreadID == current_thread::tid();
|
||||
}
|
||||
return timer;
|
||||
}
|
||||
|
||||
private:
|
||||
void reallocEventSize(size_t size)
|
||||
{
|
||||
mEventEntries.resize(size);
|
||||
}
|
||||
inline bool isInLoopThread() const
|
||||
{
|
||||
return mSelfThreadID == current_thread::tid();
|
||||
}
|
||||
|
||||
void processAfterLoopFunctors()
|
||||
{
|
||||
mCopyAfterLoopFunctors.swap(mAfterLoopFunctors);
|
||||
for (const auto& x : mCopyAfterLoopFunctors)
|
||||
{
|
||||
x();
|
||||
}
|
||||
mCopyAfterLoopFunctors.clear();
|
||||
}
|
||||
void processAsyncFunctors()
|
||||
{
|
||||
swapAsyncFunctors();
|
||||
private:
|
||||
void reAllocEventSize(size_t size)
|
||||
{
|
||||
mEventEntries.resize(size);
|
||||
}
|
||||
|
||||
for (const auto& x : mCopyAsyncFunctors)
|
||||
{
|
||||
x();
|
||||
}
|
||||
mCopyAsyncFunctors.clear();
|
||||
}
|
||||
void swapAsyncFunctors()
|
||||
void processAfterLoopFunctors()
|
||||
{
|
||||
mCopyAfterLoopFunctors.swap(mAfterLoopFunctors);
|
||||
for (const auto& x : mCopyAfterLoopFunctors)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mAsyncFunctorsMutex);
|
||||
assert(mCopyAsyncFunctors.empty());
|
||||
mCopyAsyncFunctors.swap(mAsyncFunctors);
|
||||
x();
|
||||
}
|
||||
void pushAsyncFunctor(UserFunctor&& f)
|
||||
mCopyAfterLoopFunctors.clear();
|
||||
}
|
||||
void processAsyncFunctors()
|
||||
{
|
||||
swapAsyncFunctors();
|
||||
|
||||
for (const auto& x : mCopyAsyncFunctors)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mAsyncFunctorsMutex);
|
||||
mAsyncFunctors.emplace_back(std::move(f));
|
||||
x();
|
||||
}
|
||||
mCopyAsyncFunctors.clear();
|
||||
}
|
||||
void swapAsyncFunctors()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mAsyncFunctorsMutex);
|
||||
assert(mCopyAsyncFunctors.empty());
|
||||
mCopyAsyncFunctors.swap(mAsyncFunctors);
|
||||
}
|
||||
void pushAsyncFunctor(UserFunctor&& f)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mAsyncFunctorsMutex);
|
||||
mAsyncFunctors.emplace_back(std::move(f));
|
||||
}
|
||||
|
||||
#ifdef BRYNET_PLATFORM_LINUX
|
||||
int getEpollHandle() const
|
||||
{
|
||||
return mEpollFd;
|
||||
}
|
||||
int getEpollHandle() const
|
||||
{
|
||||
return mEpollFd;
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
int getKqueueHandle() const
|
||||
{
|
||||
return mKqueueFd;
|
||||
}
|
||||
int getKqueueHandle() const
|
||||
{
|
||||
return mKqueueFd;
|
||||
}
|
||||
#endif
|
||||
bool linkChannel(BrynetSocketFD fd, const Channel* ptr) BRYNET_NOEXCEPT
|
||||
{
|
||||
bool linkChannel(BrynetSocketFD fd, const Channel* ptr) BRYNET_NOEXCEPT
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
return CreateIoCompletionPort((HANDLE)fd, mIOCP, (ULONG_PTR)ptr, 0) != nullptr;
|
||||
return CreateIoCompletionPort((HANDLE) fd, mIOCP, (ULONG_PTR) ptr, 0) != nullptr;
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
struct epoll_event ev = { 0, { nullptr } };
|
||||
ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP;
|
||||
ev.data.ptr = (void*)ptr;
|
||||
return epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &ev) == 0;
|
||||
struct epoll_event ev = {0,
|
||||
{
|
||||
nullptr
|
||||
}};
|
||||
ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP;
|
||||
ev.data.ptr = (void*) ptr;
|
||||
return epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &ev) == 0;
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
struct kevent ev[2];
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
int n = 0;
|
||||
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*)ptr);
|
||||
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*)ptr);
|
||||
struct kevent ev[2];
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
int n = 0;
|
||||
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*) ptr);
|
||||
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*) ptr);
|
||||
|
||||
struct timespec now = { 0, 0 };
|
||||
return kevent(mKqueueFd, ev, n, NULL, 0, &now) == 0;
|
||||
struct timespec now = {0, 0};
|
||||
return kevent(mKqueueFd, ev, n, NULL, 0, &now) == 0;
|
||||
#endif
|
||||
}
|
||||
TcpConnectionPtr getTcpConnection(BrynetSocketFD fd)
|
||||
}
|
||||
TcpConnectionPtr getTcpConnection(BrynetSocketFD fd)
|
||||
{
|
||||
auto it = mTcpConnections.find(fd);
|
||||
if (it != mTcpConnections.end())
|
||||
{
|
||||
auto it = mTcpConnections.find(fd);
|
||||
if (it != mTcpConnections.end())
|
||||
{
|
||||
return (*it).second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void addTcpConnection(BrynetSocketFD fd, TcpConnectionPtr tcpConnection)
|
||||
{
|
||||
mTcpConnections[fd] = std::move(tcpConnection);
|
||||
}
|
||||
void removeTcpConnection(BrynetSocketFD fd)
|
||||
{
|
||||
mTcpConnections.erase(fd);
|
||||
}
|
||||
void tryInitThreadID()
|
||||
{
|
||||
std::call_once(mOnceInitThreadID, [this]() {
|
||||
mSelfThreadID = current_thread::tid();
|
||||
});
|
||||
return (*it).second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void addTcpConnection(BrynetSocketFD fd, TcpConnectionPtr tcpConnection)
|
||||
{
|
||||
mTcpConnections[fd] = std::move(tcpConnection);
|
||||
}
|
||||
void removeTcpConnection(BrynetSocketFD fd)
|
||||
{
|
||||
mTcpConnections.erase(fd);
|
||||
}
|
||||
void tryInitThreadID()
|
||||
{
|
||||
std::call_once(mOnceInitThreadID, [this]() {
|
||||
mSelfThreadID = current_thread::tid();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
std::vector<OVERLAPPED_ENTRY> mEventEntries;
|
||||
std::vector<OVERLAPPED_ENTRY> mEventEntries;
|
||||
|
||||
typedef BOOL(WINAPI *sGetQueuedCompletionStatusEx) (HANDLE, LPOVERLAPPED_ENTRY, ULONG, PULONG, DWORD, BOOL);
|
||||
sGetQueuedCompletionStatusEx mPGetQueuedCompletionStatusEx;
|
||||
HANDLE mIOCP;
|
||||
typedef BOOL(WINAPI* sGetQueuedCompletionStatusEx)(HANDLE, LPOVERLAPPED_ENTRY, ULONG, PULONG, DWORD, BOOL);
|
||||
sGetQueuedCompletionStatusEx mPGetQueuedCompletionStatusEx;
|
||||
HANDLE mIOCP;
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
std::vector<epoll_event> mEventEntries;
|
||||
int mEpollFd;
|
||||
std::vector<epoll_event> mEventEntries;
|
||||
int mEpollFd;
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
std::vector<struct kevent> mEventEntries;
|
||||
int mKqueueFd;
|
||||
std::vector<struct kevent> mEventEntries;
|
||||
int mKqueueFd;
|
||||
#endif
|
||||
std::unique_ptr<detail::WakeupChannel> mWakeupChannel;
|
||||
std::unique_ptr<detail::WakeupChannel> mWakeupChannel;
|
||||
|
||||
std::atomic_bool mIsInBlock;
|
||||
std::atomic_bool mIsAlreadyPostWakeup;
|
||||
std::atomic_bool mIsInBlock;
|
||||
std::atomic_bool mIsAlreadyPostWakeup;
|
||||
|
||||
std::mutex mAsyncFunctorsMutex;
|
||||
std::vector<UserFunctor> mAsyncFunctors;
|
||||
std::vector<UserFunctor> mCopyAsyncFunctors;
|
||||
std::mutex mAsyncFunctorsMutex;
|
||||
std::vector<UserFunctor> mAsyncFunctors;
|
||||
std::vector<UserFunctor> mCopyAsyncFunctors;
|
||||
|
||||
std::vector<UserFunctor> mAfterLoopFunctors;
|
||||
std::vector<UserFunctor> mCopyAfterLoopFunctors;
|
||||
std::vector<UserFunctor> mAfterLoopFunctors;
|
||||
std::vector<UserFunctor> mCopyAfterLoopFunctors;
|
||||
|
||||
std::once_flag mOnceInitThreadID;
|
||||
current_thread::THREAD_ID_TYPE mSelfThreadID;
|
||||
std::once_flag mOnceInitThreadID;
|
||||
current_thread::THREAD_ID_TYPE mSelfThreadID;
|
||||
|
||||
brynet::base::TimerMgr::Ptr mTimer;
|
||||
std::unordered_map<BrynetSocketFD, TcpConnectionPtr> mTcpConnections;
|
||||
brynet::base::TimerMgr::Ptr mTimer;
|
||||
std::unordered_map<BrynetSocketFD, TcpConnectionPtr> mTcpConnections;
|
||||
|
||||
friend class TcpConnection;
|
||||
};
|
||||
friend class TcpConnection;
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
@ -1,41 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class ConnectException : public std::runtime_error
|
||||
class ConnectException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit ConnectException(const std::string& message)
|
||||
: std::runtime_error(message)
|
||||
{
|
||||
public:
|
||||
explicit ConnectException(const std::string& message)
|
||||
:
|
||||
std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
explicit ConnectException(const char* message)
|
||||
:
|
||||
std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class BrynetCommonException : public std::runtime_error
|
||||
explicit ConnectException(const char* message)
|
||||
: std::runtime_error(message)
|
||||
{
|
||||
public:
|
||||
explicit BrynetCommonException(const std::string& message)
|
||||
:
|
||||
std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
explicit BrynetCommonException(const char* message)
|
||||
:
|
||||
std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
class BrynetCommonException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit BrynetCommonException(const std::string& message)
|
||||
: std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
|
||||
} }
|
||||
explicit BrynetCommonException(const char* message)
|
||||
: std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}}// namespace brynet::net
|
||||
|
@ -4,55 +4,56 @@
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class ListenThread : public detail::ListenThreadDetail,
|
||||
public std::enable_shared_from_this<ListenThread>
|
||||
class ListenThread : public detail::ListenThreadDetail,
|
||||
public std::enable_shared_from_this<ListenThread>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<ListenThread>;
|
||||
using AccepCallback = std::function<void(TcpSocket::Ptr)>;
|
||||
using TcpSocketProcessCallback = std::function<void(TcpSocket&)>;
|
||||
|
||||
void startListen()
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<ListenThread>;
|
||||
using AccepCallback = std::function<void(TcpSocket::Ptr)>;;
|
||||
using TcpSocketProcessCallback = std::function<void(TcpSocket&)>;
|
||||
detail::ListenThreadDetail::startListen();
|
||||
}
|
||||
|
||||
void startListen()
|
||||
void stopListen()
|
||||
{
|
||||
detail::ListenThreadDetail::stopListen();
|
||||
}
|
||||
|
||||
public:
|
||||
static Ptr Create(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks = {},
|
||||
bool enabledReusePort = false)
|
||||
{
|
||||
class make_shared_enabler : public ListenThread
|
||||
{
|
||||
detail::ListenThreadDetail::startListen();
|
||||
}
|
||||
public:
|
||||
make_shared_enabler(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks,
|
||||
bool enabledReusePort)
|
||||
: ListenThread(isIPV6, ip, port, callback, processCallbacks, enabledReusePort)
|
||||
{}
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>(isIPV6, ip, port, callback, processCallbacks, enabledReusePort);
|
||||
}
|
||||
|
||||
void stopListen()
|
||||
{
|
||||
detail::ListenThreadDetail::stopListen();
|
||||
}
|
||||
protected:
|
||||
ListenThread(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks,
|
||||
bool enabledReusePort)
|
||||
: detail::ListenThreadDetail(isIPV6, ip, port, callback, processCallbacks, enabledReusePort)
|
||||
{}
|
||||
};
|
||||
|
||||
public:
|
||||
static Ptr Create(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback> & processCallbacks = {})
|
||||
{
|
||||
class make_shared_enabler : public ListenThread
|
||||
{
|
||||
public:
|
||||
make_shared_enabler(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks)
|
||||
:
|
||||
ListenThread(isIPV6, ip, port, callback, processCallbacks)
|
||||
{}
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>(isIPV6, ip, port, callback, processCallbacks);
|
||||
}
|
||||
|
||||
protected:
|
||||
ListenThread(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks)
|
||||
:
|
||||
detail::ListenThreadDetail(isIPV6, ip, port, callback, processCallbacks)
|
||||
{}
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
@ -1,13 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstdbool>
|
||||
#include <string>
|
||||
|
||||
#include <brynet/net/SocketLibTypes.hpp>
|
||||
#include <brynet/base/Stack.hpp>
|
||||
#include <brynet/net/SocketLibTypes.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
#include <poll.h>
|
||||
@ -15,252 +11,252 @@
|
||||
|
||||
namespace brynet { namespace base {
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND);
|
||||
const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM);
|
||||
const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI);
|
||||
const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||
const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP);
|
||||
#endif
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND);
|
||||
const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM);
|
||||
const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI);
|
||||
const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||
const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP);
|
||||
#endif
|
||||
|
||||
enum CheckType
|
||||
enum CheckType
|
||||
{
|
||||
ReadCheck = 0x1,
|
||||
WriteCheck = 0x2,
|
||||
ErrorCheck = 0x4,
|
||||
};
|
||||
|
||||
struct poller_s
|
||||
{
|
||||
struct pollfd* pollFds;
|
||||
int nfds;
|
||||
int limitSize;
|
||||
};
|
||||
|
||||
static void upstep_pollfd(struct poller_s* self, int upSize)
|
||||
{
|
||||
if (upSize <= 0)
|
||||
{
|
||||
ReadCheck = 0x1,
|
||||
WriteCheck = 0x2,
|
||||
ErrorCheck = 0x4,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
struct poller_s
|
||||
{
|
||||
struct pollfd* pollFds;
|
||||
int nfds;
|
||||
int limitSize;
|
||||
};
|
||||
|
||||
static void upstep_pollfd(struct poller_s* self, int upSize)
|
||||
{
|
||||
if (upSize <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd* newPollfds = (struct pollfd*)malloc(
|
||||
struct pollfd* newPollfds = (struct pollfd*) malloc(
|
||||
sizeof(struct pollfd) * (self->limitSize + upSize));
|
||||
if (newPollfds == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->pollFds != nullptr)
|
||||
{
|
||||
memcpy(newPollfds, self->pollFds, sizeof(struct pollfd) * self->nfds);
|
||||
free(self->pollFds);
|
||||
self->pollFds = nullptr;
|
||||
}
|
||||
self->pollFds = newPollfds;
|
||||
self->limitSize += upSize;
|
||||
if (newPollfds == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static struct pollfd* find_pollfd(struct poller_s* self, BrynetSocketFD fd)
|
||||
{
|
||||
for (int i = 0; i < self->nfds; i++)
|
||||
{
|
||||
if (self->pollFds[i].fd == fd)
|
||||
{
|
||||
return self->pollFds + i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void try_remove_pollfd(struct poller_s* self, BrynetSocketFD fd)
|
||||
{
|
||||
int pos = -1;
|
||||
for (int i = 0; i < self->nfds; i++)
|
||||
{
|
||||
if (self->pollFds[i].fd == fd)
|
||||
{
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
memmove(self->pollFds + pos,
|
||||
self->pollFds + pos + 1,
|
||||
sizeof(struct pollfd) * (self->nfds - pos - 1));
|
||||
self->nfds--;
|
||||
assert(self->nfds >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct poller_s* poller_new(void)
|
||||
{
|
||||
struct poller_s* ret = (struct poller_s*)malloc(sizeof(struct poller_s));
|
||||
if (ret != nullptr)
|
||||
{
|
||||
ret->pollFds = NULL;
|
||||
ret->limitSize = 0;
|
||||
ret->nfds = 0;
|
||||
upstep_pollfd(ret, 1024);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void poller_delete(struct poller_s* self)
|
||||
if (self->pollFds != nullptr)
|
||||
{
|
||||
memcpy(newPollfds, self->pollFds, sizeof(struct pollfd) * self->nfds);
|
||||
free(self->pollFds);
|
||||
self->pollFds = nullptr;
|
||||
self->nfds = 0;
|
||||
self->limitSize = 0;
|
||||
|
||||
free(self);
|
||||
self = nullptr;
|
||||
}
|
||||
self->pollFds = newPollfds;
|
||||
self->limitSize += upSize;
|
||||
}
|
||||
|
||||
static void poller_add(struct poller_s* self, BrynetSocketFD fd, int type)
|
||||
static struct pollfd* find_pollfd(struct poller_s* self, BrynetSocketFD fd)
|
||||
{
|
||||
for (int i = 0; i < self->nfds; i++)
|
||||
{
|
||||
if (self->limitSize == self->nfds)
|
||||
if (self->pollFds[i].fd == fd)
|
||||
{
|
||||
upstep_pollfd(self, 128);
|
||||
}
|
||||
|
||||
if (self->limitSize <= self->nfds)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd* pf = find_pollfd(self, fd);
|
||||
if (pf == nullptr)
|
||||
{
|
||||
/*real add*/
|
||||
pf = self->pollFds + self->nfds;
|
||||
pf->events = 0;
|
||||
pf->fd = fd;
|
||||
|
||||
self->nfds++;
|
||||
}
|
||||
|
||||
if (type & ReadCheck)
|
||||
{
|
||||
pf->events |= CHECK_READ_FLAG;
|
||||
}
|
||||
|
||||
if (type & WriteCheck)
|
||||
{
|
||||
pf->events |= CHECK_WRITE_FLAG;
|
||||
}
|
||||
|
||||
if (type & ErrorCheck)
|
||||
{
|
||||
//pf->events |= CHECK_ERROR_FLAG; TODO::on windows, not supports
|
||||
return self->pollFds + i;
|
||||
}
|
||||
}
|
||||
|
||||
static void poller_del(struct poller_s* self, BrynetSocketFD fd, int type)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void try_remove_pollfd(struct poller_s* self, BrynetSocketFD fd)
|
||||
{
|
||||
int pos = -1;
|
||||
for (int i = 0; i < self->nfds; i++)
|
||||
{
|
||||
struct pollfd* pf = find_pollfd(self, fd);
|
||||
if (pf == nullptr)
|
||||
if (self->pollFds[i].fd == fd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type & ReadCheck)
|
||||
{
|
||||
pf->events &= ~CHECK_READ_FLAG;
|
||||
}
|
||||
|
||||
if (type & WriteCheck)
|
||||
{
|
||||
pf->events &= ~CHECK_WRITE_FLAG;
|
||||
}
|
||||
|
||||
if (type & ErrorCheck)
|
||||
{
|
||||
pf->events &= ~CHECK_ERROR_FLAG;
|
||||
}
|
||||
|
||||
if (pf->events == 0)
|
||||
{
|
||||
try_remove_pollfd(self, fd);
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void poller_remove(struct poller_s* self, BrynetSocketFD fd)
|
||||
if (pos != -1)
|
||||
{
|
||||
memmove(self->pollFds + pos,
|
||||
self->pollFds + pos + 1,
|
||||
sizeof(struct pollfd) * (self->nfds - pos - 1));
|
||||
self->nfds--;
|
||||
assert(self->nfds >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct poller_s* poller_new(void)
|
||||
{
|
||||
struct poller_s* ret = (struct poller_s*) malloc(sizeof(struct poller_s));
|
||||
if (ret != nullptr)
|
||||
{
|
||||
ret->pollFds = NULL;
|
||||
ret->limitSize = 0;
|
||||
ret->nfds = 0;
|
||||
upstep_pollfd(ret, 1024);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void poller_delete(struct poller_s* self)
|
||||
{
|
||||
free(self->pollFds);
|
||||
self->pollFds = nullptr;
|
||||
self->nfds = 0;
|
||||
self->limitSize = 0;
|
||||
|
||||
free(self);
|
||||
self = nullptr;
|
||||
}
|
||||
|
||||
static void poller_add(struct poller_s* self, BrynetSocketFD fd, int type)
|
||||
{
|
||||
if (self->limitSize == self->nfds)
|
||||
{
|
||||
upstep_pollfd(self, 128);
|
||||
}
|
||||
|
||||
if (self->limitSize <= self->nfds)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd* pf = find_pollfd(self, fd);
|
||||
if (pf == nullptr)
|
||||
{
|
||||
/*real add*/
|
||||
pf = self->pollFds + self->nfds;
|
||||
pf->events = 0;
|
||||
pf->fd = fd;
|
||||
|
||||
self->nfds++;
|
||||
}
|
||||
|
||||
if (type & ReadCheck)
|
||||
{
|
||||
pf->events |= CHECK_READ_FLAG;
|
||||
}
|
||||
|
||||
if (type & WriteCheck)
|
||||
{
|
||||
pf->events |= CHECK_WRITE_FLAG;
|
||||
}
|
||||
|
||||
if (type & ErrorCheck)
|
||||
{
|
||||
//pf->events |= CHECK_ERROR_FLAG; TODO::on windows, not supports
|
||||
}
|
||||
}
|
||||
|
||||
static void poller_del(struct poller_s* self, BrynetSocketFD fd, int type)
|
||||
{
|
||||
struct pollfd* pf = find_pollfd(self, fd);
|
||||
if (pf == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type & ReadCheck)
|
||||
{
|
||||
pf->events &= ~CHECK_READ_FLAG;
|
||||
}
|
||||
|
||||
if (type & WriteCheck)
|
||||
{
|
||||
pf->events &= ~CHECK_WRITE_FLAG;
|
||||
}
|
||||
|
||||
if (type & ErrorCheck)
|
||||
{
|
||||
pf->events &= ~CHECK_ERROR_FLAG;
|
||||
}
|
||||
|
||||
if (pf->events == 0)
|
||||
{
|
||||
try_remove_pollfd(self, fd);
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_event(const struct pollfd* pf, enum CheckType type)
|
||||
static void poller_remove(struct poller_s* self, BrynetSocketFD fd)
|
||||
{
|
||||
try_remove_pollfd(self, fd);
|
||||
}
|
||||
|
||||
static bool check_event(const struct pollfd* pf, enum CheckType type)
|
||||
{
|
||||
if (pf == nullptr)
|
||||
{
|
||||
if (pf == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((type & ReadCheck) &&
|
||||
(pf->revents & CHECK_READ_FLAG))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((type & WriteCheck) &&
|
||||
(pf->revents & CHECK_WRITE_FLAG))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((type & ErrorCheck) &&
|
||||
(pf->revents & CHECK_ERROR_FLAG))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void poller_visitor(struct poller_s* self,
|
||||
enum CheckType type,
|
||||
struct stack_s* result)
|
||||
if ((type & ReadCheck) &&
|
||||
(pf->revents & CHECK_READ_FLAG))
|
||||
{
|
||||
for (int i = 0; i < self->nfds; i++)
|
||||
return true;
|
||||
}
|
||||
else if ((type & WriteCheck) &&
|
||||
(pf->revents & CHECK_WRITE_FLAG))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((type & ErrorCheck) &&
|
||||
(pf->revents & CHECK_ERROR_FLAG))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void poller_visitor(struct poller_s* self,
|
||||
enum CheckType type,
|
||||
struct stack_s* result)
|
||||
{
|
||||
for (int i = 0; i < self->nfds; i++)
|
||||
{
|
||||
if (check_event(self->pollFds + i, type))
|
||||
{
|
||||
if (check_event(self->pollFds + i, type))
|
||||
{
|
||||
stack_push(result, &self->pollFds[i].fd);
|
||||
}
|
||||
stack_push(result, &self->pollFds[i].fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int poller_poll(struct poller_s* self, long overtime)
|
||||
{
|
||||
static int poller_poll(struct poller_s* self, long overtime)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
int ret = WSAPoll(&self->pollFds[0], self->nfds, overtime);
|
||||
int ret = WSAPoll(&self->pollFds[0], self->nfds, overtime);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
int ret = poll(self->pollFds, self->nfds, overtime);
|
||||
int ret = poll(self->pollFds, self->nfds, overtime);
|
||||
#endif
|
||||
|
||||
if (ret == BRYNET_SOCKET_ERROR)
|
||||
{
|
||||
ret = (BRYNET_ERRNO != BRYNET_EINTR) ? -1 : 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool poller_check(struct poller_s* self, BrynetSocketFD fd, enum CheckType type)
|
||||
if (ret == BRYNET_SOCKET_ERROR)
|
||||
{
|
||||
const struct pollfd* pf = find_pollfd(self, fd);
|
||||
if (pf == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return check_event(pf, type);
|
||||
ret = (BRYNET_ERRNO != BRYNET_EINTR) ? -1 : 0;
|
||||
}
|
||||
|
||||
} }
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool poller_check(struct poller_s* self, BrynetSocketFD fd, enum CheckType type)
|
||||
{
|
||||
const struct pollfd* pf = find_pollfd(self, fd);
|
||||
if (pf == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return check_event(pf, type);
|
||||
}
|
||||
|
||||
}}// namespace brynet::base
|
||||
|
@ -4,153 +4,153 @@
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
/* binary search in memory */
|
||||
void memsearch(const char *hay, size_t haysize, const char *needle, size_t needlesize, size_t& result, bool& isOK)
|
||||
{
|
||||
size_t haypos, needlepos;
|
||||
haysize -= needlesize;
|
||||
/* binary search in memory */
|
||||
void memsearch(const char* hay, size_t haysize, const char* needle, size_t needlesize, size_t& result, bool& isOK)
|
||||
{
|
||||
size_t haypos, needlepos;
|
||||
haysize -= needlesize;
|
||||
|
||||
for (haypos = 0; haypos <= haysize; haypos++)
|
||||
for (haypos = 0; haypos <= haysize; haypos++)
|
||||
{
|
||||
for (needlepos = 0; needlepos < needlesize; needlepos++)
|
||||
{
|
||||
for (needlepos = 0; needlepos < needlesize; needlepos++)
|
||||
if (hay[haypos + needlepos] != needle[needlepos])
|
||||
{
|
||||
if (hay[haypos + needlepos] != needle[needlepos])
|
||||
{
|
||||
// Next character in haystack.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needlepos == needlesize)
|
||||
{
|
||||
result = haypos;
|
||||
isOK = true;
|
||||
return;
|
||||
// Next character in haystack.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
isOK = false;
|
||||
if (needlepos == needlesize)
|
||||
{
|
||||
result = haypos;
|
||||
isOK = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class PromiseReceive;
|
||||
isOK = false;
|
||||
}
|
||||
|
||||
std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session);
|
||||
class PromiseReceive;
|
||||
|
||||
class PromiseReceive : public std::enable_shared_from_this<PromiseReceive>
|
||||
std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session);
|
||||
|
||||
class PromiseReceive : public std::enable_shared_from_this<PromiseReceive>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<PromiseReceive>;
|
||||
using Handle = std::function<bool(const char* buffer, size_t len)>;
|
||||
|
||||
PromiseReceive::Ptr receive(size_t len, Handle handle)
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<PromiseReceive>;
|
||||
using Handle = std::function<bool(const char* buffer, size_t len)>;
|
||||
return receive(std::make_shared<size_t>(len), std::move(handle));
|
||||
}
|
||||
|
||||
PromiseReceive::Ptr receive(size_t len, Handle handle)
|
||||
PromiseReceive::Ptr receive(std::shared_ptr<size_t> len, Handle handle)
|
||||
{
|
||||
return helpReceive(std::move(len), "", std::move(handle));
|
||||
}
|
||||
|
||||
PromiseReceive::Ptr receiveUntil(std::string str, Handle handle)
|
||||
{
|
||||
if (str.empty())
|
||||
{
|
||||
return receive(std::make_shared<size_t>(len), std::move(handle));
|
||||
throw std::runtime_error("str is empty");
|
||||
}
|
||||
|
||||
PromiseReceive::Ptr receive(std::shared_ptr<size_t> len, Handle handle)
|
||||
{
|
||||
return helpReceive(std::move(len), "", std::move(handle));
|
||||
}
|
||||
return helpReceive(nullptr, std::move(str), std::move(handle));
|
||||
}
|
||||
|
||||
PromiseReceive::Ptr receiveUntil(std::string str, Handle handle)
|
||||
private:
|
||||
PromiseReceive::Ptr helpReceive(std::shared_ptr<size_t> len, std::string str, Handle handle)
|
||||
{
|
||||
auto pr = std::make_shared<PendingReceive>();
|
||||
pr->len = std::move(len);
|
||||
pr->str = std::move(str);
|
||||
pr->handle = std::move(handle);
|
||||
mPendingReceives.push_back(std::move(pr));
|
||||
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
size_t process(const char* buffer, const size_t len)
|
||||
{
|
||||
size_t procLen = 0;
|
||||
|
||||
while (!mPendingReceives.empty() && len >= procLen)
|
||||
{
|
||||
if (str.empty())
|
||||
auto pendingReceive = mPendingReceives.front();
|
||||
if (pendingReceive->len != nullptr)
|
||||
{
|
||||
throw std::runtime_error("str is empty");
|
||||
}
|
||||
|
||||
return helpReceive(nullptr, std::move(str), std::move(handle));
|
||||
}
|
||||
|
||||
private:
|
||||
PromiseReceive::Ptr helpReceive(std::shared_ptr<size_t> len, std::string str, Handle handle)
|
||||
{
|
||||
auto pr = std::make_shared<PendingReceive>();
|
||||
pr->len = std::move(len);
|
||||
pr->str = std::move(str);
|
||||
pr->handle = std::move(handle);
|
||||
mPendingReceives.push_back(std::move(pr));
|
||||
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
size_t process(const char* buffer, const size_t len)
|
||||
{
|
||||
size_t procLen = 0;
|
||||
|
||||
while (!mPendingReceives.empty() && len >= procLen)
|
||||
{
|
||||
auto pendingReceive = mPendingReceives.front();
|
||||
if (pendingReceive->len != nullptr)
|
||||
{
|
||||
const auto tryReceiveLen = *pendingReceive->len;
|
||||
if ((len - procLen) < tryReceiveLen)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
mPendingReceives.pop_front();
|
||||
procLen += tryReceiveLen;
|
||||
if (pendingReceive->handle(buffer + procLen - tryReceiveLen, tryReceiveLen) && tryReceiveLen > 0)
|
||||
{
|
||||
mPendingReceives.push_front(pendingReceive);
|
||||
}
|
||||
}
|
||||
else if (!pendingReceive->str.empty())
|
||||
{
|
||||
size_t pos = 0;
|
||||
bool isOK = false;
|
||||
auto data = buffer + procLen;
|
||||
memsearch(buffer + procLen,
|
||||
len - procLen,
|
||||
pendingReceive->str.c_str(),
|
||||
pendingReceive->str.size(),
|
||||
pos,
|
||||
isOK);
|
||||
|
||||
if (!isOK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
mPendingReceives.pop_front();
|
||||
procLen += (pos + pendingReceive->str.size());
|
||||
if (pendingReceive->handle(data, pos))
|
||||
{
|
||||
mPendingReceives.push_front(pendingReceive);
|
||||
}
|
||||
}
|
||||
else
|
||||
const auto tryReceiveLen = *pendingReceive->len;
|
||||
if ((len - procLen) < tryReceiveLen)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return procLen;
|
||||
mPendingReceives.pop_front();
|
||||
procLen += tryReceiveLen;
|
||||
if (pendingReceive->handle(buffer + procLen - tryReceiveLen, tryReceiveLen) && tryReceiveLen > 0)
|
||||
{
|
||||
mPendingReceives.push_front(pendingReceive);
|
||||
}
|
||||
}
|
||||
else if (!pendingReceive->str.empty())
|
||||
{
|
||||
size_t pos = 0;
|
||||
bool isOK = false;
|
||||
auto data = buffer + procLen;
|
||||
memsearch(buffer + procLen,
|
||||
len - procLen,
|
||||
pendingReceive->str.c_str(),
|
||||
pendingReceive->str.size(),
|
||||
pos,
|
||||
isOK);
|
||||
|
||||
if (!isOK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
mPendingReceives.pop_front();
|
||||
procLen += (pos + pendingReceive->str.size());
|
||||
if (pendingReceive->handle(data, pos))
|
||||
{
|
||||
mPendingReceives.push_front(pendingReceive);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct PendingReceive
|
||||
{
|
||||
std::shared_ptr<size_t> len;
|
||||
std::string str;
|
||||
Handle handle;
|
||||
};
|
||||
return procLen;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<PendingReceive>> mPendingReceives;
|
||||
|
||||
friend std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session);
|
||||
private:
|
||||
struct PendingReceive
|
||||
{
|
||||
std::shared_ptr<size_t> len;
|
||||
std::string str;
|
||||
Handle handle;
|
||||
};
|
||||
|
||||
std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session)
|
||||
{
|
||||
auto promiseReceive = std::make_shared<PromiseReceive>();
|
||||
session->setDataCallback([promiseReceive](brynet::base::BasePacketReader& reader) {
|
||||
auto procLen = promiseReceive->process(reader.begin(), reader.size());
|
||||
reader.addPos(procLen);
|
||||
reader.savePos();
|
||||
});
|
||||
std::deque<std::shared_ptr<PendingReceive>> mPendingReceives;
|
||||
|
||||
return promiseReceive;
|
||||
}
|
||||
friend std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session);
|
||||
};
|
||||
|
||||
} }
|
||||
std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session)
|
||||
{
|
||||
auto promiseReceive = std::make_shared<PromiseReceive>();
|
||||
session->setDataCallback([promiseReceive](brynet::base::BasePacketReader& reader) {
|
||||
auto procLen = promiseReceive->process(reader.begin(), reader.size());
|
||||
reader.addPos(procLen);
|
||||
reader.savePos();
|
||||
});
|
||||
|
||||
return promiseReceive;
|
||||
}
|
||||
|
||||
}}// namespace brynet::net
|
||||
|
@ -1,23 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/Platform.hpp>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#ifdef __cplusplus
|
||||
#include <openssl/ssl.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -28,147 +27,149 @@ namespace brynet { namespace net {
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
|
||||
#ifndef CRYPTO_THREADID_set_callback
|
||||
static void cryptoSetThreadIDCallback(CRYPTO_THREADID* id)
|
||||
{
|
||||
static void cryptoSetThreadIDCallback(CRYPTO_THREADID* id)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
CRYPTO_THREADID_set_numeric(id,
|
||||
static_cast<unsigned long>(GetCurrentThreadId()));
|
||||
CRYPTO_THREADID_set_numeric(id,
|
||||
static_cast<unsigned long>(GetCurrentThreadId()));
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
CRYPTO_THREADID_set_numeric(id,
|
||||
static_cast<unsigned long>(pthread_self()));
|
||||
CRYPTO_THREADID_set_numeric(id,
|
||||
static_cast<unsigned long>(pthread_self()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTO_set_locking_callback
|
||||
static std::unordered_map<int, std::shared_ptr<std::mutex>> cryptoLocks;
|
||||
static void cryptoLockingCallback(int mode,
|
||||
int type,
|
||||
const char* file, int line)
|
||||
static std::unordered_map<int, std::shared_ptr<std::mutex>> cryptoLocks;
|
||||
static void cryptoLockingCallback(int mode,
|
||||
int type,
|
||||
const char* file, int line)
|
||||
{
|
||||
(void) file;
|
||||
(void) line;
|
||||
if (mode & CRYPTO_LOCK)
|
||||
{
|
||||
(void)file;
|
||||
(void)line;
|
||||
if (mode & CRYPTO_LOCK)
|
||||
{
|
||||
cryptoLocks[type]->lock();
|
||||
}
|
||||
else if (mode & CRYPTO_UNLOCK)
|
||||
{
|
||||
cryptoLocks[type]->unlock();
|
||||
}
|
||||
cryptoLocks[type]->lock();
|
||||
}
|
||||
else if (mode & CRYPTO_UNLOCK)
|
||||
{
|
||||
cryptoLocks[type]->unlock();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::once_flag initCryptoThreadSafeSupportOnceFlag;
|
||||
static void InitCryptoThreadSafeSupport()
|
||||
{
|
||||
static std::once_flag initCryptoThreadSafeSupportOnceFlag;
|
||||
static void InitCryptoThreadSafeSupport()
|
||||
{
|
||||
#ifndef CRYPTO_THREADID_set_callback
|
||||
CRYPTO_THREADID_set_callback(cryptoSetThreadIDCallback);
|
||||
CRYPTO_THREADID_set_callback(cryptoSetThreadIDCallback);
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTO_set_locking_callback
|
||||
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||
{
|
||||
cryptoLocks[i] = std::make_shared<std::mutex>();
|
||||
}
|
||||
CRYPTO_set_locking_callback(cryptoLockingCallback);
|
||||
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||
{
|
||||
cryptoLocks[i] = std::make_shared<std::mutex>();
|
||||
}
|
||||
CRYPTO_set_locking_callback(cryptoLockingCallback);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
class SSLHelper : public brynet::base::NonCopyable,
|
||||
public std::enable_shared_from_this<SSLHelper>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<SSLHelper>;
|
||||
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
bool initSSL(const std::string& certificate,
|
||||
const std::string& privatekey)
|
||||
{
|
||||
std::call_once(initCryptoThreadSafeSupportOnceFlag,
|
||||
InitCryptoThreadSafeSupport);
|
||||
|
||||
if (mOpenSSLCTX != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (certificate.empty() || privatekey.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mOpenSSLCTX = SSL_CTX_new(SSLv23_method());
|
||||
SSL_CTX_set_client_CA_list(mOpenSSLCTX,
|
||||
SSL_load_client_CA_file(certificate.c_str()));
|
||||
SSL_CTX_set_verify_depth(mOpenSSLCTX, 10);
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(mOpenSSLCTX,
|
||||
certificate.c_str()) <= 0)
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(mOpenSSLCTX,
|
||||
privatekey.c_str(),
|
||||
SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSL_CTX_check_private_key(mOpenSSLCTX))
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroySSL()
|
||||
{
|
||||
if (mOpenSSLCTX != nullptr)
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX* getOpenSSLCTX()
|
||||
{
|
||||
return mOpenSSLCTX;
|
||||
}
|
||||
#endif
|
||||
|
||||
class SSLHelper : public brynet::base::NonCopyable,
|
||||
public std::enable_shared_from_this<SSLHelper>
|
||||
static Ptr Create()
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<SSLHelper>;
|
||||
class make_shared_enabler : public SSLHelper
|
||||
{
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
|
||||
protected:
|
||||
SSLHelper() BRYNET_NOEXCEPT
|
||||
{
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
bool initSSL(const std::string& certificate,
|
||||
const std::string& privatekey)
|
||||
{
|
||||
std::call_once(initCryptoThreadSafeSupportOnceFlag,
|
||||
InitCryptoThreadSafeSupport);
|
||||
|
||||
if (mOpenSSLCTX != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (certificate.empty() || privatekey.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mOpenSSLCTX = SSL_CTX_new(SSLv23_method());
|
||||
SSL_CTX_set_client_CA_list(mOpenSSLCTX,
|
||||
SSL_load_client_CA_file(certificate.c_str()));
|
||||
SSL_CTX_set_verify_depth(mOpenSSLCTX, 10);
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(mOpenSSLCTX,
|
||||
certificate.c_str()) <= 0)
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(mOpenSSLCTX,
|
||||
privatekey.c_str(),
|
||||
SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSL_CTX_check_private_key(mOpenSSLCTX))
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroySSL()
|
||||
{
|
||||
if (mOpenSSLCTX != nullptr)
|
||||
{
|
||||
SSL_CTX_free(mOpenSSLCTX);
|
||||
mOpenSSLCTX = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX* getOpenSSLCTX()
|
||||
{
|
||||
return mOpenSSLCTX;
|
||||
}
|
||||
mOpenSSLCTX = nullptr;
|
||||
#endif
|
||||
static Ptr Create()
|
||||
{
|
||||
class make_shared_enabler : public SSLHelper {};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
SSLHelper() BRYNET_NOEXCEPT
|
||||
{
|
||||
virtual ~SSLHelper() BRYNET_NOEXCEPT
|
||||
{
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
mOpenSSLCTX = nullptr;
|
||||
destroySSL();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~SSLHelper() BRYNET_NOEXCEPT
|
||||
{
|
||||
private:
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
destroySSL();
|
||||
SSL_CTX* mOpenSSLCTX;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
SSL_CTX* mOpenSSLCTX;
|
||||
#endif
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
60
libs/brynet/net/SendableMsg.hpp
Normal file
60
libs/brynet/net/SendableMsg.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class SendableMsg
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<SendableMsg>;
|
||||
|
||||
virtual ~SendableMsg() = default;
|
||||
|
||||
virtual const void* data() = 0;
|
||||
virtual size_t size() = 0;
|
||||
};
|
||||
|
||||
class StringSendMsg : public SendableMsg
|
||||
{
|
||||
public:
|
||||
explicit StringSendMsg(const char* buffer, size_t len)
|
||||
: mMsg(buffer, len)
|
||||
{}
|
||||
|
||||
explicit StringSendMsg(const std::string& buffer)
|
||||
: mMsg(buffer)
|
||||
{}
|
||||
|
||||
explicit StringSendMsg(std::string&& buffer)
|
||||
: mMsg(std::move(buffer))
|
||||
{}
|
||||
|
||||
const void* data() override
|
||||
{
|
||||
return static_cast<const void*>(mMsg.data());
|
||||
}
|
||||
size_t size() override
|
||||
{
|
||||
return mMsg.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mMsg;
|
||||
};
|
||||
|
||||
static SendableMsg::Ptr MakeStringMsg(const char* buffer, size_t len)
|
||||
{
|
||||
return std::make_shared<StringSendMsg>(buffer, len);
|
||||
}
|
||||
|
||||
static SendableMsg::Ptr MakeStringMsg(const std::string& buffer)
|
||||
{
|
||||
return std::make_shared<StringSendMsg>(buffer);
|
||||
}
|
||||
|
||||
static SendableMsg::Ptr MakeStringMsg(std::string&& buffer)
|
||||
{
|
||||
return std::make_shared<StringSendMsg>(std::move(buffer));
|
||||
}
|
||||
|
||||
}}// namespace brynet::net
|
@ -1,230 +1,226 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/SocketLibFunction.hpp>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class TcpConnection;
|
||||
class TcpConnection;
|
||||
|
||||
class UniqueFd final : public brynet::base::NonCopyable
|
||||
class UniqueFd final : public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit UniqueFd(BrynetSocketFD fd)
|
||||
: mFD(fd)
|
||||
{}
|
||||
|
||||
~UniqueFd()
|
||||
{
|
||||
brynet::net::base::SocketClose(mFD);
|
||||
}
|
||||
|
||||
UniqueFd(const UniqueFd& other) = delete;
|
||||
UniqueFd& operator=(const UniqueFd& other) = delete;
|
||||
|
||||
BrynetSocketFD getFD() const
|
||||
{
|
||||
return mFD;
|
||||
}
|
||||
|
||||
private:
|
||||
BrynetSocketFD mFD;
|
||||
};
|
||||
|
||||
class TcpSocket : public brynet::base::NonCopyable
|
||||
{
|
||||
private:
|
||||
class TcpSocketDeleter
|
||||
{
|
||||
public:
|
||||
explicit UniqueFd(BrynetSocketFD fd)
|
||||
:
|
||||
mFD(fd)
|
||||
{}
|
||||
|
||||
~UniqueFd()
|
||||
void operator()(TcpSocket* ptr) const
|
||||
{
|
||||
brynet::net::base::SocketClose(mFD);
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
UniqueFd(const UniqueFd& other) = delete;
|
||||
UniqueFd& operator=(const UniqueFd& other) = delete;
|
||||
|
||||
BrynetSocketFD getFD() const
|
||||
{
|
||||
return mFD;
|
||||
}
|
||||
|
||||
private:
|
||||
BrynetSocketFD mFD;
|
||||
};
|
||||
|
||||
class TcpSocket : public brynet::base::NonCopyable
|
||||
public:
|
||||
using Ptr = std::unique_ptr<TcpSocket, TcpSocketDeleter>;
|
||||
|
||||
public:
|
||||
static Ptr Create(BrynetSocketFD fd, bool serverSide)
|
||||
{
|
||||
private:
|
||||
class TcpSocketDeleter
|
||||
class make_unique_enabler : public TcpSocket
|
||||
{
|
||||
public:
|
||||
void operator()(TcpSocket* ptr) const
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
make_unique_enabler(BrynetSocketFD fd, bool serverSide)
|
||||
: TcpSocket(fd, serverSide)
|
||||
{}
|
||||
};
|
||||
public:
|
||||
using Ptr = std::unique_ptr<TcpSocket, TcpSocketDeleter>;
|
||||
|
||||
return Ptr(new make_unique_enabler(fd, serverSide));
|
||||
}
|
||||
|
||||
public:
|
||||
void setNodelay() const
|
||||
{
|
||||
brynet::net::base::SocketNodelay(mFD);
|
||||
}
|
||||
|
||||
bool setNonblock() const
|
||||
{
|
||||
return brynet::net::base::SocketNonblock(mFD);
|
||||
}
|
||||
|
||||
void setSendSize(int sdSize) const
|
||||
{
|
||||
brynet::net::base::SocketSetSendSize(mFD, sdSize);
|
||||
}
|
||||
|
||||
void setRecvSize(int rdSize) const
|
||||
{
|
||||
brynet::net::base::SocketSetRecvSize(mFD, rdSize);
|
||||
}
|
||||
|
||||
std::string getRemoteIP() const
|
||||
{
|
||||
return brynet::net::base::GetIPOfSocket(mFD);
|
||||
}
|
||||
|
||||
bool isServerSide() const
|
||||
{
|
||||
return mServerSide;
|
||||
}
|
||||
|
||||
protected:
|
||||
TcpSocket(BrynetSocketFD fd, bool serverSide)
|
||||
: mFD(fd),
|
||||
mServerSide(serverSide)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TcpSocket()
|
||||
{
|
||||
brynet::net::base::SocketClose(mFD);
|
||||
}
|
||||
|
||||
BrynetSocketFD getFD() const
|
||||
{
|
||||
return mFD;
|
||||
}
|
||||
|
||||
private:
|
||||
const BrynetSocketFD mFD;
|
||||
const bool mServerSide;
|
||||
|
||||
friend class TcpConnection;
|
||||
};
|
||||
|
||||
class EintrError : public std::exception
|
||||
{
|
||||
};
|
||||
|
||||
class AcceptError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit AcceptError(int errorCode)
|
||||
: std::runtime_error(std::to_string(errorCode)),
|
||||
mErrorCode(errorCode)
|
||||
{}
|
||||
|
||||
int getErrorCode() const
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
private:
|
||||
int mErrorCode;
|
||||
};
|
||||
|
||||
class ListenSocket : public brynet::base::NonCopyable
|
||||
{
|
||||
private:
|
||||
class ListenSocketDeleter
|
||||
{
|
||||
public:
|
||||
static Ptr Create(BrynetSocketFD fd, bool serverSide)
|
||||
void operator()(ListenSocket* ptr) const
|
||||
{
|
||||
class make_unique_enabler : public TcpSocket
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using Ptr = std::unique_ptr<ListenSocket, ListenSocketDeleter>;
|
||||
|
||||
public:
|
||||
TcpSocket::Ptr accept()
|
||||
{
|
||||
const auto clientFD = brynet::net::base::Accept(mFD, nullptr, nullptr);
|
||||
if (clientFD == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
if (BRYNET_ERRNO == EMFILE)
|
||||
{
|
||||
public:
|
||||
make_unique_enabler(BrynetSocketFD fd, bool serverSide)
|
||||
:
|
||||
TcpSocket(fd, serverSide)
|
||||
{}
|
||||
};
|
||||
|
||||
return Ptr(new make_unique_enabler(fd, serverSide));
|
||||
// Thanks libev and muduo.
|
||||
// Read the section named "The special problem of
|
||||
// accept()ing when you can't" in libev's doc.
|
||||
// By Marc Lehmann, author of libev.
|
||||
mIdle.reset();
|
||||
TcpSocket::Create(brynet::net::base::Accept(mFD, nullptr, nullptr), true);
|
||||
mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
|
||||
}
|
||||
#endif
|
||||
if (BRYNET_ERRNO == EINTR)
|
||||
{
|
||||
throw EintrError();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw AcceptError(BRYNET_ERRNO);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void setNodelay() const
|
||||
{
|
||||
brynet::net::base::SocketNodelay(mFD);
|
||||
}
|
||||
return TcpSocket::Create(clientFD, true);
|
||||
}
|
||||
|
||||
bool setNonblock() const
|
||||
{
|
||||
return brynet::net::base::SocketNonblock(mFD);
|
||||
}
|
||||
|
||||
void setSendSize(int sdSize) const
|
||||
{
|
||||
brynet::net::base::SocketSetSendSize(mFD, sdSize);
|
||||
}
|
||||
|
||||
void setRecvSize(int rdSize) const
|
||||
{
|
||||
brynet::net::base::SocketSetRecvSize(mFD, rdSize);
|
||||
}
|
||||
|
||||
std::string getRemoteIP() const
|
||||
{
|
||||
return brynet::net::base::GetIPOfSocket(mFD);
|
||||
}
|
||||
|
||||
bool isServerSide() const
|
||||
{
|
||||
return mServerSide;
|
||||
}
|
||||
|
||||
protected:
|
||||
TcpSocket(BrynetSocketFD fd, bool serverSide)
|
||||
:
|
||||
mFD(fd),
|
||||
mServerSide(serverSide)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TcpSocket()
|
||||
{
|
||||
brynet::net::base::SocketClose(mFD);
|
||||
}
|
||||
|
||||
BrynetSocketFD getFD() const
|
||||
{
|
||||
return mFD;
|
||||
}
|
||||
|
||||
private:
|
||||
const BrynetSocketFD mFD;
|
||||
const bool mServerSide;
|
||||
|
||||
friend class TcpConnection;
|
||||
};
|
||||
|
||||
class EintrError : public std::exception
|
||||
public:
|
||||
static Ptr Create(BrynetSocketFD fd)
|
||||
{
|
||||
};
|
||||
|
||||
class AcceptError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit AcceptError(int errorCode)
|
||||
:
|
||||
std::runtime_error(std::to_string(errorCode)),
|
||||
mErrorCode(errorCode)
|
||||
{}
|
||||
|
||||
int getErrorCode() const
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
private:
|
||||
int mErrorCode;
|
||||
};
|
||||
|
||||
class ListenSocket : public brynet::base::NonCopyable
|
||||
{
|
||||
private:
|
||||
class ListenSocketDeleter
|
||||
class make_unique_enabler : public ListenSocket
|
||||
{
|
||||
public:
|
||||
void operator()(ListenSocket* ptr) const
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
explicit make_unique_enabler(BrynetSocketFD fd)
|
||||
: ListenSocket(fd)
|
||||
{}
|
||||
};
|
||||
public:
|
||||
using Ptr = std::unique_ptr<ListenSocket, ListenSocketDeleter>;
|
||||
|
||||
public:
|
||||
TcpSocket::Ptr accept()
|
||||
{
|
||||
const auto clientFD = brynet::net::base::Accept(mFD, nullptr, nullptr);
|
||||
if (clientFD == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
return Ptr(new make_unique_enabler(fd));
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit ListenSocket(BrynetSocketFD fd)
|
||||
: mFD(fd)
|
||||
{
|
||||
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
if (BRYNET_ERRNO == EMFILE)
|
||||
{
|
||||
// Thanks libev and muduo.
|
||||
// Read the section named "The special problem of
|
||||
// accept()ing when you can't" in libev's doc.
|
||||
// By Marc Lehmann, author of libev.
|
||||
mIdle.reset();
|
||||
TcpSocket::Create(brynet::net::base::Accept(mFD, nullptr, nullptr), true);
|
||||
mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
|
||||
}
|
||||
mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
|
||||
#endif
|
||||
if (BRYNET_ERRNO == EINTR)
|
||||
{
|
||||
throw EintrError();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw AcceptError(BRYNET_ERRNO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TcpSocket::Create(clientFD, true);
|
||||
}
|
||||
virtual ~ListenSocket()
|
||||
{
|
||||
brynet::net::base::SocketClose(mFD);
|
||||
}
|
||||
|
||||
public:
|
||||
static Ptr Create(BrynetSocketFD fd)
|
||||
{
|
||||
class make_unique_enabler : public ListenSocket
|
||||
{
|
||||
public:
|
||||
explicit make_unique_enabler(BrynetSocketFD fd)
|
||||
: ListenSocket(fd)
|
||||
{}
|
||||
};
|
||||
|
||||
return Ptr(new make_unique_enabler(fd));
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit ListenSocket(BrynetSocketFD fd)
|
||||
:
|
||||
mFD(fd)
|
||||
{
|
||||
private:
|
||||
const BrynetSocketFD mFD;
|
||||
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~ListenSocket()
|
||||
{
|
||||
brynet::net::base::SocketClose(mFD);
|
||||
}
|
||||
|
||||
private:
|
||||
const BrynetSocketFD mFD;
|
||||
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
brynet::net::TcpSocket::Ptr mIdle;
|
||||
brynet::net::TcpSocket::Ptr mIdle;
|
||||
#endif
|
||||
|
||||
friend class TcpConnection;
|
||||
};
|
||||
friend class TcpConnection;
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
@ -1,329 +1,339 @@
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include <brynet/net/SocketLibTypes.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace net { namespace base {
|
||||
|
||||
static bool InitSocket()
|
||||
{
|
||||
bool ret = true;
|
||||
static bool InitSocket()
|
||||
{
|
||||
bool ret = true;
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
static WSADATA g_WSAData;
|
||||
static bool WinSockIsInit = false;
|
||||
if (WinSockIsInit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (WSAStartup(MAKEWORD(2, 2), &g_WSAData) == 0)
|
||||
{
|
||||
WinSockIsInit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
static WSADATA g_WSAData;
|
||||
static bool WinSockIsInit = false;
|
||||
if (WinSockIsInit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (WSAStartup(MAKEWORD(2, 2), &g_WSAData) == 0)
|
||||
{
|
||||
WinSockIsInit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void DestroySocket()
|
||||
{
|
||||
static void DestroySocket()
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
WSACleanup();
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int SocketNodelay(BrynetSocketFD fd)
|
||||
{
|
||||
const int flag = 1;
|
||||
return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag));
|
||||
}
|
||||
static int SocketNodelay(BrynetSocketFD fd)
|
||||
{
|
||||
const int flag = 1;
|
||||
return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*) &flag, sizeof(flag));
|
||||
}
|
||||
|
||||
static bool SocketBlock(BrynetSocketFD fd)
|
||||
{
|
||||
int err;
|
||||
unsigned long ul = false;
|
||||
static bool SocketBlock(BrynetSocketFD fd)
|
||||
{
|
||||
int err;
|
||||
unsigned long ul = false;
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
err = ioctlsocket(fd, FIONBIO, &ul);
|
||||
err = ioctlsocket(fd, FIONBIO, &ul);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
err = ioctl(fd, FIONBIO, &ul);
|
||||
err = ioctl(fd, FIONBIO, &ul);
|
||||
#endif
|
||||
|
||||
return err != BRYNET_SOCKET_ERROR;
|
||||
}
|
||||
return err != BRYNET_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
static bool SocketNonblock(BrynetSocketFD fd)
|
||||
{
|
||||
int err;
|
||||
unsigned long ul = true;
|
||||
static bool SocketNonblock(BrynetSocketFD fd)
|
||||
{
|
||||
int err;
|
||||
unsigned long ul = true;
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
err = ioctlsocket(fd, FIONBIO, &ul);
|
||||
err = ioctlsocket(fd, FIONBIO, &ul);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
err = ioctl(fd, FIONBIO, &ul);
|
||||
err = ioctl(fd, FIONBIO, &ul);
|
||||
#endif
|
||||
|
||||
return err != BRYNET_SOCKET_ERROR;
|
||||
}
|
||||
return err != BRYNET_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
static int SocketSetSendSize(BrynetSocketFD fd, int sd_size)
|
||||
{
|
||||
return ::setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&sd_size, sizeof(sd_size));
|
||||
}
|
||||
static int SocketSetSendSize(BrynetSocketFD fd, int sd_size)
|
||||
{
|
||||
return ::setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*) &sd_size, sizeof(sd_size));
|
||||
}
|
||||
|
||||
static int SocketSetRecvSize(BrynetSocketFD fd, int rd_size)
|
||||
{
|
||||
return ::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&rd_size, sizeof(rd_size));
|
||||
}
|
||||
static int SocketSetRecvSize(BrynetSocketFD fd, int rd_size)
|
||||
{
|
||||
return ::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &rd_size, sizeof(rd_size));
|
||||
}
|
||||
|
||||
static BrynetSocketFD SocketCreate(int af, int type, int protocol)
|
||||
{
|
||||
return ::socket(af, type, protocol);
|
||||
}
|
||||
|
||||
static void SocketClose(BrynetSocketFD fd)
|
||||
{
|
||||
static int SocketSetReusePort(BrynetSocketFD fd)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
::closesocket(fd);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
::close(fd);
|
||||
return 0;
|
||||
#else
|
||||
int enable = 1;
|
||||
return ::setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static BrynetSocketFD Connect(bool isIPV6, const std::string& server_ip, int port)
|
||||
static BrynetSocketFD SocketCreate(int af, int type, int protocol)
|
||||
{
|
||||
return ::socket(af, type, protocol);
|
||||
}
|
||||
|
||||
static void SocketClose(BrynetSocketFD fd)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
::closesocket(fd);
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
::close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BrynetSocketFD Connect(bool isIPV6, const std::string& server_ip, int port)
|
||||
{
|
||||
InitSocket();
|
||||
|
||||
struct sockaddr_in ip4Addr = sockaddr_in();
|
||||
struct sockaddr_in6 ip6Addr = sockaddr_in6();
|
||||
struct sockaddr_in* paddr = &ip4Addr;
|
||||
int addrLen = sizeof(ip4Addr);
|
||||
|
||||
BrynetSocketFD clientfd = isIPV6 ? SocketCreate(AF_INET6, SOCK_STREAM, 0) : SocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (clientfd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
InitSocket();
|
||||
|
||||
struct sockaddr_in ip4Addr = sockaddr_in();
|
||||
struct sockaddr_in6 ip6Addr = sockaddr_in6();
|
||||
struct sockaddr_in* paddr = &ip4Addr;
|
||||
int addrLen = sizeof(ip4Addr);
|
||||
|
||||
BrynetSocketFD clientfd = isIPV6 ?
|
||||
SocketCreate(AF_INET6, SOCK_STREAM, 0) :
|
||||
SocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (clientfd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
return clientfd;
|
||||
}
|
||||
|
||||
bool ptonResult = false;
|
||||
if (isIPV6)
|
||||
{
|
||||
ip6Addr.sin6_family = AF_INET6;
|
||||
ip6Addr.sin6_port = htons(port);
|
||||
ptonResult = inet_pton(AF_INET6,
|
||||
server_ip.c_str(),
|
||||
&ip6Addr.sin6_addr) > 0;
|
||||
paddr = (struct sockaddr_in*) & ip6Addr;
|
||||
addrLen = sizeof(ip6Addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip4Addr.sin_family = AF_INET;
|
||||
ip4Addr.sin_port = htons(port);
|
||||
ptonResult = inet_pton(AF_INET,
|
||||
server_ip.c_str(),
|
||||
&ip4Addr.sin_addr) > 0;
|
||||
}
|
||||
|
||||
if (!ptonResult)
|
||||
{
|
||||
SocketClose(clientfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
while (::connect(clientfd, (struct sockaddr*)paddr, addrLen) < 0)
|
||||
{
|
||||
if (EINTR == BRYNET_ERRNO)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SocketClose(clientfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return clientfd;
|
||||
}
|
||||
|
||||
static BrynetSocketFD Listen(bool isIPV6, const char* ip, int port, int back_num)
|
||||
bool ptonResult = false;
|
||||
if (isIPV6)
|
||||
{
|
||||
InitSocket();
|
||||
|
||||
struct sockaddr_in ip4Addr = sockaddr_in();
|
||||
struct sockaddr_in6 ip6Addr = sockaddr_in6();
|
||||
struct sockaddr_in* paddr = &ip4Addr;
|
||||
int addrLen = sizeof(ip4Addr);
|
||||
|
||||
const auto socketfd = isIPV6 ?
|
||||
socket(AF_INET6, SOCK_STREAM, 0) :
|
||||
socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socketfd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
bool ptonResult = false;
|
||||
if (isIPV6)
|
||||
{
|
||||
ip6Addr.sin6_family = AF_INET6;
|
||||
ip6Addr.sin6_port = htons(port);
|
||||
ptonResult = inet_pton(AF_INET6, ip, &ip6Addr.sin6_addr) > 0;
|
||||
paddr = (struct sockaddr_in*) & ip6Addr;
|
||||
addrLen = sizeof(ip6Addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip4Addr.sin_family = AF_INET;
|
||||
ip4Addr.sin_port = htons(port);
|
||||
ip4Addr.sin_addr.s_addr = INADDR_ANY;
|
||||
ptonResult = inet_pton(AF_INET, ip, &ip4Addr.sin_addr) > 0;
|
||||
}
|
||||
|
||||
const int reuseaddr_value = 1;
|
||||
if (!ptonResult ||
|
||||
::setsockopt(socketfd,
|
||||
SOL_SOCKET,
|
||||
SO_REUSEADDR,
|
||||
(const char*)&reuseaddr_value,
|
||||
sizeof(int)) < 0)
|
||||
{
|
||||
SocketClose(socketfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
const int bindRet = ::bind(socketfd, (struct sockaddr*)paddr, addrLen);
|
||||
if (bindRet == BRYNET_SOCKET_ERROR ||
|
||||
listen(socketfd, back_num) == BRYNET_SOCKET_ERROR)
|
||||
{
|
||||
SocketClose(socketfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return socketfd;
|
||||
ip6Addr.sin6_family = AF_INET6;
|
||||
ip6Addr.sin6_port = htons(port);
|
||||
ptonResult = inet_pton(AF_INET6,
|
||||
server_ip.c_str(),
|
||||
&ip6Addr.sin6_addr) > 0;
|
||||
paddr = (struct sockaddr_in*) &ip6Addr;
|
||||
addrLen = sizeof(ip6Addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip4Addr.sin_family = AF_INET;
|
||||
ip4Addr.sin_port = htons(port);
|
||||
ptonResult = inet_pton(AF_INET,
|
||||
server_ip.c_str(),
|
||||
&ip4Addr.sin_addr) > 0;
|
||||
}
|
||||
|
||||
static std::string getIPString(const struct sockaddr* sa)
|
||||
if (!ptonResult)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
using PAddrType = PVOID;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
using PAddrType = const void*;
|
||||
#endif
|
||||
char tmp[INET6_ADDRSTRLEN] = { 0 };
|
||||
switch (sa->sa_family)
|
||||
SocketClose(clientfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
while (::connect(clientfd, (struct sockaddr*) paddr, addrLen) < 0)
|
||||
{
|
||||
if (EINTR == BRYNET_ERRNO)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SocketClose(clientfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return clientfd;
|
||||
}
|
||||
|
||||
static BrynetSocketFD Listen(bool isIPV6, const char* ip, int port, int back_num, bool enabledReusePort)
|
||||
{
|
||||
InitSocket();
|
||||
|
||||
struct sockaddr_in ip4Addr = sockaddr_in();
|
||||
struct sockaddr_in6 ip6Addr = sockaddr_in6();
|
||||
struct sockaddr_in* paddr = &ip4Addr;
|
||||
int addrLen = sizeof(ip4Addr);
|
||||
|
||||
const auto socketfd = isIPV6 ? socket(AF_INET6, SOCK_STREAM, 0) : socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socketfd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
bool ptonResult = false;
|
||||
if (isIPV6)
|
||||
{
|
||||
ip6Addr.sin6_family = AF_INET6;
|
||||
ip6Addr.sin6_port = htons(port);
|
||||
ptonResult = inet_pton(AF_INET6, ip, &ip6Addr.sin6_addr) > 0;
|
||||
paddr = (struct sockaddr_in*) &ip6Addr;
|
||||
addrLen = sizeof(ip6Addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip4Addr.sin_family = AF_INET;
|
||||
ip4Addr.sin_port = htons(port);
|
||||
ip4Addr.sin_addr.s_addr = INADDR_ANY;
|
||||
ptonResult = inet_pton(AF_INET, ip, &ip4Addr.sin_addr) > 0;
|
||||
}
|
||||
|
||||
const int reuseaddr_value = 1;
|
||||
if (!ptonResult ||
|
||||
::setsockopt(socketfd,
|
||||
SOL_SOCKET,
|
||||
SO_REUSEADDR,
|
||||
(const char*) &reuseaddr_value,
|
||||
sizeof(int)) < 0)
|
||||
{
|
||||
SocketClose(socketfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (enabledReusePort && SocketSetReusePort(socketfd) < 0)
|
||||
{
|
||||
SocketClose(socketfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
const int bindRet = ::bind(socketfd, (struct sockaddr*) paddr, addrLen);
|
||||
if (bindRet == BRYNET_SOCKET_ERROR ||
|
||||
listen(socketfd, back_num) == BRYNET_SOCKET_ERROR)
|
||||
{
|
||||
SocketClose(socketfd);
|
||||
return BRYNET_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return socketfd;
|
||||
}
|
||||
|
||||
static std::string getIPString(const struct sockaddr* sa)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
using PAddrType = PVOID;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
using PAddrType = const void*;
|
||||
#endif
|
||||
char tmp[INET6_ADDRSTRLEN] = {0};
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET, (PAddrType)(&(((const struct sockaddr_in*)sa)->sin_addr)),
|
||||
tmp, sizeof(tmp));
|
||||
inet_ntop(AF_INET, (PAddrType)(&(((const struct sockaddr_in*) sa)->sin_addr)),
|
||||
tmp, sizeof(tmp));
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, (PAddrType)(&(((const struct sockaddr_in6*)sa)->sin6_addr)),
|
||||
tmp, sizeof(tmp));
|
||||
inet_ntop(AF_INET6, (PAddrType)(&(((const struct sockaddr_in6*) sa)->sin6_addr)),
|
||||
tmp, sizeof(tmp));
|
||||
break;
|
||||
default:
|
||||
return "Unknown AF";
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static std::string GetIPOfSocket(BrynetSocketFD fd)
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static std::string GetIPOfSocket(BrynetSocketFD fd)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
struct sockaddr name = sockaddr();
|
||||
int namelen = sizeof(name);
|
||||
if (::getpeername(fd, (struct sockaddr*) & name, &namelen) == 0)
|
||||
{
|
||||
return getIPString(&name);
|
||||
}
|
||||
struct sockaddr name = sockaddr();
|
||||
int namelen = sizeof(name);
|
||||
if (::getpeername(fd, (struct sockaddr*) &name, &namelen) == 0)
|
||||
{
|
||||
return getIPString(&name);
|
||||
}
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
struct sockaddr_in name = sockaddr_in();
|
||||
socklen_t namelen = sizeof(name);
|
||||
if (::getpeername(fd, (struct sockaddr*) & name, &namelen) == 0)
|
||||
{
|
||||
return getIPString((const struct sockaddr*) & name);
|
||||
}
|
||||
struct sockaddr_in name = sockaddr_in();
|
||||
socklen_t namelen = sizeof(name);
|
||||
if (::getpeername(fd, (struct sockaddr*) &name, &namelen) == 0)
|
||||
{
|
||||
return getIPString((const struct sockaddr*) &name);
|
||||
}
|
||||
#endif
|
||||
|
||||
return "";
|
||||
return "";
|
||||
}
|
||||
|
||||
static int SocketSend(BrynetSocketFD fd, const char* buffer, int len)
|
||||
{
|
||||
int transnum = ::send(fd, buffer, len, 0);
|
||||
if (transnum < 0 && BRYNET_EWOULDBLOCK == BRYNET_ERRNO)
|
||||
{
|
||||
transnum = 0;
|
||||
}
|
||||
|
||||
static int SocketSend(BrynetSocketFD fd, const char* buffer, int len)
|
||||
{
|
||||
int transnum = ::send(fd, buffer, len, 0);
|
||||
if (transnum < 0 && BRYNET_EWOULDBLOCK == BRYNET_ERRNO)
|
||||
{
|
||||
transnum = 0;
|
||||
}
|
||||
/* send error if transnum < 0 */
|
||||
return transnum;
|
||||
}
|
||||
|
||||
/* send error if transnum < 0 */
|
||||
return transnum;
|
||||
}
|
||||
static BrynetSocketFD Accept(BrynetSocketFD listenSocket, struct sockaddr* addr, socklen_t* addrLen)
|
||||
{
|
||||
return ::accept(listenSocket, addr, addrLen);
|
||||
}
|
||||
|
||||
static BrynetSocketFD Accept(BrynetSocketFD listenSocket, struct sockaddr* addr, socklen_t* addrLen)
|
||||
static struct sockaddr_in6 getPeerAddr(BrynetSocketFD sockfd)
|
||||
{
|
||||
struct sockaddr_in6 peeraddr = sockaddr_in6();
|
||||
auto addrlen = static_cast<socklen_t>(sizeof peeraddr);
|
||||
if (::getpeername(sockfd, (struct sockaddr*) (&peeraddr), &addrlen) < 0)
|
||||
{
|
||||
return ::accept(listenSocket, addr, addrLen);
|
||||
}
|
||||
|
||||
static struct sockaddr_in6 getPeerAddr(BrynetSocketFD sockfd)
|
||||
{
|
||||
struct sockaddr_in6 peeraddr = sockaddr_in6();
|
||||
auto addrlen = static_cast<socklen_t>(sizeof peeraddr);
|
||||
if (::getpeername(sockfd, (struct sockaddr*)(&peeraddr), &addrlen) < 0)
|
||||
{
|
||||
return peeraddr;
|
||||
}
|
||||
return peeraddr;
|
||||
}
|
||||
return peeraddr;
|
||||
}
|
||||
|
||||
static struct sockaddr_in6 getLocalAddr(BrynetSocketFD sockfd)
|
||||
static struct sockaddr_in6 getLocalAddr(BrynetSocketFD sockfd)
|
||||
{
|
||||
struct sockaddr_in6 localaddr = sockaddr_in6();
|
||||
auto addrlen = static_cast<socklen_t>(sizeof localaddr);
|
||||
if (::getsockname(sockfd, (struct sockaddr*) (&localaddr), &addrlen) < 0)
|
||||
{
|
||||
struct sockaddr_in6 localaddr = sockaddr_in6();
|
||||
auto addrlen = static_cast<socklen_t>(sizeof localaddr);
|
||||
if (::getsockname(sockfd, (struct sockaddr*)(&localaddr), &addrlen) < 0)
|
||||
{
|
||||
return localaddr;
|
||||
}
|
||||
return localaddr;
|
||||
}
|
||||
return localaddr;
|
||||
}
|
||||
|
||||
static bool IsSelfConnect(BrynetSocketFD fd)
|
||||
static bool IsSelfConnect(BrynetSocketFD fd)
|
||||
{
|
||||
struct sockaddr_in6 localaddr = getLocalAddr(fd);
|
||||
struct sockaddr_in6 peeraddr = getPeerAddr(fd);
|
||||
|
||||
if (localaddr.sin6_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in6 localaddr = getLocalAddr(fd);
|
||||
struct sockaddr_in6 peeraddr = getPeerAddr(fd);
|
||||
|
||||
if (localaddr.sin6_family == AF_INET)
|
||||
{
|
||||
const struct sockaddr_in* laddr4 = reinterpret_cast<struct sockaddr_in*>(&localaddr);
|
||||
const struct sockaddr_in* raddr4 = reinterpret_cast<struct sockaddr_in*>(&peeraddr);
|
||||
return laddr4->sin_port == raddr4->sin_port
|
||||
&& laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr;
|
||||
}
|
||||
else if (localaddr.sin6_family == AF_INET6)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
return localaddr.sin6_port == peeraddr.sin6_port
|
||||
&& memcmp(&localaddr.sin6_addr.u.Byte,
|
||||
&peeraddr.sin6_addr.u.Byte,
|
||||
sizeof localaddr.sin6_addr.u.Byte) == 0;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
return localaddr.sin6_port == peeraddr.sin6_port
|
||||
&& memcmp(&localaddr.sin6_addr.s6_addr,
|
||||
&peeraddr.sin6_addr.s6_addr,
|
||||
sizeof localaddr.sin6_addr.s6_addr) == 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const struct sockaddr_in* laddr4 = reinterpret_cast<struct sockaddr_in*>(&localaddr);
|
||||
const struct sockaddr_in* raddr4 = reinterpret_cast<struct sockaddr_in*>(&peeraddr);
|
||||
return laddr4->sin_port == raddr4->sin_port && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr;
|
||||
}
|
||||
else if (localaddr.sin6_family == AF_INET6)
|
||||
{
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
return localaddr.sin6_port == peeraddr.sin6_port && memcmp(&localaddr.sin6_addr.u.Byte,
|
||||
&peeraddr.sin6_addr.u.Byte,
|
||||
sizeof localaddr.sin6_addr.u.Byte) == 0;
|
||||
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||
return localaddr.sin6_port == peeraddr.sin6_port && memcmp(&localaddr.sin6_addr.s6_addr,
|
||||
&peeraddr.sin6_addr.s6_addr,
|
||||
sizeof localaddr.sin6_addr.s6_addr) == 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::base
|
||||
|
@ -3,47 +3,48 @@
|
||||
#include <brynet/base/Platform.hpp>
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
#include <winsock2.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <WinError.h>
|
||||
#include <winsock.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <errno.h>
|
||||
#include <winsock.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#else
|
||||
#error "Unsupported OS, please commit an issuse."
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,88 +4,46 @@
|
||||
|
||||
namespace brynet { namespace net {
|
||||
|
||||
class AddSocketOption
|
||||
using ConnectionOption = detail::ConnectionOption;
|
||||
class TcpService : public detail::TcpServiceDetail,
|
||||
public std::enable_shared_from_this<TcpService>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<TcpService>;
|
||||
using FrameCallback = detail::TcpServiceDetail::FrameCallback;
|
||||
|
||||
public:
|
||||
static Ptr Create()
|
||||
{
|
||||
private:
|
||||
using AddSocketOptionFunc = detail::AddSocketOptionFunc;
|
||||
using AddSocketOptionInfo = detail::AddSocketOptionInfo;
|
||||
struct make_shared_enabler : public TcpService
|
||||
{
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
|
||||
public:
|
||||
static AddSocketOptionFunc AddEnterCallback(
|
||||
TcpConnection::EnterCallback callback)
|
||||
{
|
||||
return [callback](AddSocketOptionInfo& option) {
|
||||
option.enterCallback.push_back(callback);
|
||||
};
|
||||
}
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
static AddSocketOptionFunc WithClientSideSSL()
|
||||
{
|
||||
return [](AddSocketOptionInfo& option) {
|
||||
option.useSSL = true;
|
||||
};
|
||||
}
|
||||
static AddSocketOptionFunc WithServerSideSSL(SSLHelper::Ptr sslHelper)
|
||||
{
|
||||
return [sslHelper](AddSocketOptionInfo& option) {
|
||||
option.sslHelper = sslHelper;
|
||||
option.useSSL = true;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
static AddSocketOptionFunc WithMaxRecvBufferSize(size_t size)
|
||||
{
|
||||
return [size](AddSocketOptionInfo& option) {
|
||||
option.maxRecvBufferSize = size;
|
||||
};
|
||||
}
|
||||
static AddSocketOptionFunc WithForceSameThreadLoop(bool same)
|
||||
{
|
||||
return [same](AddSocketOptionInfo& option) {
|
||||
option.forceSameThreadLoop = same;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class TcpService : public detail::TcpServiceDetail,
|
||||
public std::enable_shared_from_this<TcpService>
|
||||
void startWorkerThread(size_t threadNum,
|
||||
FrameCallback callback = nullptr)
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<TcpService>;
|
||||
using FrameCallback = detail::TcpServiceDetail::FrameCallback;
|
||||
detail::TcpServiceDetail::startWorkerThread(threadNum, callback);
|
||||
}
|
||||
|
||||
public:
|
||||
static Ptr Create()
|
||||
{
|
||||
struct make_shared_enabler : public TcpService {};
|
||||
return std::make_shared<make_shared_enabler>();
|
||||
}
|
||||
void stopWorkerThread()
|
||||
{
|
||||
detail::TcpServiceDetail::stopWorkerThread();
|
||||
}
|
||||
|
||||
void startWorkerThread(size_t threadNum,
|
||||
FrameCallback callback = nullptr)
|
||||
{
|
||||
detail::TcpServiceDetail::startWorkerThread(threadNum, callback);
|
||||
}
|
||||
bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption options)
|
||||
{
|
||||
return detail::TcpServiceDetail::addTcpConnection(std::move(socket), options);
|
||||
}
|
||||
|
||||
void stopWorkerThread()
|
||||
{
|
||||
detail::TcpServiceDetail::stopWorkerThread();
|
||||
}
|
||||
EventLoop::Ptr getRandomEventLoop()
|
||||
{
|
||||
return detail::TcpServiceDetail::getRandomEventLoop();
|
||||
}
|
||||
|
||||
template<typename... Options>
|
||||
bool addTcpConnection(TcpSocket::Ptr socket,
|
||||
const Options& ... options)
|
||||
{
|
||||
return detail::TcpServiceDetail::addTcpConnection(std::move(socket), options...);
|
||||
}
|
||||
private:
|
||||
TcpService() = default;
|
||||
};
|
||||
|
||||
EventLoop::Ptr getRandomEventLoop()
|
||||
{
|
||||
return detail::TcpServiceDetail::getRandomEventLoop();
|
||||
}
|
||||
|
||||
private:
|
||||
TcpService() = default;
|
||||
};
|
||||
|
||||
} }
|
||||
}}// namespace brynet::net
|
||||
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <brynet/net/TcpConnection.hpp>
|
||||
#include <brynet/net/SSLHelper.hpp>
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class AddSocketOptionInfo final
|
||||
{
|
||||
public:
|
||||
AddSocketOptionInfo()
|
||||
{
|
||||
useSSL = false;
|
||||
forceSameThreadLoop = false;
|
||||
maxRecvBufferSize = 128;
|
||||
}
|
||||
|
||||
std::vector<TcpConnection::EnterCallback> enterCallback;
|
||||
SSLHelper::Ptr sslHelper;
|
||||
bool useSSL;
|
||||
bool forceSameThreadLoop;
|
||||
size_t maxRecvBufferSize;
|
||||
};
|
||||
|
||||
using AddSocketOptionFunc = std::function<void(AddSocketOptionInfo& option)>;
|
||||
|
||||
} } }
|
18
libs/brynet/net/detail/ConnectionOption.hpp
Normal file
18
libs/brynet/net/detail/ConnectionOption.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <brynet/net/SSLHelper.hpp>
|
||||
#include <brynet/net/TcpConnection.hpp>
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class ConnectionOption final
|
||||
{
|
||||
public:
|
||||
std::vector<TcpConnection::EnterCallback> enterCallback;
|
||||
SSLHelper::Ptr sslHelper;
|
||||
bool useSSL = false;
|
||||
bool forceSameThreadLoop = false;
|
||||
size_t maxRecvBufferSize = 128;
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::detail
|
@ -1,23 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <brynet/base/CPP_VERSION.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/EventLoop.hpp>
|
||||
#include <brynet/net/Exception.hpp>
|
||||
#include <brynet/net/detail/ConnectorWorkInfo.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/CPP_VERSION.hpp>
|
||||
#include <brynet/base/Any.hpp>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/net/SocketLibFunction.hpp>
|
||||
#include <brynet/net/Poller.hpp>
|
||||
#include <brynet/net/Exception.hpp>
|
||||
#include <brynet/net/EventLoop.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/net/detail/ConnectorWorkInfo.hpp>
|
||||
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
#include <shared_mutex>
|
||||
#else
|
||||
@ -26,136 +17,131 @@
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class AsyncConnectorDetail : public brynet::base::NonCopyable
|
||||
class AsyncConnectorDetail : public brynet::base::NonCopyable
|
||||
{
|
||||
protected:
|
||||
void startWorkerThread()
|
||||
{
|
||||
protected:
|
||||
void startWorkerThread()
|
||||
{
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
||||
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
||||
#else
|
||||
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||
#endif
|
||||
|
||||
if (mThread != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mIsRun = std::make_shared<bool>(true);
|
||||
mWorkInfo = std::make_shared<detail::ConnectorWorkInfo>();
|
||||
mEventLoop = std::make_shared<EventLoop>();
|
||||
|
||||
auto eventLoop = mEventLoop;
|
||||
auto workerInfo = mWorkInfo;
|
||||
auto isRun = mIsRun;
|
||||
|
||||
mThread = std::make_shared<std::thread>([eventLoop, workerInfo, isRun]() {
|
||||
while (*isRun)
|
||||
{
|
||||
detail::RunOnceCheckConnect(eventLoop, workerInfo);
|
||||
}
|
||||
|
||||
workerInfo->causeAllFailed();
|
||||
});
|
||||
if (mThread != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void stopWorkerThread()
|
||||
{
|
||||
mIsRun = std::make_shared<bool>(true);
|
||||
mWorkInfo = std::make_shared<detail::ConnectorWorkInfo>();
|
||||
mEventLoop = std::make_shared<EventLoop>();
|
||||
|
||||
auto eventLoop = mEventLoop;
|
||||
auto workerInfo = mWorkInfo;
|
||||
auto isRun = mIsRun;
|
||||
|
||||
mThread = std::make_shared<std::thread>([eventLoop, workerInfo, isRun]() {
|
||||
while (*isRun)
|
||||
{
|
||||
detail::RunOnceCheckConnect(eventLoop, workerInfo);
|
||||
}
|
||||
|
||||
workerInfo->causeAllFailed();
|
||||
});
|
||||
}
|
||||
|
||||
void stopWorkerThread()
|
||||
{
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
||||
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
||||
#else
|
||||
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||
#endif
|
||||
|
||||
if (mThread == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mEventLoop->runAsyncFunctor([this]() {
|
||||
*mIsRun = false;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
if (mThread->joinable())
|
||||
{
|
||||
mThread->join();
|
||||
}
|
||||
}
|
||||
catch (std::system_error & e)
|
||||
{
|
||||
(void)e;
|
||||
}
|
||||
|
||||
mEventLoop = nullptr;
|
||||
mWorkInfo = nullptr;
|
||||
mIsRun = nullptr;
|
||||
mThread = nullptr;
|
||||
if (mThread == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void asyncConnect(const std::vector<detail::ConnectOptionFunc>& options)
|
||||
mEventLoop->runAsyncFunctor([this]() {
|
||||
*mIsRun = false;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
if (mThread->joinable())
|
||||
{
|
||||
mThread->join();
|
||||
}
|
||||
}
|
||||
catch (std::system_error& e)
|
||||
{
|
||||
(void) e;
|
||||
}
|
||||
|
||||
mEventLoop = nullptr;
|
||||
mWorkInfo = nullptr;
|
||||
mIsRun = nullptr;
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
void asyncConnect(detail::ConnectOption option)
|
||||
{
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
std::shared_lock<std::shared_mutex> lck(mThreadGuard);
|
||||
std::shared_lock<std::shared_mutex> lck(mThreadGuard);
|
||||
#else
|
||||
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||
#endif
|
||||
detail::ConnectOptionsInfo option;
|
||||
for (const auto& func : options)
|
||||
{
|
||||
func(option);
|
||||
}
|
||||
|
||||
if (option.completedCallback == nullptr && option.faledCallback == nullptr)
|
||||
{
|
||||
throw ConnectException("all callback is nullptr");
|
||||
}
|
||||
if (option.ip.empty())
|
||||
{
|
||||
throw ConnectException("addr is empty");
|
||||
}
|
||||
|
||||
if (!(*mIsRun))
|
||||
{
|
||||
throw ConnectException("work thread already stop");
|
||||
}
|
||||
|
||||
auto workInfo = mWorkInfo;
|
||||
auto address = detail::AsyncConnectAddr(std::move(option.ip),
|
||||
option.port,
|
||||
option.timeout,
|
||||
std::move(option.completedCallback),
|
||||
std::move(option.faledCallback),
|
||||
std::move(option.processCallbacks));
|
||||
mEventLoop->runAsyncFunctor([workInfo, address]() {
|
||||
workInfo->processConnect(address);
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
AsyncConnectorDetail()
|
||||
if (option.completedCallback == nullptr && option.failedCallback == nullptr)
|
||||
{
|
||||
mIsRun = std::make_shared<bool>(false);
|
||||
throw ConnectException("all callback is nullptr");
|
||||
}
|
||||
|
||||
virtual ~AsyncConnectorDetail()
|
||||
if (option.ip.empty())
|
||||
{
|
||||
stopWorkerThread();
|
||||
throw ConnectException("addr is empty");
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<EventLoop> mEventLoop;
|
||||
if (!(*mIsRun))
|
||||
{
|
||||
throw ConnectException("work thread already stop");
|
||||
}
|
||||
|
||||
std::shared_ptr<detail::ConnectorWorkInfo> mWorkInfo;
|
||||
std::shared_ptr<std::thread> mThread;
|
||||
auto workInfo = mWorkInfo;
|
||||
auto address = detail::AsyncConnectAddr(std::move(option.ip),
|
||||
option.port,
|
||||
option.timeout,
|
||||
std::move(option.completedCallback),
|
||||
std::move(option.failedCallback),
|
||||
std::move(option.processCallbacks));
|
||||
mEventLoop->runAsyncFunctor([workInfo, address]() {
|
||||
workInfo->processConnect(address);
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
AsyncConnectorDetail()
|
||||
{
|
||||
mIsRun = std::make_shared<bool>(false);
|
||||
}
|
||||
|
||||
virtual ~AsyncConnectorDetail()
|
||||
{
|
||||
stopWorkerThread();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<EventLoop> mEventLoop;
|
||||
|
||||
std::shared_ptr<detail::ConnectorWorkInfo> mWorkInfo;
|
||||
std::shared_ptr<std::thread> mThread;
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
std::shared_mutex mThreadGuard;
|
||||
std::shared_mutex mThreadGuard;
|
||||
#else
|
||||
std::mutex mThreadGuard;
|
||||
std::mutex mThreadGuard;
|
||||
#endif
|
||||
std::shared_ptr<bool> mIsRun;
|
||||
};
|
||||
std::shared_ptr<bool> mIsRun;
|
||||
};
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::detail
|
||||
|
@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/CPP_VERSION.hpp>
|
||||
#include <brynet/net/SocketLibTypes.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/Poller.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/net/SocketLibTypes.hpp>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||
#include <shared_mutex>
|
||||
@ -17,352 +18,341 @@
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class ConnectOptionsInfo;
|
||||
using ConnectOptionFunc = std::function<void(ConnectOptionsInfo & option)>;
|
||||
class AsyncConnectAddr final
|
||||
{
|
||||
public:
|
||||
using CompletedCallback = std::function<void(TcpSocket::Ptr)>;
|
||||
using ProcessTcpSocketCallback = std::function<void(TcpSocket&)>;
|
||||
using FailedCallback = std::function<void()>;
|
||||
|
||||
class AsyncConnectAddr final
|
||||
public:
|
||||
AsyncConnectAddr(std::string&& ip,
|
||||
int port,
|
||||
std::chrono::nanoseconds timeout,
|
||||
CompletedCallback&& successCB,
|
||||
FailedCallback&& failedCB,
|
||||
std::vector<ProcessTcpSocketCallback>&& processCallbacks)
|
||||
: mIP(std::move(ip)),
|
||||
mPort(port),
|
||||
mTimeout(timeout),
|
||||
mSuccessCB(std::move(successCB)),
|
||||
mFailedCB(std::move(failedCB)),
|
||||
mProcessCallbacks(std::move(processCallbacks))
|
||||
{
|
||||
public:
|
||||
using CompletedCallback = std::function<void(TcpSocket::Ptr)>;
|
||||
using ProcessTcpSocketCallback = std::function<void(TcpSocket&)>;
|
||||
using FailedCallback = std::function<void()>;
|
||||
}
|
||||
|
||||
public:
|
||||
AsyncConnectAddr(std::string&& ip,
|
||||
int port,
|
||||
std::chrono::nanoseconds timeout,
|
||||
CompletedCallback&& successCB,
|
||||
FailedCallback&& failedCB,
|
||||
std::vector<ProcessTcpSocketCallback>&& processCallbacks)
|
||||
:
|
||||
mIP(std::move(ip)),
|
||||
mPort(port),
|
||||
mTimeout(timeout),
|
||||
mSuccessCB(std::move(successCB)),
|
||||
mFailedCB(std::move(failedCB)),
|
||||
mProcessCallbacks(std::move(processCallbacks))
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& getIP() const
|
||||
{
|
||||
return mIP;
|
||||
}
|
||||
|
||||
int getPort() const
|
||||
{
|
||||
return mPort;
|
||||
}
|
||||
|
||||
const CompletedCallback& getSuccessCB() const
|
||||
{
|
||||
return mSuccessCB;
|
||||
}
|
||||
|
||||
const FailedCallback& getFailedCB() const
|
||||
{
|
||||
return mFailedCB;
|
||||
}
|
||||
|
||||
const std::vector<ProcessTcpSocketCallback>& getProcessCallbacks() const
|
||||
{
|
||||
return mProcessCallbacks;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds getTimeout() const
|
||||
{
|
||||
return mTimeout;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string mIP;
|
||||
const int mPort;
|
||||
const std::chrono::nanoseconds mTimeout;
|
||||
const CompletedCallback mSuccessCB;
|
||||
const FailedCallback mFailedCB;
|
||||
const std::vector<ProcessTcpSocketCallback> mProcessCallbacks;
|
||||
};
|
||||
|
||||
class ConnectorWorkInfo final : public brynet::base::NonCopyable
|
||||
const std::string& getIP() const
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<ConnectorWorkInfo>;
|
||||
return mIP;
|
||||
}
|
||||
|
||||
ConnectorWorkInfo() BRYNET_NOEXCEPT
|
||||
int getPort() const
|
||||
{
|
||||
return mPort;
|
||||
}
|
||||
|
||||
const CompletedCallback& getSuccessCB() const
|
||||
{
|
||||
return mSuccessCB;
|
||||
}
|
||||
|
||||
const FailedCallback& getFailedCB() const
|
||||
{
|
||||
return mFailedCB;
|
||||
}
|
||||
|
||||
const std::vector<ProcessTcpSocketCallback>& getProcessCallbacks() const
|
||||
{
|
||||
return mProcessCallbacks;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds getTimeout() const
|
||||
{
|
||||
return mTimeout;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string mIP;
|
||||
const int mPort;
|
||||
const std::chrono::nanoseconds mTimeout;
|
||||
const CompletedCallback mSuccessCB;
|
||||
const FailedCallback mFailedCB;
|
||||
const std::vector<ProcessTcpSocketCallback> mProcessCallbacks;
|
||||
};
|
||||
|
||||
class ConnectorWorkInfo final : public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<ConnectorWorkInfo>;
|
||||
|
||||
ConnectorWorkInfo() BRYNET_NOEXCEPT
|
||||
{
|
||||
mPoller.reset(brynet::base::poller_new());
|
||||
mPollResult.reset(brynet::base::stack_new(1024, sizeof(BrynetSocketFD)));
|
||||
}
|
||||
|
||||
void checkConnectStatus(int millSecond)
|
||||
{
|
||||
if (poller_poll(mPoller.get(), millSecond) <= 0)
|
||||
{
|
||||
mPoller.reset(brynet::base::poller_new());
|
||||
mPollResult.reset(brynet::base::stack_new(1024, sizeof(BrynetSocketFD)));
|
||||
return;
|
||||
}
|
||||
|
||||
void checkConnectStatus(int millsecond)
|
||||
std::set<BrynetSocketFD> totalFds;
|
||||
std::set<BrynetSocketFD> successFds;
|
||||
|
||||
poller_visitor(mPoller.get(), brynet::base::WriteCheck, mPollResult.get());
|
||||
while (true)
|
||||
{
|
||||
if (poller_poll(mPoller.get(), millsecond) <= 0)
|
||||
auto p = stack_popfront(mPollResult.get());
|
||||
if (p == nullptr)
|
||||
{
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
std::set<BrynetSocketFD> totalFds;
|
||||
std::set<BrynetSocketFD> successFds;
|
||||
|
||||
poller_visitor(mPoller.get(), brynet::base::WriteCheck, mPollResult.get());
|
||||
while (true)
|
||||
const auto fd = *(BrynetSocketFD*) p;
|
||||
totalFds.insert(fd);
|
||||
if (isConnectSuccess(fd, false) &&
|
||||
!brynet::net::base::IsSelfConnect(fd))
|
||||
{
|
||||
auto p = stack_popfront(mPollResult.get());
|
||||
if (p == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto fd = *(BrynetSocketFD*)p;
|
||||
totalFds.insert(fd);
|
||||
if (isConnectSuccess(fd, false) &&
|
||||
!brynet::net::base::IsSelfConnect(fd))
|
||||
{
|
||||
successFds.insert(fd);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto fd : totalFds)
|
||||
{
|
||||
poller_remove(mPoller.get(), fd);
|
||||
|
||||
const auto it = mConnectingInfos.find(fd);
|
||||
if (it == mConnectingInfos.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto socket = TcpSocket::Create(fd, false);
|
||||
const auto& connectingInfo = it->second;
|
||||
if (successFds.find(fd) != successFds.end())
|
||||
{
|
||||
for (const auto& process : connectingInfo.processCallbacks)
|
||||
{
|
||||
process(*socket);
|
||||
}
|
||||
if (connectingInfo.successCB != nullptr)
|
||||
{
|
||||
connectingInfo.successCB(std::move(socket));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (connectingInfo.failedCB != nullptr)
|
||||
{
|
||||
connectingInfo.failedCB();
|
||||
}
|
||||
}
|
||||
|
||||
mConnectingInfos.erase(it);
|
||||
successFds.insert(fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool isConnectSuccess(BrynetSocketFD clientfd, bool willCheckWrite) const
|
||||
for (auto fd : totalFds)
|
||||
{
|
||||
if (willCheckWrite && !poller_check(mPoller.get(), clientfd, brynet::base::WriteCheck))
|
||||
poller_remove(mPoller.get(), fd);
|
||||
|
||||
const auto it = mConnectingInfos.find(fd);
|
||||
if (it == mConnectingInfos.end())
|
||||
{
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
int error = BRYNET_SOCKET_ERROR;
|
||||
int len = sizeof(error);
|
||||
if (getsockopt(clientfd,
|
||||
SOL_SOCKET,
|
||||
SO_ERROR,
|
||||
(char*)&error,
|
||||
(socklen_t*)&len) == BRYNET_SOCKET_ERROR)
|
||||
auto socket = TcpSocket::Create(fd, false);
|
||||
const auto& connectingInfo = it->second;
|
||||
if (successFds.find(fd) != successFds.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return error == 0;
|
||||
}
|
||||
|
||||
void checkTimeout()
|
||||
{
|
||||
for (auto it = mConnectingInfos.begin(); it != mConnectingInfos.end();)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if ((now - it->second.startConnectTime) < it->second.timeout)
|
||||
for (const auto& process : connectingInfo.processCallbacks)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
process(*socket);
|
||||
}
|
||||
|
||||
auto fd = it->first;
|
||||
auto cb = it->second.failedCB;
|
||||
|
||||
poller_remove(mPoller.get(), fd);
|
||||
mConnectingInfos.erase(it++);
|
||||
|
||||
brynet::net::base::SocketClose(fd);
|
||||
if (cb != nullptr)
|
||||
if (connectingInfo.successCB != nullptr)
|
||||
{
|
||||
//TODO::don't modify mConnectingInfos in cb
|
||||
cb();
|
||||
connectingInfo.successCB(std::move(socket));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processConnect(const AsyncConnectAddr& addr)
|
||||
{
|
||||
struct sockaddr_in server_addr = sockaddr_in();
|
||||
BrynetSocketFD clientfd = BRYNET_INVALID_SOCKET;
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
const int ExpectedError = WSAEWOULDBLOCK;
|
||||
#else
|
||||
const int ExpectedError = EINPROGRESS;
|
||||
#endif
|
||||
int n = 0;
|
||||
|
||||
brynet::net::base::InitSocket();
|
||||
|
||||
clientfd = brynet::net::base::SocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||
if (clientfd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
goto FAILED;
|
||||
}
|
||||
|
||||
brynet::net::base::SocketNonblock(clientfd);
|
||||
server_addr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, addr.getIP().c_str(), &server_addr.sin_addr.s_addr);
|
||||
server_addr.sin_port = static_cast<decltype(server_addr.sin_port)>(htons(addr.getPort()));
|
||||
|
||||
n = connect(clientfd, (struct sockaddr*) & server_addr, sizeof(struct sockaddr));
|
||||
if (n == 0)
|
||||
{
|
||||
if (brynet::net::base::IsSelfConnect(clientfd))
|
||||
{
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
else if (BRYNET_ERRNO != ExpectedError)
|
||||
{
|
||||
goto FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectingInfo ci;
|
||||
ci.startConnectTime = std::chrono::steady_clock::now();
|
||||
ci.successCB = addr.getSuccessCB();
|
||||
ci.failedCB = addr.getFailedCB();
|
||||
ci.timeout = addr.getTimeout();
|
||||
ci.processCallbacks = addr.getProcessCallbacks();
|
||||
|
||||
mConnectingInfos[clientfd] = ci;
|
||||
poller_add(mPoller.get(), clientfd, brynet::base::WriteCheck);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr.getSuccessCB() != nullptr)
|
||||
{
|
||||
auto tcpSocket = TcpSocket::Create(clientfd, false);
|
||||
for (const auto& process : addr.getProcessCallbacks())
|
||||
if (connectingInfo.failedCB != nullptr)
|
||||
{
|
||||
process(*tcpSocket);
|
||||
}
|
||||
addr.getSuccessCB()(std::move(tcpSocket));
|
||||
}
|
||||
return;
|
||||
|
||||
FAILED:
|
||||
if (clientfd != BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
brynet::net::base::SocketClose(clientfd);
|
||||
clientfd = BRYNET_INVALID_SOCKET;
|
||||
(void)clientfd;
|
||||
}
|
||||
if (addr.getFailedCB() != nullptr)
|
||||
{
|
||||
addr.getFailedCB()();
|
||||
}
|
||||
}
|
||||
|
||||
void causeAllFailed()
|
||||
{
|
||||
auto copyMap = mConnectingInfos;
|
||||
mConnectingInfos.clear();
|
||||
|
||||
for (const auto& v : copyMap)
|
||||
{
|
||||
auto fd = v.first;
|
||||
auto cb = v.second.failedCB;
|
||||
|
||||
poller_remove(mPoller.get(), fd);
|
||||
brynet::net::base::SocketClose(fd);
|
||||
if (cb != nullptr)
|
||||
{
|
||||
cb();
|
||||
connectingInfo.failedCB();
|
||||
}
|
||||
}
|
||||
|
||||
mConnectingInfos.erase(it);
|
||||
}
|
||||
|
||||
private:
|
||||
class ConnectingInfo
|
||||
{
|
||||
public:
|
||||
ConnectingInfo()
|
||||
{
|
||||
timeout = std::chrono::nanoseconds::zero();
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point startConnectTime;
|
||||
std::chrono::nanoseconds timeout;
|
||||
AsyncConnectAddr::CompletedCallback successCB;
|
||||
AsyncConnectAddr::FailedCallback failedCB;
|
||||
std::vector<AsyncConnectAddr::ProcessTcpSocketCallback> processCallbacks;
|
||||
};
|
||||
|
||||
std::map<BrynetSocketFD, ConnectingInfo> mConnectingInfos;
|
||||
|
||||
class PollerDeleter
|
||||
{
|
||||
public:
|
||||
void operator()(struct brynet::base::poller_s* ptr) const
|
||||
{
|
||||
brynet::base::poller_delete(ptr);
|
||||
}
|
||||
};
|
||||
class StackDeleter
|
||||
{
|
||||
public:
|
||||
void operator()(struct brynet::base::stack_s* ptr) const
|
||||
{
|
||||
brynet::base::stack_delete(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<struct brynet::base::poller_s, PollerDeleter> mPoller;
|
||||
std::unique_ptr<struct brynet::base::stack_s, StackDeleter> mPollResult;
|
||||
};
|
||||
|
||||
static void RunOnceCheckConnect(
|
||||
const std::shared_ptr<brynet::net::EventLoop>& eventLoop,
|
||||
const std::shared_ptr<ConnectorWorkInfo>& workerInfo)
|
||||
{
|
||||
eventLoop->loop(std::chrono::milliseconds(10).count());
|
||||
workerInfo->checkConnectStatus(0);
|
||||
workerInfo->checkTimeout();
|
||||
}
|
||||
|
||||
class ConnectOptionsInfo final
|
||||
bool isConnectSuccess(BrynetSocketFD clientfd, bool willCheckWrite) const
|
||||
{
|
||||
public:
|
||||
ConnectOptionsInfo()
|
||||
:
|
||||
port(0),
|
||||
timeout(std::chrono::seconds(10))
|
||||
if (willCheckWrite && !poller_check(mPoller.get(), clientfd, brynet::base::WriteCheck))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string ip;
|
||||
int port;
|
||||
int error = BRYNET_SOCKET_ERROR;
|
||||
int len = sizeof(error);
|
||||
if (getsockopt(clientfd,
|
||||
SOL_SOCKET,
|
||||
SO_ERROR,
|
||||
(char*) &error,
|
||||
(socklen_t*) &len) == BRYNET_SOCKET_ERROR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return error == 0;
|
||||
}
|
||||
|
||||
void checkTimeout()
|
||||
{
|
||||
for (auto it = mConnectingInfos.begin(); it != mConnectingInfos.end();)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if ((now - it->second.startConnectTime) < it->second.timeout)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fd = it->first;
|
||||
auto cb = it->second.failedCB;
|
||||
|
||||
poller_remove(mPoller.get(), fd);
|
||||
mConnectingInfos.erase(it++);
|
||||
|
||||
brynet::net::base::SocketClose(fd);
|
||||
if (cb != nullptr)
|
||||
{
|
||||
//TODO::don't modify mConnectingInfos in cb
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processConnect(const AsyncConnectAddr& addr)
|
||||
{
|
||||
struct sockaddr_in server_addr = sockaddr_in();
|
||||
BrynetSocketFD clientfd = BRYNET_INVALID_SOCKET;
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
const int ExpectedError = WSAEWOULDBLOCK;
|
||||
#else
|
||||
const int ExpectedError = EINPROGRESS;
|
||||
#endif
|
||||
int n = 0;
|
||||
|
||||
brynet::net::base::InitSocket();
|
||||
|
||||
clientfd = brynet::net::base::SocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||
if (clientfd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
goto FAILED;
|
||||
}
|
||||
|
||||
brynet::net::base::SocketNonblock(clientfd);
|
||||
server_addr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, addr.getIP().c_str(), &server_addr.sin_addr.s_addr);
|
||||
server_addr.sin_port = static_cast<decltype(server_addr.sin_port)>(htons(addr.getPort()));
|
||||
|
||||
n = connect(clientfd, (struct sockaddr*) &server_addr, sizeof(struct sockaddr));
|
||||
if (n == 0)
|
||||
{
|
||||
if (brynet::net::base::IsSelfConnect(clientfd))
|
||||
{
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
else if (BRYNET_ERRNO != ExpectedError)
|
||||
{
|
||||
goto FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectingInfo ci;
|
||||
ci.startConnectTime = std::chrono::steady_clock::now();
|
||||
ci.successCB = addr.getSuccessCB();
|
||||
ci.failedCB = addr.getFailedCB();
|
||||
ci.timeout = addr.getTimeout();
|
||||
ci.processCallbacks = addr.getProcessCallbacks();
|
||||
|
||||
mConnectingInfos[clientfd] = ci;
|
||||
poller_add(mPoller.get(), clientfd, brynet::base::WriteCheck);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr.getSuccessCB() != nullptr)
|
||||
{
|
||||
auto tcpSocket = TcpSocket::Create(clientfd, false);
|
||||
for (const auto& process : addr.getProcessCallbacks())
|
||||
{
|
||||
process(*tcpSocket);
|
||||
}
|
||||
addr.getSuccessCB()(std::move(tcpSocket));
|
||||
}
|
||||
return;
|
||||
|
||||
FAILED:
|
||||
if (clientfd != BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
brynet::net::base::SocketClose(clientfd);
|
||||
clientfd = BRYNET_INVALID_SOCKET;
|
||||
(void) clientfd;
|
||||
}
|
||||
if (addr.getFailedCB() != nullptr)
|
||||
{
|
||||
addr.getFailedCB()();
|
||||
}
|
||||
}
|
||||
|
||||
void causeAllFailed()
|
||||
{
|
||||
auto copyMap = mConnectingInfos;
|
||||
mConnectingInfos.clear();
|
||||
|
||||
for (const auto& v : copyMap)
|
||||
{
|
||||
auto fd = v.first;
|
||||
auto cb = v.second.failedCB;
|
||||
|
||||
poller_remove(mPoller.get(), fd);
|
||||
brynet::net::base::SocketClose(fd);
|
||||
if (cb != nullptr)
|
||||
{
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class ConnectingInfo
|
||||
{
|
||||
public:
|
||||
ConnectingInfo()
|
||||
{
|
||||
timeout = std::chrono::nanoseconds::zero();
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point startConnectTime;
|
||||
std::chrono::nanoseconds timeout;
|
||||
AsyncConnectAddr::CompletedCallback successCB;
|
||||
AsyncConnectAddr::FailedCallback failedCB;
|
||||
std::vector<AsyncConnectAddr::ProcessTcpSocketCallback> processCallbacks;
|
||||
AsyncConnectAddr::CompletedCallback completedCallback;
|
||||
AsyncConnectAddr::FailedCallback faledCallback;
|
||||
};
|
||||
|
||||
} } }
|
||||
std::map<BrynetSocketFD, ConnectingInfo> mConnectingInfos;
|
||||
|
||||
class PollerDeleter
|
||||
{
|
||||
public:
|
||||
void operator()(struct brynet::base::poller_s* ptr) const
|
||||
{
|
||||
brynet::base::poller_delete(ptr);
|
||||
}
|
||||
};
|
||||
class StackDeleter
|
||||
{
|
||||
public:
|
||||
void operator()(struct brynet::base::stack_s* ptr) const
|
||||
{
|
||||
brynet::base::stack_delete(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<struct brynet::base::poller_s, PollerDeleter> mPoller;
|
||||
std::unique_ptr<struct brynet::base::stack_s, StackDeleter> mPollResult;
|
||||
};
|
||||
|
||||
static void RunOnceCheckConnect(
|
||||
const std::shared_ptr<brynet::net::EventLoop>& eventLoop,
|
||||
const std::shared_ptr<ConnectorWorkInfo>& workerInfo)
|
||||
{
|
||||
eventLoop->loop(std::chrono::milliseconds(10).count());
|
||||
workerInfo->checkConnectStatus(0);
|
||||
workerInfo->checkTimeout();
|
||||
}
|
||||
|
||||
class ConnectOption final
|
||||
{
|
||||
public:
|
||||
std::string ip;
|
||||
int port = 0;
|
||||
std::chrono::nanoseconds timeout = std::chrono::seconds(10);
|
||||
std::vector<AsyncConnectAddr::ProcessTcpSocketCallback> processCallbacks;
|
||||
AsyncConnectAddr::CompletedCallback completedCallback;
|
||||
AsyncConnectAddr::FailedCallback failedCallback;
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::detail
|
||||
|
@ -1,67 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/EventLoop.hpp>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class TcpServiceDetail;
|
||||
class TcpServiceDetail;
|
||||
|
||||
class IOLoopData : public brynet::base::NonCopyable,
|
||||
public std::enable_shared_from_this<IOLoopData>
|
||||
class IOLoopData : public brynet::base::NonCopyable,
|
||||
public std::enable_shared_from_this<IOLoopData>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<IOLoopData>;
|
||||
|
||||
static Ptr Create(EventLoop::Ptr eventLoop,
|
||||
std::shared_ptr<std::thread> ioThread)
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<IOLoopData>;
|
||||
|
||||
static Ptr Create(EventLoop::Ptr eventLoop,
|
||||
std::shared_ptr<std::thread> ioThread)
|
||||
class make_shared_enabler : public IOLoopData
|
||||
{
|
||||
class make_shared_enabler : public IOLoopData
|
||||
{
|
||||
public:
|
||||
make_shared_enabler(EventLoop::Ptr eventLoop,
|
||||
std::shared_ptr<std::thread> ioThread)
|
||||
:
|
||||
IOLoopData(std::move(eventLoop), std::move(ioThread))
|
||||
{}
|
||||
};
|
||||
public:
|
||||
make_shared_enabler(EventLoop::Ptr eventLoop,
|
||||
std::shared_ptr<std::thread> ioThread)
|
||||
: IOLoopData(std::move(eventLoop), std::move(ioThread))
|
||||
{}
|
||||
};
|
||||
|
||||
return std::make_shared<make_shared_enabler>(std::move(eventLoop),
|
||||
std::move(ioThread));
|
||||
}
|
||||
return std::make_shared<make_shared_enabler>(std::move(eventLoop),
|
||||
std::move(ioThread));
|
||||
}
|
||||
|
||||
const EventLoop::Ptr& getEventLoop() const
|
||||
{
|
||||
return mEventLoop;
|
||||
}
|
||||
const EventLoop::Ptr& getEventLoop() const
|
||||
{
|
||||
return mEventLoop;
|
||||
}
|
||||
|
||||
protected:
|
||||
const std::shared_ptr<std::thread>& getIOThread() const
|
||||
{
|
||||
return mIOThread;
|
||||
}
|
||||
protected:
|
||||
const std::shared_ptr<std::thread>& getIOThread() const
|
||||
{
|
||||
return mIOThread;
|
||||
}
|
||||
|
||||
IOLoopData(EventLoop::Ptr eventLoop,
|
||||
std::shared_ptr<std::thread> ioThread)
|
||||
:
|
||||
mEventLoop(std::move(eventLoop)),
|
||||
mIOThread(std::move(ioThread))
|
||||
{}
|
||||
virtual ~IOLoopData() = default;
|
||||
IOLoopData(EventLoop::Ptr eventLoop,
|
||||
std::shared_ptr<std::thread> ioThread)
|
||||
: mEventLoop(std::move(eventLoop)),
|
||||
mIOThread(std::move(ioThread))
|
||||
{}
|
||||
virtual ~IOLoopData() = default;
|
||||
|
||||
const EventLoop::Ptr mEventLoop;
|
||||
const EventLoop::Ptr mEventLoop;
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::thread> mIOThread;
|
||||
private:
|
||||
std::shared_ptr<std::thread> mIOThread;
|
||||
|
||||
friend class TcpServiceDetail;
|
||||
};
|
||||
friend class TcpServiceDetail;
|
||||
};
|
||||
|
||||
using IOLoopDataPtr = std::shared_ptr<IOLoopData>;
|
||||
using IOLoopDataPtr = std::shared_ptr<IOLoopData>;
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::detail
|
||||
|
@ -1,169 +1,168 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/AsyncConnector.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/net/SocketLibFunction.hpp>
|
||||
#include <brynet/net/wrapper/ConnectionBuilder.hpp>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/net/SocketLibFunction.hpp>
|
||||
#include <brynet/net/AsyncConnector.hpp>
|
||||
#include <brynet/net/wrapper/ConnectionBuilder.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class ListenThreadDetail : public brynet::base::NonCopyable
|
||||
class ListenThreadDetail : public brynet::base::NonCopyable
|
||||
{
|
||||
protected:
|
||||
using AccepCallback = std::function<void(TcpSocket::Ptr)>;
|
||||
using TcpSocketProcessCallback = std::function<void(TcpSocket&)>;
|
||||
|
||||
void startListen()
|
||||
{
|
||||
protected:
|
||||
using AccepCallback = std::function<void(TcpSocket::Ptr)>;
|
||||
using TcpSocketProcessCallback = std::function<void(TcpSocket&)>;
|
||||
std::lock_guard<std::mutex> lck(mListenThreadGuard);
|
||||
|
||||
void startListen()
|
||||
if (mListenThread != nullptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mListenThreadGuard);
|
||||
|
||||
if (mListenThread != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto fd = brynet::net::base::Listen(mIsIPV6, mIP.c_str(), mPort, 512);
|
||||
if (fd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
throw BrynetCommonException(
|
||||
std::string("listen error of:") + std::to_string(BRYNET_ERRNO));
|
||||
}
|
||||
|
||||
mRunListen = std::make_shared<bool>(true);
|
||||
|
||||
auto listenSocket = std::shared_ptr<ListenSocket>(ListenSocket::Create(fd));
|
||||
auto isRunListen = mRunListen;
|
||||
auto callback = mCallback;
|
||||
auto processCallbacks = mProcessCallbacks;
|
||||
mListenThread = std::make_shared<std::thread>(
|
||||
[isRunListen, listenSocket, callback, processCallbacks]() mutable {
|
||||
while (*isRunListen)
|
||||
{
|
||||
auto clientSocket = runOnceListen(listenSocket);
|
||||
if (clientSocket == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*isRunListen)
|
||||
{
|
||||
for (const auto& process : processCallbacks)
|
||||
{
|
||||
process(*clientSocket);
|
||||
}
|
||||
callback(std::move(clientSocket));
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void stopListen()
|
||||
const auto fd = brynet::net::base::Listen(mIsIPV6, mIP.c_str(), mPort, 512, mEnabledReusePort);
|
||||
if (fd == BRYNET_INVALID_SOCKET)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mListenThreadGuard);
|
||||
throw BrynetCommonException(
|
||||
std::string("listen error of:") + std::to_string(BRYNET_ERRNO));
|
||||
}
|
||||
|
||||
if (mListenThread == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mRunListen = std::make_shared<bool>(true);
|
||||
|
||||
*mRunListen = false;
|
||||
auto selfIP = mIP;
|
||||
if (selfIP == "0.0.0.0")
|
||||
{
|
||||
selfIP = "127.0.0.1";
|
||||
}
|
||||
auto listenSocket = std::shared_ptr<ListenSocket>(ListenSocket::Create(fd));
|
||||
auto isRunListen = mRunListen;
|
||||
auto callback = mCallback;
|
||||
auto processCallbacks = mProcessCallbacks;
|
||||
mListenThread = std::make_shared<std::thread>(
|
||||
[isRunListen, listenSocket, callback, processCallbacks]() mutable {
|
||||
while (*isRunListen)
|
||||
{
|
||||
auto clientSocket = runOnceListen(listenSocket);
|
||||
if (clientSocket == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto connector = AsyncConnector::Create();
|
||||
connector->startWorkerThread();
|
||||
if (*isRunListen)
|
||||
{
|
||||
for (const auto& process : processCallbacks)
|
||||
{
|
||||
process(*clientSocket);
|
||||
}
|
||||
callback(std::move(clientSocket));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
wrapper::SocketConnectBuilder connectBuilder;
|
||||
connectBuilder
|
||||
.configureConnector(connector)
|
||||
.configureConnectOptions({
|
||||
ConnectOption::WithTimeout(std::chrono::seconds(2)),
|
||||
ConnectOption::WithAddr(selfIP, mPort)
|
||||
})
|
||||
void stopListen()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mListenThreadGuard);
|
||||
|
||||
if (mListenThread == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*mRunListen = false;
|
||||
auto selfIP = mIP;
|
||||
if (selfIP == "0.0.0.0")
|
||||
{
|
||||
selfIP = "127.0.0.1";
|
||||
}
|
||||
|
||||
auto connector = AsyncConnector::Create();
|
||||
connector->startWorkerThread();
|
||||
|
||||
//TODO:: if the listen enable reuse_port, one time connect may be can't wakeup listen.
|
||||
wrapper::SocketConnectBuilder connectBuilder;
|
||||
(void) connectBuilder
|
||||
.WithConnector(connector)
|
||||
.WithTimeout(std::chrono::seconds(2))
|
||||
.WithAddr(selfIP, mPort)
|
||||
.syncConnect();
|
||||
|
||||
try
|
||||
{
|
||||
if (mListenThread->joinable())
|
||||
{
|
||||
mListenThread->join();
|
||||
}
|
||||
}
|
||||
catch (std::system_error & e)
|
||||
{
|
||||
(void)e;
|
||||
}
|
||||
mListenThread = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
ListenThreadDetail(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks)
|
||||
:
|
||||
mIsIPV6(isIPV6),
|
||||
mIP(ip),
|
||||
mPort(port),
|
||||
mCallback(callback),
|
||||
mProcessCallbacks(processCallbacks)
|
||||
try
|
||||
{
|
||||
if (mCallback == nullptr)
|
||||
if (mListenThread->joinable())
|
||||
{
|
||||
throw BrynetCommonException("accept callback is nullptr");
|
||||
mListenThread->join();
|
||||
}
|
||||
mRunListen = std::make_shared<bool>(false);
|
||||
}
|
||||
|
||||
virtual ~ListenThreadDetail() BRYNET_NOEXCEPT
|
||||
catch (std::system_error& e)
|
||||
{
|
||||
stopListen();
|
||||
(void) e;
|
||||
}
|
||||
mListenThread = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static brynet::net::TcpSocket::Ptr runOnceListen(const std::shared_ptr<ListenSocket>& listenSocket)
|
||||
protected:
|
||||
ListenThreadDetail(bool isIPV6,
|
||||
const std::string& ip,
|
||||
int port,
|
||||
const AccepCallback& callback,
|
||||
const std::vector<TcpSocketProcessCallback>& processCallbacks,
|
||||
bool enabledReusePort)
|
||||
: mIsIPV6(isIPV6),
|
||||
mIP(ip),
|
||||
mPort(port),
|
||||
mCallback(callback),
|
||||
mProcessCallbacks(processCallbacks),
|
||||
mEnabledReusePort(enabledReusePort)
|
||||
{
|
||||
if (mCallback == nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
return listenSocket->accept();
|
||||
}
|
||||
catch (const EintrError & e)
|
||||
{
|
||||
std::cerr << "accept eintr execption:" << e.what() << std::endl;
|
||||
}
|
||||
catch (const AcceptError & e)
|
||||
{
|
||||
std::cerr << "accept execption:" << e.what() << std::endl;
|
||||
}
|
||||
throw BrynetCommonException("accept callback is nullptr");
|
||||
}
|
||||
mRunListen = std::make_shared<bool>(false);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
virtual ~ListenThreadDetail() BRYNET_NOEXCEPT
|
||||
{
|
||||
stopListen();
|
||||
}
|
||||
|
||||
private:
|
||||
static brynet::net::TcpSocket::Ptr runOnceListen(const std::shared_ptr<ListenSocket>& listenSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
return listenSocket->accept();
|
||||
}
|
||||
catch (const EintrError& e)
|
||||
{
|
||||
std::cerr << "accept eintr execption:" << e.what() << std::endl;
|
||||
}
|
||||
catch (const AcceptError& e)
|
||||
{
|
||||
std::cerr << "accept execption:" << e.what() << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
const bool mIsIPV6;
|
||||
const std::string mIP;
|
||||
const int mPort;
|
||||
const AccepCallback mCallback;
|
||||
const std::vector<TcpSocketProcessCallback> mProcessCallbacks;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<bool> mRunListen;
|
||||
std::shared_ptr<std::thread> mListenThread;
|
||||
std::mutex mListenThreadGuard;
|
||||
};
|
||||
private:
|
||||
const bool mIsIPV6;
|
||||
const std::string mIP;
|
||||
const int mPort;
|
||||
const AccepCallback mCallback;
|
||||
const std::vector<TcpSocketProcessCallback> mProcessCallbacks;
|
||||
const bool mEnabledReusePort;
|
||||
|
||||
} } }
|
||||
std::shared_ptr<bool> mRunListen;
|
||||
std::shared_ptr<std::thread> mListenThread;
|
||||
std::mutex mListenThreadGuard;
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::detail
|
||||
|
@ -1,198 +1,177 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/Noexcept.hpp>
|
||||
#include <brynet/net/TcpConnection.hpp>
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/SSLHelper.hpp>
|
||||
#include <brynet/net/Socket.hpp>
|
||||
#include <brynet/net/TcpConnection.hpp>
|
||||
#include <brynet/net/detail/ConnectionOption.hpp>
|
||||
#include <brynet/net/detail/IOLoopData.hpp>
|
||||
#include <brynet/net/detail/AddSocketOptionInfo.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
class TcpServiceDetail : public brynet::base::NonCopyable
|
||||
class TcpServiceDetail : public brynet::base::NonCopyable
|
||||
{
|
||||
protected:
|
||||
using FrameCallback = std::function<void(const EventLoop::Ptr&)>;
|
||||
const static unsigned int sDefaultLoopTimeOutMS = 100;
|
||||
|
||||
void startWorkerThread(size_t threadNum,
|
||||
FrameCallback callback = nullptr)
|
||||
{
|
||||
protected:
|
||||
using FrameCallback = std::function<void(const EventLoop::Ptr&)>;
|
||||
const static unsigned int sDefaultLoopTimeOutMS = 100;
|
||||
std::lock_guard<std::mutex> lck(mServiceGuard);
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
|
||||
void startWorkerThread(size_t threadNum,
|
||||
FrameCallback callback = nullptr)
|
||||
if (!mIOLoopDatas.empty())
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mServiceGuard);
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
|
||||
if (!mIOLoopDatas.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mRunIOLoop = std::make_shared<bool>(true);
|
||||
|
||||
mIOLoopDatas.resize(threadNum);
|
||||
for (auto& v : mIOLoopDatas)
|
||||
{
|
||||
auto eventLoop = std::make_shared<EventLoop>();
|
||||
auto runIoLoop = mRunIOLoop;
|
||||
v = IOLoopData::Create(eventLoop,
|
||||
std::make_shared<std::thread>(
|
||||
[callback, runIoLoop, eventLoop]() {
|
||||
while (*runIoLoop)
|
||||
{
|
||||
eventLoop->loopCompareNearTimer(sDefaultLoopTimeOutMS);
|
||||
if (callback != nullptr)
|
||||
{
|
||||
callback(eventLoop);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void stopWorkerThread()
|
||||
mRunIOLoop = std::make_shared<bool>(true);
|
||||
|
||||
mIOLoopDatas.resize(threadNum);
|
||||
for (auto& v : mIOLoopDatas)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mServiceGuard);
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
auto eventLoop = std::make_shared<EventLoop>();
|
||||
auto runIoLoop = mRunIOLoop;
|
||||
v = IOLoopData::Create(eventLoop,
|
||||
std::make_shared<std::thread>(
|
||||
[callback, runIoLoop, eventLoop]() {
|
||||
while (*runIoLoop)
|
||||
{
|
||||
eventLoop->loopCompareNearTimer(sDefaultLoopTimeOutMS);
|
||||
if (callback != nullptr)
|
||||
{
|
||||
callback(eventLoop);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
*mRunIOLoop = false;
|
||||
void stopWorkerThread()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mServiceGuard);
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
|
||||
for (const auto& v : mIOLoopDatas)
|
||||
*mRunIOLoop = false;
|
||||
|
||||
for (const auto& v : mIOLoopDatas)
|
||||
{
|
||||
v->getEventLoop()->wakeup();
|
||||
try
|
||||
{
|
||||
v->getEventLoop()->wakeup();
|
||||
try
|
||||
if (v->getIOThread()->joinable())
|
||||
{
|
||||
if (v->getIOThread()->joinable())
|
||||
{
|
||||
v->getIOThread()->join();
|
||||
}
|
||||
}
|
||||
catch (std::system_error & e)
|
||||
{
|
||||
(void)e;
|
||||
v->getIOThread()->join();
|
||||
}
|
||||
}
|
||||
mIOLoopDatas.clear();
|
||||
}
|
||||
|
||||
template<typename... Options>
|
||||
bool addTcpConnection(TcpSocket::Ptr socket,
|
||||
const Options& ... options)
|
||||
{
|
||||
return _addTcpConnection(std::move(socket), { options... });
|
||||
}
|
||||
|
||||
EventLoop::Ptr getRandomEventLoop()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
|
||||
const auto ioLoopSize = mIOLoopDatas.size();
|
||||
if (ioLoopSize == 0)
|
||||
catch (std::system_error& e)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else if (ioLoopSize == 1)
|
||||
{
|
||||
return mIOLoopDatas.front()->getEventLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop();
|
||||
(void) e;
|
||||
}
|
||||
}
|
||||
mIOLoopDatas.clear();
|
||||
}
|
||||
|
||||
TcpServiceDetail() BRYNET_NOEXCEPT
|
||||
:
|
||||
mRandom(static_cast<unsigned int>(
|
||||
std::chrono::system_clock::now().time_since_epoch().count()))
|
||||
bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption option)
|
||||
{
|
||||
if (option.maxRecvBufferSize <= 0)
|
||||
{
|
||||
mRunIOLoop = std::make_shared<bool>(false);
|
||||
throw BrynetCommonException("buffer size is zero");
|
||||
}
|
||||
|
||||
virtual ~TcpServiceDetail() BRYNET_NOEXCEPT
|
||||
EventLoop::Ptr eventLoop;
|
||||
if (option.forceSameThreadLoop)
|
||||
{
|
||||
stopWorkerThread();
|
||||
eventLoop = getSameThreadEventLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
eventLoop = getRandomEventLoop();
|
||||
}
|
||||
if (eventLoop == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _addTcpConnection(TcpSocket::Ptr socket,
|
||||
const std::vector<AddSocketOptionFunc>& optionFuncs)
|
||||
auto wrapperEnterCallback = [option](const TcpConnection::Ptr& tcpConnection) {
|
||||
for (const auto& callback : option.enterCallback)
|
||||
{
|
||||
callback(tcpConnection);
|
||||
}
|
||||
};
|
||||
|
||||
if (option.useSSL && option.sslHelper == nullptr)
|
||||
{
|
||||
AddSocketOptionInfo options;
|
||||
for (const auto& v : optionFuncs)
|
||||
{
|
||||
if (v != nullptr)
|
||||
{
|
||||
v(options);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.maxRecvBufferSize <= 0)
|
||||
{
|
||||
throw BrynetCommonException("buffer size is zero");
|
||||
}
|
||||
|
||||
EventLoop::Ptr eventLoop;
|
||||
if (options.forceSameThreadLoop)
|
||||
{
|
||||
eventLoop = getSameThreadEventLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
eventLoop = getRandomEventLoop();
|
||||
}
|
||||
if (eventLoop == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto wrapperEnterCallback = [options](const TcpConnection::Ptr& tcpConnection) {
|
||||
for (const auto& callback : options.enterCallback)
|
||||
{
|
||||
callback(tcpConnection);
|
||||
}
|
||||
};
|
||||
|
||||
if (options.useSSL && options.sslHelper == nullptr)
|
||||
{
|
||||
options.sslHelper = SSLHelper::Create();
|
||||
}
|
||||
|
||||
TcpConnection::Create(std::move(socket),
|
||||
options.maxRecvBufferSize,
|
||||
wrapperEnterCallback,
|
||||
eventLoop,
|
||||
options.sslHelper);
|
||||
|
||||
return true;
|
||||
option.sslHelper = SSLHelper::Create();
|
||||
}
|
||||
|
||||
EventLoop::Ptr getSameThreadEventLoop()
|
||||
TcpConnection::Create(std::move(socket),
|
||||
option.maxRecvBufferSize,
|
||||
wrapperEnterCallback,
|
||||
eventLoop,
|
||||
option.sslHelper);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EventLoop::Ptr getRandomEventLoop()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
|
||||
const auto ioLoopSize = mIOLoopDatas.size();
|
||||
if (ioLoopSize == 0)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
for (const auto& v : mIOLoopDatas)
|
||||
{
|
||||
if (v->getEventLoop()->isInLoopThread())
|
||||
{
|
||||
return v->getEventLoop();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
else if (ioLoopSize == 1)
|
||||
{
|
||||
return mIOLoopDatas.front()->getEventLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<IOLoopDataPtr> mIOLoopDatas;
|
||||
mutable std::mutex mIOLoopGuard;
|
||||
std::shared_ptr<bool> mRunIOLoop;
|
||||
TcpServiceDetail() BRYNET_NOEXCEPT
|
||||
: mRandom(static_cast<unsigned int>(
|
||||
std::chrono::system_clock::now().time_since_epoch().count()))
|
||||
{
|
||||
mRunIOLoop = std::make_shared<bool>(false);
|
||||
}
|
||||
|
||||
std::mutex mServiceGuard;
|
||||
std::mt19937 mRandom;
|
||||
};
|
||||
virtual ~TcpServiceDetail() BRYNET_NOEXCEPT
|
||||
{
|
||||
stopWorkerThread();
|
||||
}
|
||||
|
||||
} } }
|
||||
EventLoop::Ptr getSameThreadEventLoop()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||
for (const auto& v : mIOLoopDatas)
|
||||
{
|
||||
if (v->getEventLoop()->isInLoopThread())
|
||||
{
|
||||
return v->getEventLoop();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<IOLoopDataPtr> mIOLoopDatas;
|
||||
mutable std::mutex mIOLoopGuard;
|
||||
std::shared_ptr<bool> mRunIOLoop;
|
||||
|
||||
std::mutex mServiceGuard;
|
||||
std::mt19937 mRandom;
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::detail
|
||||
|
@ -1,15 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/net/SocketLibFunction.hpp>
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
#include <brynet/net/port/Win.hpp>
|
||||
#endif
|
||||
@ -20,120 +11,119 @@
|
||||
namespace brynet { namespace net { namespace detail {
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit WakeupChannel(HANDLE iocp)
|
||||
: mIOCP(iocp),
|
||||
mWakeupOvl(port::Win::OverlappedType::OverlappedRecv)
|
||||
{
|
||||
public:
|
||||
explicit WakeupChannel(HANDLE iocp)
|
||||
:
|
||||
mIOCP(iocp),
|
||||
mWakeupOvl(port::Win::OverlappedType::OverlappedRecv)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
bool wakeup() BRYNET_NOEXCEPT
|
||||
{
|
||||
return PostQueuedCompletionStatus(mIOCP,
|
||||
0,
|
||||
reinterpret_cast<ULONG_PTR>(this),
|
||||
&mWakeupOvl.base);
|
||||
}
|
||||
bool wakeup() BRYNET_NOEXCEPT
|
||||
{
|
||||
return PostQueuedCompletionStatus(mIOCP,
|
||||
0,
|
||||
reinterpret_cast<ULONG_PTR>(this),
|
||||
&mWakeupOvl.base);
|
||||
}
|
||||
|
||||
private:
|
||||
void canRecv() BRYNET_NOEXCEPT override
|
||||
{
|
||||
;
|
||||
}
|
||||
private:
|
||||
void canRecv(bool) BRYNET_NOEXCEPT override
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void canSend() BRYNET_NOEXCEPT override
|
||||
{
|
||||
;
|
||||
}
|
||||
void canSend() BRYNET_NOEXCEPT override
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void onClose() BRYNET_NOEXCEPT override
|
||||
{
|
||||
;
|
||||
}
|
||||
void onClose() BRYNET_NOEXCEPT override
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
HANDLE mIOCP;
|
||||
port::Win::OverlappedExt mWakeupOvl;
|
||||
};
|
||||
HANDLE mIOCP;
|
||||
port::Win::OverlappedExt mWakeupOvl;
|
||||
};
|
||||
#elif defined BRYNET_PLATFORM_LINUX
|
||||
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit WakeupChannel(BrynetSocketFD fd)
|
||||
: mUniqueFd(fd)
|
||||
{
|
||||
public:
|
||||
explicit WakeupChannel(BrynetSocketFD fd) : mUniqueFd(fd)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
bool wakeup()
|
||||
{
|
||||
uint64_t one = 1;
|
||||
return write(mUniqueFd.getFD(), &one, sizeof one) > 0;
|
||||
}
|
||||
bool wakeup()
|
||||
{
|
||||
uint64_t one = 1;
|
||||
return write(mUniqueFd.getFD(), &one, sizeof one) > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void canRecv() override
|
||||
private:
|
||||
void canRecv(bool) override
|
||||
{
|
||||
char temp[1024 * 10];
|
||||
while (true)
|
||||
{
|
||||
char temp[1024 * 10];
|
||||
while (true)
|
||||
auto n = read(mUniqueFd.getFD(), temp, sizeof(temp));
|
||||
if (n == -1 || static_cast<size_t>(n) < sizeof(temp))
|
||||
{
|
||||
auto n = read(mUniqueFd.getFD(), temp, sizeof(temp));
|
||||
if (n == -1 || static_cast<size_t>(n) < sizeof(temp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void canSend() override
|
||||
{
|
||||
}
|
||||
void canSend() override
|
||||
{
|
||||
}
|
||||
|
||||
void onClose() override
|
||||
{
|
||||
}
|
||||
void onClose() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
UniqueFd mUniqueFd;
|
||||
};
|
||||
private:
|
||||
UniqueFd mUniqueFd;
|
||||
};
|
||||
|
||||
#elif defined BRYNET_PLATFORM_DARWIN
|
||||
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit WakeupChannel(int kqueuefd, int ident)
|
||||
: mKqueueFd(kqueuefd),
|
||||
mUserEvent(ident)
|
||||
{
|
||||
public:
|
||||
explicit WakeupChannel(int kqueuefd, int ident)
|
||||
:
|
||||
mKqueueFd(kqueuefd),
|
||||
mUserEvent(ident)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
bool wakeup()
|
||||
{
|
||||
struct kevent ev;
|
||||
EV_SET(&ev, mUserEvent, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
|
||||
bool wakeup()
|
||||
{
|
||||
struct kevent ev;
|
||||
EV_SET(&ev, mUserEvent, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
|
||||
|
||||
struct timespec timeout = { 0, 0 };
|
||||
return kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout) == 0;
|
||||
}
|
||||
struct timespec timeout = {0, 0};
|
||||
return kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout) == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void canRecv() override
|
||||
{
|
||||
}
|
||||
private:
|
||||
void canRecv(bool) override
|
||||
{
|
||||
}
|
||||
|
||||
void canSend() override
|
||||
{
|
||||
}
|
||||
void canSend() override
|
||||
{
|
||||
}
|
||||
|
||||
void onClose() override
|
||||
{
|
||||
}
|
||||
void onClose() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
int mKqueueFd;
|
||||
int mUserEvent;
|
||||
};
|
||||
private:
|
||||
int mKqueueFd;
|
||||
int mUserEvent;
|
||||
};
|
||||
#endif
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::detail
|
||||
|
@ -1,222 +1,234 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace net { namespace http {
|
||||
|
||||
class HttpQueryParameter final
|
||||
class HttpQueryParameter final
|
||||
{
|
||||
public:
|
||||
void add(const std::string& k, const std::string& v)
|
||||
{
|
||||
public:
|
||||
void add(const std::string& k, const std::string& v)
|
||||
if (!mParameter.empty())
|
||||
{
|
||||
if (!mParameter.empty())
|
||||
{
|
||||
mParameter += "&";
|
||||
}
|
||||
|
||||
mParameter += k;
|
||||
mParameter += "=";
|
||||
mParameter += v;
|
||||
mParameter += "&";
|
||||
}
|
||||
|
||||
const std::string& getResult() const
|
||||
{
|
||||
return mParameter;
|
||||
}
|
||||
mParameter += k;
|
||||
mParameter += "=";
|
||||
mParameter += v;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mParameter;
|
||||
const std::string& getResult() const
|
||||
{
|
||||
return mParameter;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mParameter;
|
||||
};
|
||||
|
||||
class HttpRequest final
|
||||
{
|
||||
public:
|
||||
enum class HTTP_METHOD
|
||||
{
|
||||
HTTP_METHOD_HEAD,
|
||||
HTTP_METHOD_GET,
|
||||
HTTP_METHOD_POST,
|
||||
HTTP_METHOD_PUT,
|
||||
HTTP_METHOD_DELETE,
|
||||
HTTP_METHOD_MAX
|
||||
};
|
||||
|
||||
class HttpRequest final
|
||||
HttpRequest()
|
||||
{
|
||||
public:
|
||||
setMethod(HTTP_METHOD::HTTP_METHOD_GET);
|
||||
}
|
||||
|
||||
enum class HTTP_METHOD
|
||||
{
|
||||
HTTP_METHOD_HEAD,
|
||||
HTTP_METHOD_GET,
|
||||
HTTP_METHOD_POST,
|
||||
HTTP_METHOD_PUT,
|
||||
HTTP_METHOD_DELETE,
|
||||
HTTP_METHOD_MAX
|
||||
};
|
||||
void setMethod(HTTP_METHOD protocol)
|
||||
{
|
||||
mMethod = protocol;
|
||||
assert(mMethod > HTTP_METHOD::HTTP_METHOD_HEAD &&
|
||||
mMethod < HTTP_METHOD::HTTP_METHOD_MAX);
|
||||
}
|
||||
|
||||
HttpRequest()
|
||||
void setHost(const std::string& host)
|
||||
{
|
||||
addHeadValue("Host", host);
|
||||
}
|
||||
|
||||
void setUrl(const std::string& url)
|
||||
{
|
||||
mUrl = url;
|
||||
}
|
||||
|
||||
void setCookie(const std::string& v)
|
||||
{
|
||||
addHeadValue("Cookie", v);
|
||||
}
|
||||
|
||||
void setContentType(const std::string& v)
|
||||
{
|
||||
addHeadValue("Content-Type", v);
|
||||
}
|
||||
|
||||
void setQuery(const std::string& query)
|
||||
{
|
||||
mQuery = query;
|
||||
}
|
||||
|
||||
void setBody(const std::string& body)
|
||||
{
|
||||
addHeadValue("Content-Length", std::to_string(body.size()));
|
||||
mBody = body;
|
||||
}
|
||||
|
||||
void setBody(std::string&& body)
|
||||
{
|
||||
addHeadValue("Content-Length", std::to_string(body.size()));
|
||||
mBody = std::move(body);
|
||||
}
|
||||
|
||||
void addHeadValue(const std::string& field,
|
||||
const std::string& value)
|
||||
{
|
||||
mHeadField[field] = value;
|
||||
}
|
||||
|
||||
std::string getResult() const
|
||||
{
|
||||
const auto MethodMax = static_cast<size_t>(HTTP_METHOD::HTTP_METHOD_MAX);
|
||||
const static std::array<std::string, MethodMax> HttpMethodString =
|
||||
{"HEAD", "GET", "POST", "PUT", "DELETE"};
|
||||
|
||||
std::string ret;
|
||||
if (mMethod >= HTTP_METHOD::HTTP_METHOD_HEAD &&
|
||||
mMethod < HTTP_METHOD::HTTP_METHOD_MAX)
|
||||
{
|
||||
setMethod(HTTP_METHOD::HTTP_METHOD_GET);
|
||||
ret += HttpMethodString[static_cast<size_t>(mMethod)];
|
||||
}
|
||||
|
||||
void setMethod(HTTP_METHOD protocol)
|
||||
ret += " ";
|
||||
ret += mUrl;
|
||||
if (!mQuery.empty())
|
||||
{
|
||||
mMethod = protocol;
|
||||
assert(mMethod > HTTP_METHOD::HTTP_METHOD_HEAD &&
|
||||
mMethod < HTTP_METHOD::HTTP_METHOD_MAX);
|
||||
ret += "?";
|
||||
ret += mQuery;
|
||||
}
|
||||
|
||||
void setHost(const std::string& host)
|
||||
ret += " HTTP/1.1\r\n";
|
||||
|
||||
for (auto& v : mHeadField)
|
||||
{
|
||||
addHeadValue("Host", host);
|
||||
}
|
||||
|
||||
void setUrl(const std::string& url)
|
||||
{
|
||||
mUrl = url;
|
||||
}
|
||||
|
||||
void setCookie(const std::string& v)
|
||||
{
|
||||
addHeadValue("Cookie", v);
|
||||
}
|
||||
|
||||
void setContentType(const std::string& v)
|
||||
{
|
||||
addHeadValue("Content-Type", v);
|
||||
}
|
||||
|
||||
void setQuery(const std::string& query)
|
||||
{
|
||||
mQuery = query;
|
||||
}
|
||||
|
||||
void setBody(const std::string& body)
|
||||
{
|
||||
mBody = body;
|
||||
addHeadValue("Content-Length", std::to_string(body.size()));
|
||||
}
|
||||
|
||||
void addHeadValue(const std::string& field,
|
||||
const std::string& value)
|
||||
{
|
||||
mHeadField[field] = value;
|
||||
}
|
||||
|
||||
std::string getResult() const
|
||||
{
|
||||
const auto MethodMax = static_cast<size_t>(HTTP_METHOD::HTTP_METHOD_MAX);
|
||||
const static std::array<std::string, MethodMax> HttpMethodString =
|
||||
{ "HEAD", "GET", "POST", "PUT", "DELETE" };
|
||||
|
||||
std::string ret;
|
||||
if (mMethod >= HTTP_METHOD::HTTP_METHOD_HEAD &&
|
||||
mMethod < HTTP_METHOD::HTTP_METHOD_MAX)
|
||||
{
|
||||
ret += HttpMethodString[static_cast<size_t>(mMethod)];
|
||||
}
|
||||
|
||||
ret += " ";
|
||||
ret += mUrl;
|
||||
if (!mQuery.empty())
|
||||
{
|
||||
ret += "?";
|
||||
ret += mQuery;
|
||||
}
|
||||
|
||||
ret += " HTTP/1.1\r\n";
|
||||
|
||||
for (auto& v : mHeadField)
|
||||
{
|
||||
ret += v.first;
|
||||
ret += ": ";
|
||||
ret += v.second;
|
||||
ret += "\r\n";
|
||||
}
|
||||
|
||||
ret += v.first;
|
||||
ret += ": ";
|
||||
ret += v.second;
|
||||
ret += "\r\n";
|
||||
|
||||
if (!mBody.empty())
|
||||
{
|
||||
ret += mBody;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mUrl;
|
||||
std::string mQuery;
|
||||
std::string mBody;
|
||||
HTTP_METHOD mMethod;
|
||||
std::map<std::string, std::string> mHeadField;
|
||||
ret += "\r\n";
|
||||
|
||||
if (!mBody.empty())
|
||||
{
|
||||
ret += mBody;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mUrl;
|
||||
std::string mQuery;
|
||||
std::string mBody;
|
||||
HTTP_METHOD mMethod;
|
||||
std::map<std::string, std::string> mHeadField;
|
||||
};
|
||||
|
||||
class HttpResponse final
|
||||
{
|
||||
public:
|
||||
enum class HTTP_RESPONSE_STATUS
|
||||
{
|
||||
NONE,
|
||||
OK = 200,
|
||||
};
|
||||
|
||||
class HttpResponse final
|
||||
HttpResponse()
|
||||
: mStatus(HTTP_RESPONSE_STATUS::OK)
|
||||
{
|
||||
public:
|
||||
enum class HTTP_RESPONSE_STATUS
|
||||
{
|
||||
NONE,
|
||||
OK = 200,
|
||||
};
|
||||
}
|
||||
|
||||
HttpResponse() : mStatus(HTTP_RESPONSE_STATUS::OK)
|
||||
{
|
||||
}
|
||||
void setStatus(HTTP_RESPONSE_STATUS status)
|
||||
{
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
void setStatus(HTTP_RESPONSE_STATUS status)
|
||||
{
|
||||
mStatus = status;
|
||||
}
|
||||
void setContentType(const std::string& v)
|
||||
{
|
||||
addHeadValue("Content-Type", v);
|
||||
}
|
||||
|
||||
void setContentType(const std::string& v)
|
||||
{
|
||||
addHeadValue("Content-Type", v);
|
||||
}
|
||||
void addHeadValue(const std::string& field,
|
||||
const std::string& value)
|
||||
{
|
||||
mHeadField[field] = value;
|
||||
}
|
||||
|
||||
void addHeadValue(const std::string& field,
|
||||
const std::string& value)
|
||||
{
|
||||
mHeadField[field] = value;
|
||||
}
|
||||
void setBody(const std::string& body)
|
||||
{
|
||||
addHeadValue("Content-Length", std::to_string(body.size()));
|
||||
mBody = body;
|
||||
}
|
||||
|
||||
void setBody(const std::string& body)
|
||||
{
|
||||
mBody = body;
|
||||
addHeadValue("Content-Length", std::to_string(body.size()));
|
||||
}
|
||||
void setBody(std::string&& body)
|
||||
{
|
||||
addHeadValue("Content-Length", std::to_string(body.size()));
|
||||
mBody = std::move(body);
|
||||
}
|
||||
|
||||
std::string getResult() const
|
||||
{
|
||||
std::string ret = "HTTP/1.1 ";
|
||||
std::string getResult() const
|
||||
{
|
||||
std::string ret = "HTTP/1.1 ";
|
||||
|
||||
ret += std::to_string(static_cast<int>(mStatus));
|
||||
switch (mStatus)
|
||||
{
|
||||
ret += std::to_string(static_cast<int>(mStatus));
|
||||
switch (mStatus)
|
||||
{
|
||||
case HTTP_RESPONSE_STATUS::OK:
|
||||
ret += " OK";
|
||||
break;
|
||||
default:
|
||||
ret += "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
ret += "\r\n";
|
||||
|
||||
for (auto& v : mHeadField)
|
||||
{
|
||||
ret += v.first;
|
||||
ret += ": ";
|
||||
ret += v.second;
|
||||
ret += "\r\n";
|
||||
}
|
||||
|
||||
ret += "\r\n";
|
||||
|
||||
if (!mBody.empty())
|
||||
{
|
||||
ret += mBody;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
HTTP_RESPONSE_STATUS mStatus;
|
||||
std::map<std::string, std::string> mHeadField;
|
||||
std::string mBody;
|
||||
};
|
||||
ret += "\r\n";
|
||||
|
||||
} } }
|
||||
for (auto& v : mHeadField)
|
||||
{
|
||||
ret += v.first;
|
||||
ret += ": ";
|
||||
ret += v.second;
|
||||
ret += "\r\n";
|
||||
}
|
||||
|
||||
ret += "\r\n";
|
||||
|
||||
if (!mBody.empty())
|
||||
{
|
||||
ret += mBody;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
HTTP_RESPONSE_STATUS mStatus;
|
||||
std::map<std::string, std::string> mHeadField;
|
||||
std::string mBody;
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::http
|
||||
|
@ -1,318 +1,327 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <brynet/net/http/WebSocketFormat.hpp>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "http_parser.h"
|
||||
#include <brynet/net/http/WebSocketFormat.hpp>
|
||||
|
||||
namespace brynet { namespace net { namespace http {
|
||||
|
||||
class HttpService;
|
||||
class HttpService;
|
||||
|
||||
class HTTPParser
|
||||
class HTTPParser
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<HTTPParser>;
|
||||
|
||||
explicit HTTPParser(http_parser_type parserType)
|
||||
: mParserType(parserType)
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<HTTPParser>;
|
||||
mLastWasValue = true;
|
||||
|
||||
explicit HTTPParser(http_parser_type parserType)
|
||||
:
|
||||
mParserType(parserType)
|
||||
mIsUpgrade = false;
|
||||
mIsWebSocket = false;
|
||||
mIsKeepAlive = false;
|
||||
mISCompleted = false;
|
||||
mStatusCode = 0;
|
||||
mWSFrameType = WebSocketFormat::WebSocketFrameType::ERROR_FRAME;
|
||||
mSettings.on_status = sStatusHandle;
|
||||
mSettings.on_body = sBodyHandle;
|
||||
mSettings.on_url = sUrlHandle;
|
||||
mSettings.on_header_field = sHeadField;
|
||||
mSettings.on_header_value = sHeadValue;
|
||||
mSettings.on_headers_complete = sHeadComplete;
|
||||
mSettings.on_message_begin = sMessageBegin;
|
||||
mSettings.on_message_complete = sMessageEnd;
|
||||
mSettings.on_chunk_header = sChunkHeader;
|
||||
mSettings.on_chunk_complete = sChunkComplete;
|
||||
mParser.data = this;
|
||||
|
||||
http_parser_init(&mParser, mParserType);
|
||||
}
|
||||
|
||||
virtual ~HTTPParser() = default;
|
||||
|
||||
bool isUpgrade() const
|
||||
{
|
||||
return mIsUpgrade;
|
||||
}
|
||||
|
||||
bool isWebSocket() const
|
||||
{
|
||||
return mIsWebSocket;
|
||||
}
|
||||
|
||||
bool isKeepAlive() const
|
||||
{
|
||||
return mIsKeepAlive;
|
||||
}
|
||||
|
||||
|
||||
bool isCompleted() const
|
||||
{
|
||||
return mISCompleted;
|
||||
}
|
||||
|
||||
int method() const
|
||||
{
|
||||
// mMethod's value defined in http_method, such as HTTP_GET、HTTP_POST.
|
||||
// if mMethod is -1, it's invalid.
|
||||
return mMethod;
|
||||
}
|
||||
|
||||
const std::string& getPath() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
const std::string& getQuery() const
|
||||
{
|
||||
return mQuery;
|
||||
}
|
||||
|
||||
const std::string& getStatus() const
|
||||
{
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
int getStatusCode() const
|
||||
{
|
||||
return mStatusCode;
|
||||
}
|
||||
|
||||
bool hasEntry(const std::string& key,
|
||||
const std::string& value) const
|
||||
{
|
||||
const auto it = mHeadValues.find(key);
|
||||
return it != mHeadValues.end() && value == it->second;
|
||||
}
|
||||
|
||||
bool hasKey(const std::string& key) const
|
||||
{
|
||||
return mHeadValues.find(key) != mHeadValues.end();
|
||||
}
|
||||
|
||||
const std::string& getValue(const std::string& key) const
|
||||
{
|
||||
const static std::string emptystr("");
|
||||
|
||||
auto it = mHeadValues.find(key);
|
||||
if (it != mHeadValues.end())
|
||||
{
|
||||
mLastWasValue = true;
|
||||
return (*it).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return emptystr;
|
||||
}
|
||||
}
|
||||
|
||||
mIsWebSocket = false;
|
||||
mIsKeepAlive = false;
|
||||
mISCompleted = false;
|
||||
mStatusCode = 0;
|
||||
mWSFrameType = WebSocketFormat::WebSocketFrameType::ERROR_FRAME;
|
||||
mSettings.on_status = sStatusHandle;
|
||||
mSettings.on_body = sBodyHandle;
|
||||
mSettings.on_url = sUrlHandle;
|
||||
mSettings.on_header_field = sHeadField;
|
||||
mSettings.on_header_value = sHeadValue;
|
||||
mSettings.on_headers_complete = sHeadComplete;
|
||||
mSettings.on_message_begin = sMessageBegin;
|
||||
mSettings.on_message_complete = sMessageEnd;
|
||||
mSettings.on_chunk_header = sChunkHeader;
|
||||
mSettings.on_chunk_complete = sChunkComplete;
|
||||
mParser.data = this;
|
||||
const std::string& getBody() const
|
||||
{
|
||||
return mBody;
|
||||
}
|
||||
|
||||
std::string& getWSCacheFrame()
|
||||
{
|
||||
return mWSCacheFrame;
|
||||
}
|
||||
|
||||
std::string& getWSParseString()
|
||||
{
|
||||
return mWSParsePayload;
|
||||
}
|
||||
|
||||
WebSocketFormat::WebSocketFrameType getWSFrameType() const
|
||||
{
|
||||
return mWSFrameType;
|
||||
}
|
||||
|
||||
void cacheWSFrameType(WebSocketFormat::WebSocketFrameType frameType)
|
||||
{
|
||||
mWSFrameType = frameType;
|
||||
}
|
||||
|
||||
private:
|
||||
void clearParse()
|
||||
{
|
||||
mMethod = -1;
|
||||
mIsUpgrade = false;
|
||||
mIsWebSocket = false;
|
||||
mISCompleted = false;
|
||||
mLastWasValue = true;
|
||||
mUrl.clear();
|
||||
mQuery.clear();
|
||||
mBody.clear();
|
||||
mStatus.clear();
|
||||
mCurrentField.clear();
|
||||
mCurrentValue.clear();
|
||||
mHeadValues.clear();
|
||||
mPath.clear();
|
||||
}
|
||||
|
||||
size_t tryParse(const char* buffer, size_t len)
|
||||
{
|
||||
const size_t nparsed = http_parser_execute(&mParser, &mSettings, buffer, len);
|
||||
if (mISCompleted)
|
||||
{
|
||||
mIsUpgrade = mParser.upgrade;
|
||||
mIsWebSocket = mIsUpgrade && hasEntry("Upgrade", "websocket");
|
||||
mIsKeepAlive = hasEntry("Connection", "Keep-Alive");
|
||||
mMethod = mParser.method;
|
||||
http_parser_init(&mParser, mParserType);
|
||||
}
|
||||
|
||||
virtual ~HTTPParser() = default;
|
||||
return nparsed;
|
||||
}
|
||||
|
||||
bool isWebSocket() const
|
||||
private:
|
||||
static int sChunkHeader(http_parser* hp)
|
||||
{
|
||||
(void) hp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sChunkComplete(http_parser* hp)
|
||||
{
|
||||
(void) hp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sMessageBegin(http_parser* hp)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
httpParser->clearParse();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sMessageEnd(http_parser* hp)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
httpParser->mISCompleted = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sHeadComplete(http_parser* hp)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
|
||||
if (httpParser->mUrl.empty())
|
||||
{
|
||||
return mIsWebSocket;
|
||||
}
|
||||
|
||||
bool isKeepAlive() const
|
||||
{
|
||||
return mIsKeepAlive;
|
||||
}
|
||||
|
||||
int method() const
|
||||
{
|
||||
// mMethod's value defined in http_method, such as HTTP_GET、HTTP_POST.
|
||||
// if mMethod is -1, it's invalid.
|
||||
return mMethod;
|
||||
}
|
||||
|
||||
const std::string& getPath() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
const std::string& getQuery() const
|
||||
{
|
||||
return mQuery;
|
||||
}
|
||||
|
||||
const std::string& getStatus() const
|
||||
{
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
int getStatusCode() const
|
||||
{
|
||||
return mStatusCode;
|
||||
}
|
||||
|
||||
bool hasEntry(const std::string& key,
|
||||
const std::string& value) const
|
||||
{
|
||||
const auto it = mHeadValues.find(key);
|
||||
return it != mHeadValues.end() && value == it->second;
|
||||
}
|
||||
|
||||
bool hasKey(const std::string& key) const
|
||||
{
|
||||
return mHeadValues.find(key) != mHeadValues.end();
|
||||
}
|
||||
|
||||
const std::string& getValue(const std::string& key) const
|
||||
{
|
||||
const static std::string emptystr("");
|
||||
|
||||
auto it = mHeadValues.find(key);
|
||||
if (it != mHeadValues.end())
|
||||
{
|
||||
return (*it).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return emptystr;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& getBody() const
|
||||
{
|
||||
return mBody;
|
||||
}
|
||||
|
||||
std::string& getWSCacheFrame()
|
||||
{
|
||||
return mWSCacheFrame;
|
||||
}
|
||||
|
||||
std::string& getWSParseString()
|
||||
{
|
||||
return mWSParsePayload;
|
||||
}
|
||||
|
||||
WebSocketFormat::WebSocketFrameType getWSFrameType() const
|
||||
{
|
||||
return mWSFrameType;
|
||||
}
|
||||
|
||||
void cacheWSFrameType(WebSocketFormat::WebSocketFrameType frameType)
|
||||
{
|
||||
mWSFrameType = frameType;
|
||||
}
|
||||
|
||||
private:
|
||||
void clearParse()
|
||||
{
|
||||
mMethod = -1;
|
||||
mISCompleted = false;
|
||||
mLastWasValue = true;
|
||||
mUrl.clear();
|
||||
mQuery.clear();
|
||||
mBody.clear();
|
||||
mStatus.clear();
|
||||
mCurrentField.clear();
|
||||
mCurrentValue.clear();
|
||||
mHeadValues.clear();
|
||||
mPath.clear();
|
||||
}
|
||||
|
||||
size_t tryParse(const char* buffer, size_t len)
|
||||
{
|
||||
const size_t nparsed = http_parser_execute(&mParser, &mSettings, buffer, len);
|
||||
if (mISCompleted)
|
||||
{
|
||||
mIsWebSocket = mParser.upgrade;
|
||||
mIsKeepAlive = hasEntry("Connection", "Keep-Alive");
|
||||
mMethod = mParser.method;
|
||||
http_parser_init(&mParser, mParserType);
|
||||
}
|
||||
|
||||
return nparsed;
|
||||
}
|
||||
|
||||
bool isCompleted() const
|
||||
{
|
||||
return mISCompleted;
|
||||
}
|
||||
|
||||
private:
|
||||
static int sChunkHeader(http_parser* hp)
|
||||
{
|
||||
(void)hp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sChunkComplete(http_parser* hp)
|
||||
struct http_parser_url u;
|
||||
|
||||
const int result = http_parser_parse_url(httpParser->mUrl.data(),
|
||||
httpParser->mUrl.size(),
|
||||
0,
|
||||
&u);
|
||||
if (result != 0)
|
||||
{
|
||||
(void)hp;
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sMessageBegin(http_parser* hp)
|
||||
if (!(u.field_set & (1 << UF_PATH)))
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
httpParser->clearParse();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sMessageEnd(http_parser* hp)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
httpParser->mISCompleted = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sHeadComplete(http_parser* hp)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
|
||||
if (httpParser->mUrl.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct http_parser_url u;
|
||||
|
||||
const int result = http_parser_parse_url(httpParser->mUrl.data(),
|
||||
httpParser->mUrl.size(),
|
||||
0,
|
||||
&u);
|
||||
if (result != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(u.field_set & (1 << UF_PATH)))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"\n\n*** failed to parse PATH in URL %s ***\n\n",
|
||||
fprintf(stderr,
|
||||
"\n\n*** failed to parse PATH in URL %s ***\n\n",
|
||||
httpParser->mUrl.c_str());
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
httpParser->mPath = std::string(
|
||||
httpParser->mUrl.data() + u.field_data[UF_PATH].off,
|
||||
httpParser->mPath = std::string(
|
||||
httpParser->mUrl.data() + u.field_data[UF_PATH].off,
|
||||
u.field_data[UF_PATH].len);
|
||||
if (u.field_set & (1 << UF_QUERY))
|
||||
{
|
||||
httpParser->mQuery = std::string(
|
||||
httpParser->mUrl.data() + u.field_data[UF_QUERY].off,
|
||||
if (u.field_set & (1 << UF_QUERY))
|
||||
{
|
||||
httpParser->mQuery = std::string(
|
||||
httpParser->mUrl.data() + u.field_data[UF_QUERY].off,
|
||||
u.field_data[UF_QUERY].len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sUrlHandle(http_parser* hp, const char* url, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sUrlHandle(http_parser* hp, const char* url, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
httpParser->mUrl.append(url, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sHeadValue(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
auto& value = httpParser->mHeadValues[httpParser->mCurrentField];
|
||||
value.append(at, length);
|
||||
httpParser->mLastWasValue = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sHeadField(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
if (httpParser->mLastWasValue)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
httpParser->mUrl.append(url, length);
|
||||
|
||||
return 0;
|
||||
httpParser->mCurrentField.clear();
|
||||
}
|
||||
httpParser->mCurrentField.append(at, length);
|
||||
httpParser->mLastWasValue = false;
|
||||
|
||||
static int sHeadValue(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
auto& value = httpParser->mHeadValues[httpParser->mCurrentField];
|
||||
value.append(at, length);
|
||||
httpParser->mLastWasValue = true;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sHeadField(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
if (httpParser->mLastWasValue)
|
||||
{
|
||||
httpParser->mCurrentField.clear();
|
||||
}
|
||||
httpParser->mCurrentField.append(at, length);
|
||||
httpParser->mLastWasValue = false;
|
||||
static int sStatusHandle(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
httpParser->mStatus.append(at, length);
|
||||
httpParser->mStatusCode = hp->status_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int sBodyHandle(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*) hp->data;
|
||||
httpParser->mBody.append(at, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sStatusHandle(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
httpParser->mStatus.append(at, length);
|
||||
httpParser->mStatusCode = hp->status_code;
|
||||
return 0;
|
||||
}
|
||||
private:
|
||||
const http_parser_type mParserType;
|
||||
http_parser mParser;
|
||||
http_parser_settings mSettings;
|
||||
|
||||
static int sBodyHandle(http_parser* hp, const char* at, size_t length)
|
||||
{
|
||||
HTTPParser* httpParser = (HTTPParser*)hp->data;
|
||||
httpParser->mBody.append(at, length);
|
||||
return 0;
|
||||
}
|
||||
int mMethod = -1;
|
||||
bool mIsUpgrade = false;
|
||||
bool mIsWebSocket = false;
|
||||
bool mIsKeepAlive;
|
||||
bool mISCompleted;
|
||||
|
||||
private:
|
||||
const http_parser_type mParserType;
|
||||
http_parser mParser;
|
||||
http_parser_settings mSettings;
|
||||
bool mLastWasValue;
|
||||
std::string mCurrentField;
|
||||
std::string mCurrentValue;
|
||||
|
||||
int mMethod = -1;
|
||||
bool mIsWebSocket;
|
||||
bool mIsKeepAlive;
|
||||
bool mISCompleted;
|
||||
std::string mPath;
|
||||
std::string mQuery;
|
||||
std::string mStatus;
|
||||
std::map<std::string, std::string> mHeadValues;
|
||||
int mStatusCode;
|
||||
|
||||
bool mLastWasValue;
|
||||
std::string mCurrentField;
|
||||
std::string mCurrentValue;
|
||||
std::string mUrl;
|
||||
std::string mBody;
|
||||
|
||||
std::string mPath;
|
||||
std::string mQuery;
|
||||
std::string mStatus;
|
||||
std::map<std::string, std::string> mHeadValues;
|
||||
int mStatusCode;
|
||||
std::string mWSCacheFrame;
|
||||
std::string mWSParsePayload;
|
||||
WebSocketFormat::WebSocketFrameType mWSFrameType;
|
||||
|
||||
std::string mUrl;
|
||||
std::string mBody;
|
||||
private:
|
||||
friend class HttpService;
|
||||
};
|
||||
|
||||
std::string mWSCacheFrame;
|
||||
std::string mWSParsePayload;
|
||||
WebSocketFormat::WebSocketFrameType mWSFrameType;
|
||||
|
||||
private:
|
||||
friend class HttpService;
|
||||
};
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::http
|
||||
|
@ -1,342 +1,355 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <brynet/base/NonCopyable.hpp>
|
||||
#include <brynet/base/Any.hpp>
|
||||
#include <brynet/net/TcpService.hpp>
|
||||
#include <brynet/net/http/HttpParser.hpp>
|
||||
#include <brynet/net/http/WebSocketFormat.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace brynet { namespace net { namespace http {
|
||||
|
||||
class HttpService;
|
||||
class HttpSessionHandlers;
|
||||
class HttpService;
|
||||
class HttpSessionHandlers;
|
||||
|
||||
class HttpSession : public brynet::base::NonCopyable
|
||||
class HttpSession : public brynet::base::NonCopyable
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<HttpSession>;
|
||||
|
||||
using EnterCallback = std::function<void(const HttpSession::Ptr&, HttpSessionHandlers&)>;
|
||||
using HttpParserCallback = std::function<void(const HTTPParser&, const HttpSession::Ptr&)>;
|
||||
using WsCallback = std::function<void(const HttpSession::Ptr&,
|
||||
WebSocketFormat::WebSocketFrameType opcode,
|
||||
const std::string& payload)>;
|
||||
|
||||
using ClosedCallback = std::function<void(const HttpSession::Ptr&)>;
|
||||
using WsConnectedCallback = std::function<void(const HttpSession::Ptr&, const HTTPParser&)>;
|
||||
|
||||
public:
|
||||
template<typename PacketType>
|
||||
void send(PacketType&& packet,
|
||||
TcpConnection::PacketSendedCallback&& callback = nullptr)
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<HttpSession>;
|
||||
|
||||
using EnterCallback = std::function <void(const HttpSession::Ptr&, HttpSessionHandlers&)>;
|
||||
using HttpParserCallback = std::function <void(const HTTPParser&, const HttpSession::Ptr&)>;
|
||||
using WsCallback = std::function < void( const HttpSession::Ptr&,
|
||||
WebSocketFormat::WebSocketFrameType opcode,
|
||||
const std::string& payload)>;
|
||||
|
||||
using ClosedCallback = std::function <void(const HttpSession::Ptr&)>;
|
||||
using WsConnectedCallback = std::function <void(const HttpSession::Ptr&, const HTTPParser&)>;
|
||||
|
||||
public:
|
||||
template<typename PacketType>
|
||||
void send(PacketType&& packet,
|
||||
TcpConnection::PacketSendedCallback&& callback = nullptr)
|
||||
{
|
||||
mSession->send(std::forward<PacketType&&>(packet),
|
||||
std::move(callback));
|
||||
}
|
||||
void send(const char* packet,
|
||||
size_t len,
|
||||
TcpConnection::PacketSendedCallback&& callback = nullptr)
|
||||
{
|
||||
mSession->send(packet, len, std::move(callback));
|
||||
}
|
||||
|
||||
void postShutdown() const
|
||||
{
|
||||
mSession->postShutdown();
|
||||
}
|
||||
|
||||
void postClose() const
|
||||
{
|
||||
mSession->postDisConnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit HttpSession(TcpConnection::Ptr session)
|
||||
{
|
||||
mSession = std::move(session);
|
||||
}
|
||||
|
||||
virtual ~HttpSession() = default;
|
||||
|
||||
static Ptr Create(TcpConnection::Ptr session)
|
||||
{
|
||||
class make_shared_enabler : public HttpSession
|
||||
{
|
||||
public:
|
||||
explicit make_shared_enabler(TcpConnection::Ptr session)
|
||||
:
|
||||
HttpSession(std::move(session))
|
||||
{}
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>(std::move(session));
|
||||
}
|
||||
|
||||
const TcpConnection::Ptr& getSession() const
|
||||
{
|
||||
return mSession;
|
||||
}
|
||||
|
||||
const HttpParserCallback& getHttpCallback() const
|
||||
{
|
||||
return mHttpRequestCallback;
|
||||
}
|
||||
|
||||
const ClosedCallback& getCloseCallback() const
|
||||
{
|
||||
return mCloseCallback;
|
||||
}
|
||||
|
||||
const WsCallback& getWSCallback() const
|
||||
{
|
||||
return mWSCallback;
|
||||
}
|
||||
|
||||
const WsConnectedCallback& getWSConnectedCallback() const
|
||||
{
|
||||
return mWSConnectedCallback;
|
||||
}
|
||||
|
||||
private:
|
||||
void setHttpCallback(HttpParserCallback&& callback)
|
||||
{
|
||||
mHttpRequestCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setClosedCallback(ClosedCallback&& callback)
|
||||
{
|
||||
mCloseCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSCallback(WsCallback&& callback)
|
||||
{
|
||||
mWSCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSConnected(WsConnectedCallback&& callback)
|
||||
{
|
||||
mWSConnectedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
TcpConnection::Ptr mSession;
|
||||
HttpParserCallback mHttpRequestCallback;
|
||||
WsCallback mWSCallback;
|
||||
ClosedCallback mCloseCallback;
|
||||
WsConnectedCallback mWSConnectedCallback;
|
||||
|
||||
friend class HttpService;
|
||||
};
|
||||
|
||||
class HttpSessionHandlers
|
||||
mSession->send(std::forward<PacketType&&>(packet),
|
||||
std::move(callback));
|
||||
}
|
||||
void send(const char* packet,
|
||||
size_t len,
|
||||
TcpConnection::PacketSendedCallback&& callback = nullptr)
|
||||
{
|
||||
public:
|
||||
void setHttpCallback(HttpSession::HttpParserCallback&& callback)
|
||||
{
|
||||
mHttpRequestCallback = std::move(callback);
|
||||
}
|
||||
mSession->send(packet, len, std::move(callback));
|
||||
}
|
||||
|
||||
void setClosedCallback(HttpSession::ClosedCallback&& callback)
|
||||
{
|
||||
mCloseCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSCallback(HttpSession::WsCallback&& callback)
|
||||
{
|
||||
mWSCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSConnected(HttpSession::WsConnectedCallback&& callback)
|
||||
{
|
||||
mWSConnectedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
HttpSession::HttpParserCallback mHttpRequestCallback;
|
||||
HttpSession::WsCallback mWSCallback;
|
||||
HttpSession::ClosedCallback mCloseCallback;
|
||||
HttpSession::WsConnectedCallback mWSConnectedCallback;
|
||||
|
||||
friend class HttpService;
|
||||
};
|
||||
|
||||
class HttpService
|
||||
void postShutdown() const
|
||||
{
|
||||
public:
|
||||
static void setup(const TcpConnection::Ptr& session,
|
||||
const HttpSession::EnterCallback& enterCallback)
|
||||
mSession->postShutdown();
|
||||
}
|
||||
|
||||
void postClose() const
|
||||
{
|
||||
mSession->postDisConnect();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit HttpSession(TcpConnection::Ptr session)
|
||||
{
|
||||
mSession = std::move(session);
|
||||
}
|
||||
|
||||
virtual ~HttpSession() = default;
|
||||
|
||||
static Ptr Create(TcpConnection::Ptr session)
|
||||
{
|
||||
class make_shared_enabler : public HttpSession
|
||||
{
|
||||
auto httpSession = HttpSession::Create(session);
|
||||
if (enterCallback != nullptr)
|
||||
{
|
||||
HttpSessionHandlers handlers;
|
||||
enterCallback(httpSession, handlers);
|
||||
httpSession->setHttpCallback(std::move(handlers.mHttpRequestCallback));
|
||||
httpSession->setClosedCallback(std::move(handlers.mCloseCallback));
|
||||
httpSession->setWSCallback(std::move(handlers.mWSCallback));
|
||||
httpSession->setWSConnected(std::move(handlers.mWSConnectedCallback));
|
||||
}
|
||||
HttpService::handle(httpSession);
|
||||
public:
|
||||
explicit make_shared_enabler(TcpConnection::Ptr session)
|
||||
: HttpSession(std::move(session))
|
||||
{}
|
||||
};
|
||||
return std::make_shared<make_shared_enabler>(std::move(session));
|
||||
}
|
||||
|
||||
const TcpConnection::Ptr& getSession() const
|
||||
{
|
||||
return mSession;
|
||||
}
|
||||
|
||||
const HttpParserCallback& getHttpCallback() const
|
||||
{
|
||||
return mHttpRequestCallback;
|
||||
}
|
||||
|
||||
const ClosedCallback& getCloseCallback() const
|
||||
{
|
||||
return mCloseCallback;
|
||||
}
|
||||
|
||||
const WsCallback& getWSCallback() const
|
||||
{
|
||||
return mWSCallback;
|
||||
}
|
||||
|
||||
const WsConnectedCallback& getWSConnectedCallback() const
|
||||
{
|
||||
return mWSConnectedCallback;
|
||||
}
|
||||
|
||||
private:
|
||||
void setHttpCallback(HttpParserCallback&& callback)
|
||||
{
|
||||
mHttpRequestCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setClosedCallback(ClosedCallback&& callback)
|
||||
{
|
||||
mCloseCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSCallback(WsCallback&& callback)
|
||||
{
|
||||
mWSCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSConnected(WsConnectedCallback&& callback)
|
||||
{
|
||||
mWSConnectedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
TcpConnection::Ptr mSession;
|
||||
HttpParserCallback mHttpRequestCallback;
|
||||
WsCallback mWSCallback;
|
||||
ClosedCallback mCloseCallback;
|
||||
WsConnectedCallback mWSConnectedCallback;
|
||||
|
||||
friend class HttpService;
|
||||
};
|
||||
|
||||
class HttpSessionHandlers
|
||||
{
|
||||
public:
|
||||
void setHttpCallback(HttpSession::HttpParserCallback&& callback)
|
||||
{
|
||||
mHttpRequestCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setClosedCallback(HttpSession::ClosedCallback&& callback)
|
||||
{
|
||||
mCloseCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSCallback(HttpSession::WsCallback&& callback)
|
||||
{
|
||||
mWSCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setWSConnected(HttpSession::WsConnectedCallback&& callback)
|
||||
{
|
||||
mWSConnectedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
HttpSession::HttpParserCallback mHttpRequestCallback;
|
||||
HttpSession::WsCallback mWSCallback;
|
||||
HttpSession::ClosedCallback mCloseCallback;
|
||||
HttpSession::WsConnectedCallback mWSConnectedCallback;
|
||||
|
||||
friend class HttpService;
|
||||
};
|
||||
|
||||
class HttpService
|
||||
{
|
||||
public:
|
||||
static void setup(const TcpConnection::Ptr& session,
|
||||
const HttpSession::EnterCallback& enterCallback)
|
||||
{
|
||||
auto httpSession = HttpSession::Create(session);
|
||||
if (enterCallback != nullptr)
|
||||
{
|
||||
HttpSessionHandlers handlers;
|
||||
enterCallback(httpSession, handlers);
|
||||
httpSession->setHttpCallback(std::move(handlers.mHttpRequestCallback));
|
||||
httpSession->setClosedCallback(std::move(handlers.mCloseCallback));
|
||||
httpSession->setWSCallback(std::move(handlers.mWSCallback));
|
||||
httpSession->setWSConnected(std::move(handlers.mWSConnectedCallback));
|
||||
}
|
||||
HttpService::handle(httpSession);
|
||||
}
|
||||
|
||||
private:
|
||||
static void handle(const HttpSession::Ptr& httpSession)
|
||||
{
|
||||
/*TODO::keep alive and timeout close */
|
||||
auto& session = httpSession->getSession();
|
||||
private:
|
||||
static void handle(const HttpSession::Ptr& httpSession)
|
||||
{
|
||||
/*TODO::keep alive and timeout close */
|
||||
auto& session = httpSession->getSession();
|
||||
auto httpParser = std::make_shared<HTTPParser>(HTTP_BOTH);
|
||||
|
||||
session->setDisConnectCallback([httpSession](const TcpConnection::Ptr&) {
|
||||
const auto& tmp = httpSession->getCloseCallback();
|
||||
if (tmp != nullptr)
|
||||
{
|
||||
tmp(httpSession);
|
||||
}
|
||||
});
|
||||
|
||||
auto httpParser = std::make_shared<HTTPParser>(HTTP_BOTH);
|
||||
session->setDataCallback([httpSession, httpParser](
|
||||
brynet::base::BasePacketReader& reader) {
|
||||
size_t retLen = 0;
|
||||
|
||||
if (httpParser->isWebSocket())
|
||||
{
|
||||
retLen = HttpService::ProcessWebSocket( reader.begin(),
|
||||
reader.size(),
|
||||
httpParser,
|
||||
httpSession);
|
||||
}
|
||||
else
|
||||
{
|
||||
retLen = HttpService::ProcessHttp( reader.begin(),
|
||||
reader.size(),
|
||||
httpParser,
|
||||
httpSession);
|
||||
}
|
||||
|
||||
reader.addPos(retLen);
|
||||
reader.savePos();
|
||||
});
|
||||
}
|
||||
|
||||
static size_t ProcessWebSocket(const char* buffer,
|
||||
size_t len,
|
||||
const HTTPParser::Ptr& httpParser,
|
||||
const HttpSession::Ptr& httpSession)
|
||||
{
|
||||
size_t leftLen = len;
|
||||
|
||||
const auto& wsCallback = httpSession->getWSCallback();
|
||||
auto& cacheFrame = httpParser->getWSCacheFrame();
|
||||
auto& parseString = httpParser->getWSParseString();
|
||||
|
||||
while (leftLen > 0)
|
||||
{
|
||||
parseString.clear();
|
||||
|
||||
auto opcode = WebSocketFormat::WebSocketFrameType::ERROR_FRAME;
|
||||
size_t frameSize = 0;
|
||||
bool isFin = false;
|
||||
|
||||
if (!WebSocketFormat::wsFrameExtractBuffer(buffer,
|
||||
leftLen,
|
||||
parseString,
|
||||
opcode,
|
||||
frameSize,
|
||||
isFin))
|
||||
{
|
||||
// 如果没有解析出完整的ws frame则退出函数
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果当前fram的fin为false或者opcode为延续包
|
||||
// 则将当前frame的payload添加到cache
|
||||
if (!isFin ||
|
||||
opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME)
|
||||
{
|
||||
cacheFrame += parseString;
|
||||
parseString.clear();
|
||||
}
|
||||
// 如果当前fram的fin为false,并且opcode不为延续包
|
||||
// 则表示收到分段payload的第一个段(frame),需要缓存当前frame的opcode
|
||||
if (!isFin &&
|
||||
opcode != WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME)
|
||||
{
|
||||
httpParser->cacheWSFrameType(opcode);
|
||||
}
|
||||
|
||||
leftLen -= frameSize;
|
||||
buffer += frameSize;
|
||||
|
||||
if (!isFin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果fin为true,并且opcode为延续包
|
||||
// 则表示分段payload全部接受完毕
|
||||
// 因此需要获取之前第一次收到分段frame的opcode作为整个payload的类型
|
||||
if (opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME)
|
||||
{
|
||||
if (!cacheFrame.empty())
|
||||
{
|
||||
parseString = std::move(cacheFrame);
|
||||
cacheFrame.clear();
|
||||
}
|
||||
opcode = httpParser->getWSFrameType();
|
||||
}
|
||||
|
||||
if (wsCallback != nullptr)
|
||||
{
|
||||
wsCallback(httpSession, opcode, parseString);
|
||||
}
|
||||
}
|
||||
|
||||
return (len - leftLen);
|
||||
}
|
||||
|
||||
static size_t ProcessHttp(const char* buffer,
|
||||
size_t len,
|
||||
const HTTPParser::Ptr& httpParser,
|
||||
const HttpSession::Ptr& httpSession)
|
||||
{
|
||||
size_t retlen = len;
|
||||
session->setDisConnectCallback([httpSession, httpParser](const TcpConnection::Ptr&) {
|
||||
if (!httpParser->isCompleted())
|
||||
{
|
||||
retlen = httpParser->tryParse(buffer, len);
|
||||
if (!httpParser->isCompleted())
|
||||
{
|
||||
return retlen;
|
||||
}
|
||||
// try pass EOF to http parser
|
||||
HttpService::ProcessHttp(nullptr, 0, httpParser, httpSession);
|
||||
}
|
||||
|
||||
const auto& tmp = httpSession->getCloseCallback();
|
||||
if (tmp != nullptr)
|
||||
{
|
||||
tmp(httpSession);
|
||||
}
|
||||
});
|
||||
|
||||
session->setDataCallback([httpSession, httpParser](
|
||||
brynet::base::BasePacketReader& reader) {
|
||||
size_t retLen = 0;
|
||||
|
||||
if (httpParser->isWebSocket())
|
||||
{
|
||||
if (httpParser->hasKey("Sec-WebSocket-Key"))
|
||||
{
|
||||
auto response = WebSocketFormat::wsHandshake(
|
||||
httpParser->getValue("Sec-WebSocket-Key"));
|
||||
httpSession->send(response.c_str(),
|
||||
response.size());
|
||||
}
|
||||
|
||||
const auto& wsConnectedCallback = httpSession->getWSConnectedCallback();
|
||||
if (wsConnectedCallback != nullptr)
|
||||
{
|
||||
wsConnectedCallback(httpSession, *httpParser);
|
||||
}
|
||||
retLen = HttpService::ProcessWebSocket(reader.begin(),
|
||||
reader.size(),
|
||||
httpParser,
|
||||
httpSession);
|
||||
}
|
||||
else if (httpParser->isUpgrade())
|
||||
{
|
||||
// TODO::not support other upgrade protocol
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& httpCallback = httpSession->getHttpCallback();
|
||||
if (httpCallback != nullptr)
|
||||
retLen = HttpService::ProcessHttp(reader.begin(),
|
||||
reader.size(),
|
||||
httpParser,
|
||||
httpSession);
|
||||
// if http_parser_execute not consume all data that indicate cause error in parser.
|
||||
// so we need close connection.
|
||||
if (retLen != reader.size())
|
||||
{
|
||||
httpCallback(*httpParser, httpSession);
|
||||
httpSession->postClose();
|
||||
}
|
||||
}
|
||||
|
||||
return retlen;
|
||||
}
|
||||
};
|
||||
reader.addPos(retLen);
|
||||
reader.savePos();
|
||||
});
|
||||
}
|
||||
|
||||
} } }
|
||||
static size_t ProcessWebSocket(const char* buffer,
|
||||
size_t len,
|
||||
const HTTPParser::Ptr& httpParser,
|
||||
const HttpSession::Ptr& httpSession)
|
||||
{
|
||||
size_t leftLen = len;
|
||||
|
||||
const auto& wsCallback = httpSession->getWSCallback();
|
||||
auto& cacheFrame = httpParser->getWSCacheFrame();
|
||||
auto& parseString = httpParser->getWSParseString();
|
||||
|
||||
while (leftLen > 0)
|
||||
{
|
||||
parseString.clear();
|
||||
|
||||
auto opcode = WebSocketFormat::WebSocketFrameType::ERROR_FRAME;
|
||||
size_t frameSize = 0;
|
||||
bool isFin = false;
|
||||
|
||||
if (!WebSocketFormat::wsFrameExtractBuffer(buffer,
|
||||
leftLen,
|
||||
parseString,
|
||||
opcode,
|
||||
frameSize,
|
||||
isFin))
|
||||
{
|
||||
// 如果没有解析出完整的ws frame则退出函数
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果当前fram的fin为false或者opcode为延续包
|
||||
// 则将当前frame的payload添加到cache
|
||||
if (!isFin ||
|
||||
opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME)
|
||||
{
|
||||
cacheFrame += parseString;
|
||||
parseString.clear();
|
||||
}
|
||||
// 如果当前fram的fin为false,并且opcode不为延续包
|
||||
// 则表示收到分段payload的第一个段(frame),需要缓存当前frame的opcode
|
||||
if (!isFin &&
|
||||
opcode != WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME)
|
||||
{
|
||||
httpParser->cacheWSFrameType(opcode);
|
||||
}
|
||||
|
||||
leftLen -= frameSize;
|
||||
buffer += frameSize;
|
||||
|
||||
if (!isFin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果fin为true,并且opcode为延续包
|
||||
// 则表示分段payload全部接受完毕
|
||||
// 因此需要获取之前第一次收到分段frame的opcode作为整个payload的类型
|
||||
if (opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME)
|
||||
{
|
||||
if (!cacheFrame.empty())
|
||||
{
|
||||
parseString = std::move(cacheFrame);
|
||||
cacheFrame.clear();
|
||||
}
|
||||
opcode = httpParser->getWSFrameType();
|
||||
}
|
||||
|
||||
if (wsCallback != nullptr)
|
||||
{
|
||||
wsCallback(httpSession, opcode, parseString);
|
||||
}
|
||||
}
|
||||
|
||||
return (len - leftLen);
|
||||
}
|
||||
|
||||
static size_t ProcessHttp(const char* buffer,
|
||||
size_t len,
|
||||
const HTTPParser::Ptr& httpParser,
|
||||
const HttpSession::Ptr& httpSession)
|
||||
{
|
||||
size_t retlen = len;
|
||||
if (!httpParser->isCompleted())
|
||||
{
|
||||
retlen = httpParser->tryParse(buffer, len);
|
||||
if (!httpParser->isCompleted())
|
||||
{
|
||||
return retlen;
|
||||
}
|
||||
}
|
||||
|
||||
if (httpParser->isWebSocket())
|
||||
{
|
||||
if (httpParser->hasKey("Sec-WebSocket-Key"))
|
||||
{
|
||||
auto response = WebSocketFormat::wsHandshake(
|
||||
httpParser->getValue("Sec-WebSocket-Key"));
|
||||
httpSession->send(response.c_str(),
|
||||
response.size());
|
||||
}
|
||||
|
||||
const auto& wsConnectedCallback = httpSession->getWSConnectedCallback();
|
||||
if (wsConnectedCallback != nullptr)
|
||||
{
|
||||
wsConnectedCallback(httpSession, *httpParser);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& httpCallback = httpSession->getHttpCallback();
|
||||
if (httpCallback != nullptr)
|
||||
{
|
||||
httpCallback(*httpParser, httpSession);
|
||||
}
|
||||
}
|
||||
|
||||
return retlen;
|
||||
}
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::http
|
||||
|
@ -1,239 +1,239 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
||||
#include <brynet/base/crypto/Base64.hpp>
|
||||
#include <brynet/base/crypto/SHA1.hpp>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
namespace brynet { namespace net { namespace http {
|
||||
|
||||
class WebSocketFormat
|
||||
class WebSocketFormat
|
||||
{
|
||||
public:
|
||||
enum class WebSocketFrameType
|
||||
{
|
||||
public:
|
||||
enum class WebSocketFrameType {
|
||||
ERROR_FRAME = 0xff,
|
||||
CONTINUATION_FRAME = 0x00,
|
||||
TEXT_FRAME = 0x01,
|
||||
BINARY_FRAME = 0x02,
|
||||
CLOSE_FRAME = 0x08,
|
||||
PING_FRAME = 0x09,
|
||||
PONG_FRAME = 0x0A
|
||||
};
|
||||
ERROR_FRAME = 0xff,
|
||||
CONTINUATION_FRAME = 0x00,
|
||||
TEXT_FRAME = 0x01,
|
||||
BINARY_FRAME = 0x02,
|
||||
CLOSE_FRAME = 0x08,
|
||||
PING_FRAME = 0x09,
|
||||
PONG_FRAME = 0x0A
|
||||
};
|
||||
|
||||
static std::string wsHandshake(std::string secKey)
|
||||
{
|
||||
secKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
static std::string wsHandshake(std::string secKey)
|
||||
{
|
||||
secKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
|
||||
CSHA1 s1;
|
||||
s1.Update((unsigned char*)secKey.c_str(), static_cast<unsigned int>(secKey.size()));
|
||||
s1.Final();
|
||||
unsigned char puDest[20];
|
||||
s1.GetHash(puDest);
|
||||
CSHA1 s1;
|
||||
s1.Update((unsigned char*) secKey.c_str(), static_cast<unsigned int>(secKey.size()));
|
||||
s1.Final();
|
||||
unsigned char puDest[20];
|
||||
s1.GetHash(puDest);
|
||||
|
||||
std::string base64Str = brynet::base::crypto::base64_encode((const unsigned char*)puDest, 20);
|
||||
std::string base64Str = brynet::base::crypto::base64_encode((const unsigned char*) puDest, 20);
|
||||
|
||||
std::string response = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
std::string response =
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: ";
|
||||
|
||||
response += base64Str;
|
||||
response += "\r\n\r\n";
|
||||
response += base64Str;
|
||||
response += "\r\n\r\n";
|
||||
|
||||
return response;
|
||||
return response;
|
||||
}
|
||||
|
||||
static bool wsFrameBuild(const char* payload,
|
||||
size_t payloadLen,
|
||||
std::string& frame,
|
||||
WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME,
|
||||
bool isFin = true,
|
||||
bool masking = false)
|
||||
{
|
||||
const auto unixTime = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
static std::mt19937 random(static_cast<unsigned int>(unixTime));
|
||||
|
||||
static_assert(std::is_same<std::string::value_type, char>::value, "");
|
||||
|
||||
const uint8_t head = static_cast<uint8_t>(frame_type) | (isFin ? 0x80 : 0x00);
|
||||
|
||||
frame.clear();
|
||||
frame.push_back(static_cast<char>(head));
|
||||
if (payloadLen <= 125)
|
||||
{
|
||||
// mask << 7 | payloadLen, mask = 0
|
||||
frame.push_back(static_cast<uint8_t>(payloadLen));
|
||||
}
|
||||
else if (payloadLen <= 0xFFFF)
|
||||
{
|
||||
// 126 + 16bit len
|
||||
frame.push_back(126);
|
||||
frame.push_back((payloadLen & 0xFF00) >> 8);
|
||||
frame.push_back(payloadLen & 0x00FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 127 + 64bit len
|
||||
frame.push_back(127);
|
||||
// assume payload len is less than u_int32_max
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(static_cast<char>((payloadLen & 0xFF000000) >> 24));
|
||||
frame.push_back(static_cast<char>((payloadLen & 0x00FF0000) >> 16));
|
||||
frame.push_back(static_cast<char>((payloadLen & 0x0000FF00) >> 8));
|
||||
frame.push_back(static_cast<char>(payloadLen & 0x000000FF));
|
||||
}
|
||||
|
||||
static bool wsFrameBuild(const char* payload,
|
||||
size_t payloadLen,
|
||||
std::string& frame,
|
||||
WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME,
|
||||
bool isFin = true,
|
||||
bool masking = false)
|
||||
if (masking)
|
||||
{
|
||||
const auto unixTime = std::chrono::system_clock::now().
|
||||
time_since_epoch().
|
||||
count();
|
||||
static std::mt19937 random(static_cast<unsigned int>(unixTime));
|
||||
|
||||
static_assert(std::is_same<std::string::value_type, char>::value, "");
|
||||
|
||||
const uint8_t head = static_cast<uint8_t>(frame_type) | (isFin ? 0x80 : 0x00);
|
||||
|
||||
frame.clear();
|
||||
frame.push_back(static_cast<char>(head));
|
||||
if (payloadLen <= 125)
|
||||
{
|
||||
// mask << 7 | payloadLen, mask = 0
|
||||
frame.push_back(static_cast<uint8_t>(payloadLen));
|
||||
}
|
||||
else if (payloadLen <= 0xFFFF)
|
||||
{
|
||||
// 126 + 16bit len
|
||||
frame.push_back(126);
|
||||
frame.push_back((payloadLen & 0xFF00) >> 8);
|
||||
frame.push_back(payloadLen & 0x00FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 127 + 64bit len
|
||||
frame.push_back(127);
|
||||
// assume payload len is less than u_int32_max
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(0x00);
|
||||
frame.push_back(static_cast<char>((payloadLen & 0xFF000000) >> 24));
|
||||
frame.push_back(static_cast<char>((payloadLen & 0x00FF0000) >> 16));
|
||||
frame.push_back(static_cast<char>((payloadLen & 0x0000FF00) >> 8));
|
||||
frame.push_back(static_cast<char>(payloadLen & 0x000000FF));
|
||||
}
|
||||
|
||||
if (masking)
|
||||
{
|
||||
frame[1] = ((uint8_t)frame[1]) | 0x80;
|
||||
uint8_t mask[4];
|
||||
for (auto& m : mask)
|
||||
{
|
||||
m = static_cast<uint8_t>(random());
|
||||
frame.push_back(m);
|
||||
}
|
||||
|
||||
frame.reserve(frame.size() + payloadLen);
|
||||
|
||||
for (size_t i = 0; i < payloadLen; i++)
|
||||
{
|
||||
frame.push_back(static_cast<uint8_t>(payload[i]) ^ mask[i % 4]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.append(payload, payloadLen);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool wsFrameBuild(const std::string& payload,
|
||||
std::string& frame,
|
||||
WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME,
|
||||
bool isFin = true,
|
||||
bool masking = false)
|
||||
{
|
||||
return wsFrameBuild(payload.c_str(),
|
||||
payload.size(),
|
||||
frame,
|
||||
frame_type,
|
||||
isFin,
|
||||
masking);
|
||||
}
|
||||
|
||||
static bool wsFrameExtractBuffer(const char* inbuffer,
|
||||
const size_t bufferSize,
|
||||
std::string& payload,
|
||||
WebSocketFrameType& outopcode,
|
||||
size_t& frameSize,
|
||||
bool& outfin)
|
||||
{
|
||||
const auto buffer = (const unsigned char*)inbuffer;
|
||||
|
||||
if (bufferSize < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outfin = (buffer[0] & 0x80) != 0;
|
||||
outopcode = (WebSocketFrameType)(buffer[0] & 0x0F);
|
||||
const bool isMasking = (buffer[1] & 0x80) != 0;
|
||||
uint32_t payloadlen = buffer[1] & 0x7F;
|
||||
|
||||
uint32_t pos = 2;
|
||||
if (payloadlen == 126)
|
||||
{
|
||||
if (bufferSize < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
payloadlen = (buffer[2] << 8) + buffer[3];
|
||||
pos = 4;
|
||||
}
|
||||
else if (payloadlen == 127)
|
||||
{
|
||||
if (bufferSize < 10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer[2] != 0 ||
|
||||
buffer[3] != 0 ||
|
||||
buffer[4] != 0 ||
|
||||
buffer[5] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((buffer[6] & 0x80) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
payloadlen = (buffer[6] << 24) +
|
||||
(buffer[7] << 16) +
|
||||
(buffer[8] << 8) +
|
||||
buffer[9];
|
||||
pos = 10;
|
||||
}
|
||||
|
||||
frame[1] = ((uint8_t) frame[1]) | 0x80;
|
||||
uint8_t mask[4];
|
||||
if (isMasking)
|
||||
for (auto& m : mask)
|
||||
{
|
||||
if (bufferSize < (pos + 4))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mask[0] = buffer[pos++];
|
||||
mask[1] = buffer[pos++];
|
||||
mask[2] = buffer[pos++];
|
||||
mask[3] = buffer[pos++];
|
||||
m = static_cast<uint8_t>(random());
|
||||
frame.push_back(m);
|
||||
}
|
||||
|
||||
if (bufferSize < (pos + payloadlen))
|
||||
frame.reserve(frame.size() + payloadLen);
|
||||
|
||||
for (size_t i = 0; i < payloadLen; i++)
|
||||
{
|
||||
frame.push_back(static_cast<uint8_t>(payload[i]) ^ mask[i % 4]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.append(payload, payloadLen);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool wsFrameBuild(const std::string& payload,
|
||||
std::string& frame,
|
||||
WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME,
|
||||
bool isFin = true,
|
||||
bool masking = false)
|
||||
{
|
||||
return wsFrameBuild(payload.c_str(),
|
||||
payload.size(),
|
||||
frame,
|
||||
frame_type,
|
||||
isFin,
|
||||
masking);
|
||||
}
|
||||
|
||||
static bool wsFrameExtractBuffer(const char* inbuffer,
|
||||
const size_t bufferSize,
|
||||
std::string& payload,
|
||||
WebSocketFrameType& outopcode,
|
||||
size_t& frameSize,
|
||||
bool& outfin)
|
||||
{
|
||||
const auto buffer = (const unsigned char*) inbuffer;
|
||||
|
||||
if (bufferSize < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outfin = (buffer[0] & 0x80) != 0;
|
||||
outopcode = (WebSocketFrameType)(buffer[0] & 0x0F);
|
||||
const bool isMasking = (buffer[1] & 0x80) != 0;
|
||||
uint32_t payloadlen = buffer[1] & 0x7F;
|
||||
|
||||
uint32_t pos = 2;
|
||||
if (payloadlen == 126)
|
||||
{
|
||||
if (bufferSize < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isMasking)
|
||||
{
|
||||
payload.reserve(payloadlen);
|
||||
for (size_t j = 0; j < payloadlen; j++)
|
||||
payload.push_back(buffer[pos+j] ^ mask[j % 4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload.append((const char*)(buffer + pos), payloadlen);
|
||||
}
|
||||
|
||||
frameSize = payloadlen + pos;
|
||||
|
||||
return true;
|
||||
payloadlen = (buffer[2] << 8) + buffer[3];
|
||||
pos = 4;
|
||||
}
|
||||
|
||||
static bool wsFrameExtractString(const std::string& buffer,
|
||||
std::string& payload,
|
||||
WebSocketFrameType& opcode,
|
||||
size_t& frameSize, bool& isFin)
|
||||
else if (payloadlen == 127)
|
||||
{
|
||||
return wsFrameExtractBuffer(buffer.c_str(),
|
||||
buffer.size(),
|
||||
payload,
|
||||
opcode,
|
||||
frameSize,
|
||||
isFin);
|
||||
}
|
||||
};
|
||||
if (bufferSize < 10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} } }
|
||||
if (buffer[2] != 0 ||
|
||||
buffer[3] != 0 ||
|
||||
buffer[4] != 0 ||
|
||||
buffer[5] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((buffer[6] & 0x80) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
payloadlen = (buffer[6] << 24) +
|
||||
(buffer[7] << 16) +
|
||||
(buffer[8] << 8) +
|
||||
buffer[9];
|
||||
pos = 10;
|
||||
}
|
||||
|
||||
uint8_t mask[4];
|
||||
if (isMasking)
|
||||
{
|
||||
if (bufferSize < (pos + 4))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mask[0] = buffer[pos++];
|
||||
mask[1] = buffer[pos++];
|
||||
mask[2] = buffer[pos++];
|
||||
mask[3] = buffer[pos++];
|
||||
}
|
||||
|
||||
if (bufferSize < (pos + payloadlen))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isMasking)
|
||||
{
|
||||
payload.reserve(payloadlen);
|
||||
for (size_t j = 0; j < payloadlen; j++)
|
||||
payload.push_back(buffer[pos + j] ^ mask[j % 4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload.append((const char*) (buffer + pos), payloadlen);
|
||||
}
|
||||
|
||||
frameSize = payloadlen + pos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool wsFrameExtractString(const std::string& buffer,
|
||||
std::string& payload,
|
||||
WebSocketFrameType& opcode,
|
||||
size_t& frameSize, bool& isFin)
|
||||
{
|
||||
return wsFrameExtractBuffer(buffer.c_str(),
|
||||
buffer.size(),
|
||||
payload,
|
||||
opcode,
|
||||
frameSize,
|
||||
isFin);
|
||||
}
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::http
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,27 +5,27 @@
|
||||
namespace brynet { namespace net { namespace port {
|
||||
|
||||
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||
class Win
|
||||
class Win
|
||||
{
|
||||
public:
|
||||
enum class OverlappedType
|
||||
{
|
||||
public:
|
||||
enum class OverlappedType
|
||||
{
|
||||
OverlappedNone = 0,
|
||||
OverlappedRecv,
|
||||
OverlappedSend,
|
||||
};
|
||||
|
||||
struct OverlappedExt
|
||||
{
|
||||
OVERLAPPED base;
|
||||
const OverlappedType OP;
|
||||
|
||||
OverlappedExt(OverlappedType op) BRYNET_NOEXCEPT : OP(op)
|
||||
{
|
||||
memset(&base, 0, sizeof(base));
|
||||
}
|
||||
};
|
||||
OverlappedNone = 0,
|
||||
OverlappedRecv,
|
||||
OverlappedSend,
|
||||
};
|
||||
|
||||
struct OverlappedExt
|
||||
{
|
||||
OVERLAPPED base;
|
||||
const OverlappedType OP;
|
||||
|
||||
OverlappedExt(OverlappedType op) BRYNET_NOEXCEPT : OP(op)
|
||||
{
|
||||
memset(&base, 0, sizeof(base));
|
||||
}
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::port
|
||||
|
@ -1,191 +1,210 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <brynet/net/TcpService.hpp>
|
||||
#include <brynet/net/AsyncConnector.hpp>
|
||||
#include <brynet/net/Exception.hpp>
|
||||
#include <brynet/net/TcpService.hpp>
|
||||
#include <future>
|
||||
#include <utility>
|
||||
|
||||
namespace brynet { namespace net { namespace wrapper {
|
||||
|
||||
template<typename Derived>
|
||||
class BaseSocketConnectBuilder
|
||||
using CompletedCallback = detail::AsyncConnectAddr::CompletedCallback;
|
||||
using ProcessTcpSocketCallback = detail::AsyncConnectAddr::ProcessTcpSocketCallback;
|
||||
using FailedCallback = detail::AsyncConnectAddr::FailedCallback;
|
||||
|
||||
template<typename Derived>
|
||||
class BaseSocketConnectBuilder
|
||||
{
|
||||
public:
|
||||
virtual ~BaseSocketConnectBuilder() = default;
|
||||
|
||||
Derived& WithConnector(AsyncConnector::Ptr connector)
|
||||
{
|
||||
protected:
|
||||
using AddSocketOptionFunc = detail::AddSocketOptionFunc;
|
||||
using ConnectOptionFunc = detail::ConnectOptionFunc;
|
||||
mConnector = std::move(connector);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~BaseSocketConnectBuilder() = default;
|
||||
|
||||
Derived& configureConnector(AsyncConnector::Ptr connector)
|
||||
{
|
||||
mConnector = std::move(connector);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& configureConnectOptions(
|
||||
std::vector<ConnectOptionFunc> options)
|
||||
{
|
||||
mConnectOptions = std::move(options);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void asyncConnect() const
|
||||
{
|
||||
asyncConnect(mConnectOptions);
|
||||
}
|
||||
|
||||
TcpSocket::Ptr syncConnect() const
|
||||
{
|
||||
return syncConnect(mConnectOptions);
|
||||
}
|
||||
|
||||
protected:
|
||||
void asyncConnect(std::vector<ConnectOptionFunc> connectOptions) const
|
||||
{
|
||||
if (mConnector == nullptr)
|
||||
{
|
||||
throw BrynetCommonException("connector is nullptr");
|
||||
}
|
||||
if (connectOptions.empty())
|
||||
{
|
||||
throw BrynetCommonException("options is empty");
|
||||
}
|
||||
|
||||
mConnector->asyncConnect(connectOptions);
|
||||
}
|
||||
|
||||
TcpSocket::Ptr syncConnect(std::vector<ConnectOptionFunc> connectOptions) const
|
||||
{
|
||||
auto timeout = ConnectOption::ExtractTimeout(connectOptions);
|
||||
|
||||
auto socketPromise = std::make_shared<std::promise<TcpSocket::Ptr>>();
|
||||
connectOptions.push_back(ConnectOption::WithCompletedCallback(
|
||||
[socketPromise](TcpSocket::Ptr socket) {
|
||||
socketPromise->set_value(std::move(socket));
|
||||
}));
|
||||
connectOptions.push_back(ConnectOption::WithFailedCallback([socketPromise]() {
|
||||
socketPromise->set_value(nullptr);
|
||||
}));
|
||||
|
||||
asyncConnect(connectOptions);
|
||||
|
||||
auto future = socketPromise->get_future();
|
||||
if (future.wait_for(timeout) != std::future_status::ready)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return future.get();
|
||||
}
|
||||
|
||||
std::vector<ConnectOptionFunc> getConnectOptions() const
|
||||
{
|
||||
return mConnectOptions;
|
||||
}
|
||||
|
||||
private:
|
||||
AsyncConnector::Ptr mConnector;
|
||||
std::vector<ConnectOptionFunc> mConnectOptions;
|
||||
};
|
||||
|
||||
class SocketConnectBuilder : public BaseSocketConnectBuilder<SocketConnectBuilder>
|
||||
Derived& WithAddr(std::string ip, size_t port)
|
||||
{
|
||||
};
|
||||
mConnectOption.ip = std::move(ip);
|
||||
mConnectOption.port = port;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
class BaseConnectionBuilder : public BaseSocketConnectBuilder<Derived>
|
||||
Derived& WithTimeout(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
protected:
|
||||
using AddSocketOptionFunc = detail::AddSocketOptionFunc;
|
||||
using ConnectOptionFunc = detail::ConnectOptionFunc;
|
||||
mConnectOption.timeout = timeout;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
Derived& configureService(TcpService::Ptr service)
|
||||
{
|
||||
mTcpService = std::move(service);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& configureConnectionOptions(std::vector<AddSocketOptionFunc> options)
|
||||
{
|
||||
mConnectionOptions = std::move(options);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void asyncConnect() const
|
||||
{
|
||||
asyncConnect(BaseSocketConnectBuilder<Derived>::getConnectOptions(),
|
||||
mConnectionOptions);
|
||||
}
|
||||
|
||||
TcpConnection::Ptr syncConnect() const
|
||||
{
|
||||
return syncConnect(BaseSocketConnectBuilder<Derived>::getConnectOptions(),
|
||||
mConnectionOptions);
|
||||
}
|
||||
|
||||
protected:
|
||||
void asyncConnect(std::vector<ConnectOptionFunc> connectOptions,
|
||||
std::vector<AddSocketOptionFunc> connectionOptions) const
|
||||
{
|
||||
if (mTcpService == nullptr)
|
||||
{
|
||||
throw BrynetCommonException("tcp serviceis nullptr");
|
||||
}
|
||||
if (connectionOptions.empty())
|
||||
{
|
||||
throw BrynetCommonException("options is empty");
|
||||
}
|
||||
|
||||
auto service = mTcpService;
|
||||
auto enterCallback = [service, connectionOptions](TcpSocket::Ptr socket) mutable {
|
||||
service->addTcpConnection(std::move(socket), connectionOptions);
|
||||
};
|
||||
connectOptions.push_back(ConnectOption::WithCompletedCallback(enterCallback));
|
||||
|
||||
BaseSocketConnectBuilder<Derived>::asyncConnect(connectOptions);
|
||||
}
|
||||
|
||||
TcpConnection::Ptr syncConnect(std::vector<ConnectOptionFunc> connectOptions,
|
||||
std::vector<AddSocketOptionFunc> connectionOptions) const
|
||||
{
|
||||
auto timeout = ConnectOption::ExtractTimeout(connectOptions);
|
||||
auto sessionPromise = std::make_shared<std::promise<TcpConnection::Ptr>>();
|
||||
|
||||
connectOptions.push_back(ConnectOption::WithFailedCallback(
|
||||
[sessionPromise]() {
|
||||
sessionPromise->set_value(nullptr);
|
||||
}));
|
||||
|
||||
connectionOptions.push_back(AddSocketOption::AddEnterCallback(
|
||||
[sessionPromise](const TcpConnection::Ptr& session) {
|
||||
sessionPromise->set_value(session);
|
||||
}));
|
||||
|
||||
asyncConnect(connectOptions, connectionOptions);
|
||||
|
||||
auto future = sessionPromise->get_future();
|
||||
if (future.wait_for(timeout) != std::future_status::ready)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return future.get();
|
||||
}
|
||||
|
||||
std::vector<AddSocketOptionFunc> getConnectionOptions() const
|
||||
{
|
||||
return mConnectionOptions;
|
||||
}
|
||||
|
||||
private:
|
||||
TcpService::Ptr mTcpService;
|
||||
std::vector<AddSocketOptionFunc> mConnectionOptions;
|
||||
};
|
||||
|
||||
class ConnectionBuilder : public BaseConnectionBuilder<ConnectionBuilder>
|
||||
Derived& AddSocketProcessCallback(const ProcessTcpSocketCallback& callback)
|
||||
{
|
||||
};
|
||||
mConnectOption.processCallbacks.push_back(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
} } }
|
||||
Derived& WithCompletedCallback(CompletedCallback callback)
|
||||
{
|
||||
mConnectOption.completedCallback = std::move(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& WithFailedCallback(FailedCallback callback)
|
||||
{
|
||||
mConnectOption.failedCallback = std::move(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void asyncConnect() const
|
||||
{
|
||||
if (mConnector == nullptr)
|
||||
{
|
||||
throw BrynetCommonException("connector is nullptr");
|
||||
}
|
||||
if (mConnectOption.ip.empty())
|
||||
{
|
||||
throw BrynetCommonException("address is empty");
|
||||
}
|
||||
|
||||
mConnector->asyncConnect(mConnectOption);
|
||||
}
|
||||
|
||||
TcpSocket::Ptr syncConnect()
|
||||
{
|
||||
if (mConnectOption.completedCallback != nullptr || mConnectOption.failedCallback != nullptr)
|
||||
{
|
||||
throw std::runtime_error("already setting completed callback or failed callback");
|
||||
}
|
||||
|
||||
auto socketPromise = std::make_shared<std::promise<TcpSocket::Ptr>>();
|
||||
mConnectOption.completedCallback = [socketPromise](TcpSocket::Ptr socket) {
|
||||
socketPromise->set_value(std::move(socket));
|
||||
};
|
||||
mConnectOption.failedCallback = [socketPromise]() {
|
||||
socketPromise->set_value(nullptr);
|
||||
};
|
||||
|
||||
asyncConnect();
|
||||
|
||||
auto future = socketPromise->get_future();
|
||||
if (future.wait_for(mConnectOption.timeout) != std::future_status::ready)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return future.get();
|
||||
}
|
||||
|
||||
private:
|
||||
AsyncConnector::Ptr mConnector;
|
||||
ConnectOption mConnectOption;
|
||||
};
|
||||
|
||||
class SocketConnectBuilder : public BaseSocketConnectBuilder<SocketConnectBuilder>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
class BaseConnectionBuilder
|
||||
{
|
||||
public:
|
||||
Derived& WithService(TcpService::Ptr service)
|
||||
{
|
||||
mTcpService = std::move(service);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& WithConnector(AsyncConnector::Ptr connector)
|
||||
{
|
||||
mConnectBuilder.WithConnector(std::move(connector));
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& WithAddr(std::string ip, size_t port)
|
||||
{
|
||||
mConnectBuilder.WithAddr(std::move(ip), port);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& WithTimeout(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
mConnectBuilder.WithTimeout(timeout);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& AddSocketProcessCallback(const ProcessTcpSocketCallback& callback)
|
||||
{
|
||||
mConnectBuilder.AddSocketProcessCallback(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& WithFailedCallback(FailedCallback callback)
|
||||
{
|
||||
mConnectBuilder.WithFailedCallback(std::move(callback));
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& WithMaxRecvBufferSize(size_t size)
|
||||
{
|
||||
mOption.maxRecvBufferSize = size;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
Derived& WithSSL()
|
||||
{
|
||||
mOption.useSSL = true;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
#endif
|
||||
Derived& WithForceSameThreadLoop()
|
||||
{
|
||||
mOption.forceSameThreadLoop = true;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& AddEnterCallback(const TcpConnection::EnterCallback& callback)
|
||||
{
|
||||
mOption.enterCallback.push_back(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void asyncConnect()
|
||||
{
|
||||
auto service = mTcpService;
|
||||
auto option = mOption;
|
||||
mConnectBuilder.WithCompletedCallback([service, option](TcpSocket::Ptr socket) mutable {
|
||||
service->addTcpConnection(std::move(socket), option);
|
||||
});
|
||||
|
||||
mConnectBuilder.asyncConnect();
|
||||
}
|
||||
|
||||
TcpConnection::Ptr syncConnect()
|
||||
{
|
||||
auto sessionPromise = std::make_shared<std::promise<TcpConnection::Ptr>>();
|
||||
|
||||
auto option = mOption;
|
||||
option.enterCallback.push_back([sessionPromise](const TcpConnection::Ptr& session) {
|
||||
sessionPromise->set_value(session);
|
||||
});
|
||||
|
||||
auto socket = mConnectBuilder.syncConnect();
|
||||
if (socket == nullptr || !mTcpService->addTcpConnection(std::move(socket), option))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return sessionPromise->get_future().get();
|
||||
}
|
||||
|
||||
private:
|
||||
TcpService::Ptr mTcpService;
|
||||
ConnectionOption mOption;
|
||||
SocketConnectBuilder mConnectBuilder;
|
||||
};
|
||||
|
||||
class ConnectionBuilder : public BaseConnectionBuilder<ConnectionBuilder>
|
||||
{
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::wrapper
|
||||
|
@ -2,43 +2,92 @@
|
||||
|
||||
#include <brynet/net/http/HttpService.hpp>
|
||||
#include <brynet/net/wrapper/ConnectionBuilder.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace brynet { namespace net { namespace wrapper {
|
||||
|
||||
class HttpConnectionBuilder : public BaseConnectionBuilder<HttpConnectionBuilder>
|
||||
class HttpConnectionBuilder
|
||||
{
|
||||
public:
|
||||
HttpConnectionBuilder& WithService(TcpService::Ptr service)
|
||||
{
|
||||
public:
|
||||
HttpConnectionBuilder& configureEnterCallback(
|
||||
http::HttpSession::EnterCallback&& callback)
|
||||
mBuilder.WithService(std::move(service));
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& WithConnector(AsyncConnector::Ptr connector)
|
||||
{
|
||||
mBuilder.WithConnector(std::move(connector));
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& WithAddr(std::string ip, size_t port)
|
||||
{
|
||||
mBuilder.WithAddr(std::move(ip), port);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& WithTimeout(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
mBuilder.WithTimeout(timeout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& AddSocketProcessCallback(const ProcessTcpSocketCallback& callback)
|
||||
{
|
||||
mBuilder.AddSocketProcessCallback(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& WithEnterCallback(http::HttpSession::EnterCallback&& callback)
|
||||
{
|
||||
mHttpEnterCallback = std::move(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& WithFailedCallback(FailedCallback callback)
|
||||
{
|
||||
mBuilder.WithFailedCallback(std::move(callback));
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpConnectionBuilder& WithMaxRecvBufferSize(size_t size)
|
||||
{
|
||||
mBuilder.WithMaxRecvBufferSize(size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
HttpConnectionBuilder& WithSSL()
|
||||
{
|
||||
mBuilder.WithSSL();
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
HttpConnectionBuilder& WithForceSameThreadLoop()
|
||||
{
|
||||
mBuilder.WithForceSameThreadLoop();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void asyncConnect()
|
||||
{
|
||||
if (mHttpEnterCallback == nullptr)
|
||||
{
|
||||
mHttpEnterCallback = std::move(callback);
|
||||
return *this;
|
||||
throw BrynetCommonException("not setting http enter callback");
|
||||
}
|
||||
|
||||
void asyncConnect() const
|
||||
{
|
||||
if (mHttpEnterCallback == nullptr)
|
||||
{
|
||||
throw BrynetCommonException("not setting http enter callback");
|
||||
}
|
||||
auto callback = mHttpEnterCallback;
|
||||
auto builder = mBuilder;
|
||||
builder.AddEnterCallback([callback](const TcpConnection::Ptr& session) {
|
||||
http::HttpService::setup(session, callback);
|
||||
});
|
||||
builder.asyncConnect();
|
||||
}
|
||||
|
||||
auto connectionOptions =
|
||||
BaseConnectionBuilder<HttpConnectionBuilder>::getConnectionOptions();
|
||||
auto callback = mHttpEnterCallback;
|
||||
private:
|
||||
http::HttpSession::EnterCallback mHttpEnterCallback;
|
||||
ConnectionBuilder mBuilder;
|
||||
};
|
||||
|
||||
connectionOptions.push_back(
|
||||
AddSocketOption::AddEnterCallback(
|
||||
[callback](const TcpConnection::Ptr& session) {
|
||||
http::HttpService::setup(session, callback);
|
||||
}));
|
||||
|
||||
BaseConnectionBuilder<HttpConnectionBuilder>::asyncConnect(
|
||||
BaseConnectionBuilder<HttpConnectionBuilder>::getConnectOptions(),
|
||||
connectionOptions);
|
||||
}
|
||||
|
||||
private:
|
||||
http::HttpSession::EnterCallback mHttpEnterCallback;
|
||||
};
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::wrapper
|
||||
|
@ -2,38 +2,78 @@
|
||||
|
||||
#include <brynet/net/http/HttpService.hpp>
|
||||
#include <brynet/net/wrapper/ServiceBuilder.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace brynet { namespace net { namespace wrapper {
|
||||
|
||||
class HttpListenerBuilder : public BaseListenerBuilder<HttpListenerBuilder>
|
||||
class HttpListenerBuilder
|
||||
{
|
||||
public:
|
||||
HttpListenerBuilder& WithService(TcpService::Ptr service)
|
||||
{
|
||||
public:
|
||||
HttpListenerBuilder& configureEnterCallback(http::HttpSession::EnterCallback&& callback)
|
||||
mBuilder.WithService(std::move(service));
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpListenerBuilder& WithEnterCallback(http::HttpSession::EnterCallback&& callback)
|
||||
{
|
||||
mHttpEnterCallback = std::move(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpListenerBuilder& AddSocketProcess(const ListenThread::TcpSocketProcessCallback& callback)
|
||||
{
|
||||
mBuilder.AddSocketProcess(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpListenerBuilder& WithMaxRecvBufferSize(size_t size)
|
||||
{
|
||||
mBuilder.WithMaxRecvBufferSize(size);
|
||||
return *this;
|
||||
}
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
HttpListenerBuilder& WithSSL(SSLHelper::Ptr sslHelper)
|
||||
{
|
||||
mBuilder.WithSSL(std::move(sslHelper));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
HttpListenerBuilder& WithForceSameThreadLoop()
|
||||
{
|
||||
mBuilder.WithForceSameThreadLoop();
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpListenerBuilder& WithAddr(bool ipV6, std::string ip, size_t port)
|
||||
{
|
||||
mBuilder.WithAddr(ipV6, std::move(ip), port);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpListenerBuilder& WithReusePort()
|
||||
{
|
||||
mBuilder.WithReusePort();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void asyncRun()
|
||||
{
|
||||
if (mHttpEnterCallback == nullptr)
|
||||
{
|
||||
mHttpEnterCallback = std::move(callback);
|
||||
return *this;
|
||||
throw BrynetCommonException("not setting http enter callback");
|
||||
}
|
||||
|
||||
void asyncRun()
|
||||
{
|
||||
if (mHttpEnterCallback == nullptr)
|
||||
{
|
||||
throw BrynetCommonException("not setting http enter callback");
|
||||
}
|
||||
auto callback = mHttpEnterCallback;
|
||||
mBuilder.AddEnterCallback([callback](const TcpConnection::Ptr& session) {
|
||||
http::HttpService::setup(session, callback);
|
||||
});
|
||||
mBuilder.asyncRun();
|
||||
}
|
||||
|
||||
auto connectionOptions =
|
||||
BaseListenerBuilder<HttpListenerBuilder>::getConnectionOptions();
|
||||
auto callback = mHttpEnterCallback;
|
||||
connectionOptions.push_back(
|
||||
AddSocketOption::AddEnterCallback(
|
||||
[callback](const TcpConnection::Ptr& session) {
|
||||
http::HttpService::setup(session, callback);
|
||||
}));
|
||||
BaseListenerBuilder<HttpListenerBuilder>::asyncRun(connectionOptions);
|
||||
}
|
||||
private:
|
||||
http::HttpSession::EnterCallback mHttpEnterCallback;
|
||||
ListenerBuilder mBuilder;
|
||||
};
|
||||
|
||||
private:
|
||||
http::HttpSession::EnterCallback mHttpEnterCallback;
|
||||
};
|
||||
|
||||
} } }
|
||||
}}}// namespace brynet::net::wrapper
|
||||
|
@ -1,167 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <brynet/net/TcpService.hpp>
|
||||
#include <brynet/net/ListenThread.hpp>
|
||||
#include <brynet/net/Exception.hpp>
|
||||
#include <brynet/net/ListenThread.hpp>
|
||||
#include <brynet/net/TcpService.hpp>
|
||||
#include <brynet/net/detail/ConnectionOption.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace brynet { namespace net { namespace wrapper {
|
||||
|
||||
class ListenConfig final
|
||||
template<typename Derived>
|
||||
class BaseListenerBuilder
|
||||
{
|
||||
public:
|
||||
virtual ~BaseListenerBuilder() = default;
|
||||
|
||||
Derived& WithService(TcpService::Ptr service)
|
||||
{
|
||||
public:
|
||||
ListenConfig()
|
||||
{
|
||||
mSetting = false;
|
||||
mIsIpV6 = false;
|
||||
mPort = 0;
|
||||
}
|
||||
mTcpService = std::move(service);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void setAddr(bool ipV6, std::string ip, int port)
|
||||
{
|
||||
mIsIpV6 = ipV6;
|
||||
mListenAddr = ip;
|
||||
mPort = port;
|
||||
mSetting = true;
|
||||
}
|
||||
|
||||
std::string ip() const
|
||||
{
|
||||
return mListenAddr;
|
||||
}
|
||||
|
||||
int port() const
|
||||
{
|
||||
return mPort;
|
||||
}
|
||||
|
||||
bool useIpV6() const
|
||||
{
|
||||
return mIsIpV6;
|
||||
}
|
||||
|
||||
bool hasSetting() const
|
||||
{
|
||||
return mSetting;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mListenAddr;
|
||||
int mPort;
|
||||
bool mIsIpV6;
|
||||
bool mSetting;
|
||||
};
|
||||
|
||||
class BuildListenConfig
|
||||
Derived& WithAddr(bool ipV6, std::string ip, size_t port)
|
||||
{
|
||||
public:
|
||||
explicit BuildListenConfig(ListenConfig* config)
|
||||
:
|
||||
mConfig(config)
|
||||
{
|
||||
}
|
||||
mIsIpV6 = ipV6;
|
||||
mListenAddr = std::move(ip);
|
||||
mPort = port;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void setAddr(bool ipV6, std::string ip, int port)
|
||||
{
|
||||
mConfig->setAddr(ipV6, ip, port);
|
||||
}
|
||||
|
||||
private:
|
||||
ListenConfig* mConfig;
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
class BaseListenerBuilder
|
||||
Derived& WithReusePort()
|
||||
{
|
||||
protected:
|
||||
using AddSocketOptionFunc = detail::AddSocketOptionFunc;
|
||||
using ConnectOptionFunc = detail::ConnectOptionFunc;
|
||||
mEnabledReusePort = true;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~BaseListenerBuilder() = default;
|
||||
Derived& AddSocketProcess(const ListenThread::TcpSocketProcessCallback& callback)
|
||||
{
|
||||
mSocketProcessCallbacks.push_back(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& configureService(TcpService::Ptr service)
|
||||
Derived& WithMaxRecvBufferSize(size_t size)
|
||||
{
|
||||
mSocketOption.maxRecvBufferSize = size;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
#ifdef BRYNET_USE_OPENSSL
|
||||
Derived& WithSSL(SSLHelper::Ptr sslHelper)
|
||||
{
|
||||
mSocketOption.sslHelper = std::move(sslHelper);
|
||||
mSocketOption.useSSL = true;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
#endif
|
||||
Derived& WithForceSameThreadLoop()
|
||||
{
|
||||
mSocketOption.forceSameThreadLoop = true;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& AddEnterCallback(const TcpConnection::EnterCallback& callback)
|
||||
{
|
||||
mSocketOption.enterCallback.push_back(callback);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void asyncRun()
|
||||
{
|
||||
if (mTcpService == nullptr)
|
||||
{
|
||||
mTcpService = std::move(service);
|
||||
return static_cast<Derived&>(*this);
|
||||
throw BrynetCommonException("tcp service is nullptr");
|
||||
}
|
||||
if (mListenAddr.empty())
|
||||
{
|
||||
throw BrynetCommonException("not config listen addr");
|
||||
}
|
||||
|
||||
Derived& configureSocketOptions(std::vector<ListenThread::TcpSocketProcessCallback> options)
|
||||
{
|
||||
mSocketOptions = std::move(options);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
Derived& configureConnectionOptions(std::vector<AddSocketOptionFunc> options)
|
||||
{
|
||||
mConnectionOptions = std::move(options);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
template<typename BuilderFunc>
|
||||
Derived& configureListen(const BuilderFunc& builder)
|
||||
{
|
||||
BuildListenConfig buildConfig(&mListenConfig);
|
||||
builder(buildConfig);
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
|
||||
void asyncRun()
|
||||
{
|
||||
asyncRun(getConnectionOptions());
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (mListenThread)
|
||||
{
|
||||
mListenThread->stopListen();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AddSocketOptionFunc> getConnectionOptions() const
|
||||
{
|
||||
return mConnectionOptions;
|
||||
}
|
||||
|
||||
protected:
|
||||
void asyncRun(std::vector<AddSocketOptionFunc> connectionOptions)
|
||||
{
|
||||
if (mTcpService == nullptr)
|
||||
{
|
||||
throw BrynetCommonException("tcp service is nullptr");
|
||||
}
|
||||
if (connectionOptions.empty())
|
||||
{
|
||||
throw BrynetCommonException("options is empty");
|
||||
}
|
||||
if (!mListenConfig.hasSetting())
|
||||
{
|
||||
throw BrynetCommonException("not config listen addr");
|
||||
}
|
||||
|
||||
auto service = mTcpService;
|
||||
mListenThread = ListenThread::Create(mListenConfig.useIpV6(),
|
||||
mListenConfig.ip(),
|
||||
mListenConfig.port(),
|
||||
[service, connectionOptions](brynet::net::TcpSocket::Ptr socket) {
|
||||
service->addTcpConnection(std::move(socket), connectionOptions);
|
||||
auto service = mTcpService;
|
||||
auto option = mSocketOption;
|
||||
mListenThread = ListenThread::Create(
|
||||
mIsIpV6,
|
||||
mListenAddr,
|
||||
mPort,
|
||||
[service, option](brynet::net::TcpSocket::Ptr socket) {
|
||||
service->addTcpConnection(std::move(socket), option);
|
||||
},
|
||||
mSocketOptions);
|
||||
mListenThread->startListen();
|
||||
}
|
||||
mSocketProcessCallbacks,
|
||||
mEnabledReusePort);
|
||||
mListenThread->startListen();
|
||||
}
|
||||
|
||||
private:
|
||||
TcpService::Ptr mTcpService;
|
||||
std::vector<ListenThread::TcpSocketProcessCallback> mSocketOptions;
|
||||
ListenConfig mListenConfig;
|
||||
ListenThread::Ptr mListenThread;
|
||||
|
||||
private:
|
||||
std::vector<AddSocketOptionFunc> mConnectionOptions;
|
||||
};
|
||||
|
||||
class ListenerBuilder : public BaseListenerBuilder<ListenerBuilder>
|
||||
void stop()
|
||||
{
|
||||
};
|
||||
if (mListenThread)
|
||||
{
|
||||
mListenThread->stopListen();
|
||||
}
|
||||
}
|
||||
|
||||
} } }
|
||||
private:
|
||||
TcpService::Ptr mTcpService;
|
||||
std::vector<ListenThread::TcpSocketProcessCallback> mSocketProcessCallbacks;
|
||||
ConnectionOption mSocketOption;
|
||||
std::string mListenAddr;
|
||||
int mPort = 0;
|
||||
bool mIsIpV6 = false;
|
||||
bool mEnabledReusePort = false;
|
||||
ListenThread::Ptr mListenThread;
|
||||
};
|
||||
|
||||
class ListenerBuilder : public BaseListenerBuilder<ListenerBuilder>
|
||||
{
|
||||
};
|
||||
|
||||
}}}// namespace brynet::net::wrapper
|
||||
|
Loading…
Reference in New Issue
Block a user