Update brynet to the latest.

This commit is contained in:
Relintai 2021-04-30 16:10:14 +02:00
parent 8c483b4f8e
commit d4ccc6775d
49 changed files with 8661 additions and 8609 deletions

View File

@ -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); });

View File

@ -1,4 +1,4 @@
RapidJSON 0ccdbf364c577803e2a751f5aededce935314313
brynet b0d13e7419628d0f7051a2bb310daaf8a506e08b
brynet a63ac30364641000ccf8f831eea864aa98f1d50d
rapidxml 1.13
maddy adb1a910d4aadea09cb7b200f2ec204f61214596

View File

@ -1,3 +1,3 @@
#pragma once
#define BRYNET_VERSION 1009000
#define BRYNET_VERSION 1010000

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -13,4 +13,4 @@
#if (__cplusplus >= 201703L || \
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
#define BRYNET_HAVE_LANG_CXX17 1
#endif
#endif

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)>;
} } }

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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