Removed brynet.

This commit is contained in:
Relintai 2022-01-07 20:11:34 +01:00
parent a1afe210d1
commit 2133be9254
50 changed files with 0 additions and 10083 deletions

View File

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

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 IronsDu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

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

View File

@ -1,24 +0,0 @@
#pragma once
#include <brynet/base/CPP_VERSION.hpp>
#ifdef BRYNET_HAVE_LANG_CXX17
#include <any>
#else
#include <cstdint>
#endif
#ifdef BRYNET_HAVE_LANG_CXX17
using BrynetAny = std::any;
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);
}
#endif

View File

@ -1,41 +0,0 @@
#pragma once
#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>
#endif
static bool app_kbhit() {
#ifdef BRYNET_PLATFORM_WINDOWS
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);
const auto ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if (ch != EOF) {
ungetc(ch, stdin);
return true;
}
return false;
#endif
}

View File

@ -1,101 +0,0 @@
#pragma once
#include <cassert>
#include <cstdlib>
#include <cstring>
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) {
return;
}
if (self->buffer != nullptr) {
free(self->buffer);
self->buffer = nullptr;
}
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) {
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;
}
static void *array_at(struct array_s *self, size_t index) {
void *ret = nullptr;
if (index < self->element_num) {
ret = (char *)(self->buffer) + (index * self->element_size);
} else {
assert(false);
}
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) {
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;
}

View File

@ -1,141 +0,0 @@
#pragma once
#include <cstdlib>
#include <cstring>
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) {
return;
}
if (self->data != nullptr) {
free(self->data);
self->data = nullptr;
}
free(self);
self = 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) {
buffer_adjustto_head(self);
buffer_write(self, data, len);
} else {
write_ret = false;
}
}
return write_ret;
}

View File

@ -1,16 +0,0 @@
#pragma once
#if (__cplusplus >= 201103L || \
(defined(_MSC_VER) && _MSC_VER >= 1800))
#define BRYNET_HAVE_LANG_CXX11 1
#endif
#if (__cplusplus >= 201402L || \
(defined(_MSC_VER) && _MSC_VER >= 1900))
#define BRYNET_HAVE_LANG_CXX14 1
#endif
#if (__cplusplus >= 201703L || \
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
#define BRYNET_HAVE_LANG_CXX17 1
#endif

View File

@ -1,9 +0,0 @@
#pragma once
#include <brynet/base/CPP_VERSION.hpp>
#ifdef BRYNET_HAVE_LANG_CXX17
#define BRYNET_NOEXCEPT noexcept
#else
#define BRYNET_NOEXCEPT
#endif

View File

@ -1,12 +0,0 @@
#pragma once
class NonCopyable {
public:
NonCopyable(const NonCopyable &) = delete;
const NonCopyable &operator=(const NonCopyable &) = delete;
protected:
NonCopyable() = default;
~NonCopyable() = default;
};

View File

@ -1,354 +0,0 @@
#pragma once
#include <brynet/base/NonCopyable.hpp>
#include <brynet/base/endian/Endian.hpp>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <string>
class BasePacketWriter : public NonCopyable {
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) {
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 = hostToNetwork16(value, mBigEndian);
return writeBuffer((char *)&value, sizeof(value));
}
bool writeUINT16(uint16_t value) {
value = hostToNetwork16(value, mBigEndian);
return writeBuffer((char *)&value, sizeof(value));
}
bool writeINT32(int32_t value) {
value = hostToNetwork32(value, mBigEndian);
return writeBuffer((char *)&value, sizeof(value));
}
bool writeUINT32(uint32_t value) {
value = hostToNetwork32(value, mBigEndian);
return writeBuffer((char *)&value, sizeof(value));
}
bool writeINT64(int64_t value) {
value = hostToNetwork64(value, mBigEndian);
return writeBuffer((char *)&value, sizeof(value));
}
bool writeUINT64(uint64_t value) {
value = 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 {
public:
BasePacketReader(const char *buffer,
size_t len,
bool useBigEndian = false) :
mBigEndian(useBigEndian),
mSize(len) {
mPos = 0;
mSavedPos = 0;
mBuffer = buffer;
}
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 networkToHost16(value, mBigEndian);
}
uint16_t readUINT16() {
uint16_t value = 0;
read(value);
return networkToHost16(value, mBigEndian);
}
int32_t readINT32() {
int32_t value = 0;
read(value);
return networkToHost32(value, mBigEndian);
}
uint32_t readUINT32() {
uint32_t value = 0;
read(value);
return networkToHost32(value, mBigEndian);
}
int64_t readINT64() {
int64_t value = 0;
read(value);
return networkToHost64(value, mBigEndian);
}
uint64_t readUINT64() {
uint64_t value = 0;
read(value);
return 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>;

View File

@ -1,9 +0,0 @@
#pragma once
#if defined _MSC_VER || defined __MINGW32__
#define BRYNET_PLATFORM_WINDOWS
#elif defined __APPLE_CC__ || defined __APPLE__
#define BRYNET_PLATFORM_DARWIN
#else
#define BRYNET_PLATFORM_LINUX
#endif

View File

@ -1,140 +0,0 @@
#pragma once
#include <brynet/base/Array.hpp>
#include <cstdlib>
struct stack_s {
struct array_s *array;
size_t element_size;
size_t element_num;
size_t front;
size_t num;
};
static void stack_delete(struct stack_s *self) {
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) {
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;
}
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)) {
stack_increase(self, stack_size(self));
}
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;
}

View File

@ -1,139 +0,0 @@
#pragma once
#include <brynet/base/Noexcept.hpp>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <vector>
class TimerMgr;
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) {
}
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 {
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>(
std::chrono::steady_clock::now(),
std::chrono::nanoseconds(timeout),
std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...));
mTimers.push(timer);
return timer;
}
void addTimer(const Timer::Ptr &timer) {
mTimers.push(timer);
}
void schedule() {
while (!mTimers.empty()) {
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();
}
auto result = mTimers.top()->getLeftTime();
if (result < std::chrono::nanoseconds::zero()) {
return std::chrono::nanoseconds::zero();
}
return result;
}
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;
};

View File

@ -1,56 +0,0 @@
#pragma once
#include <atomic>
#include <brynet/base/NonCopyable.hpp>
#include <chrono>
#include <condition_variable>
#include <memory>
#include <mutex>
class WaitGroup : public NonCopyable {
public:
typedef std::shared_ptr<WaitGroup> Ptr;
static Ptr Create() {
struct make_shared_enabler : public WaitGroup {
};
return std::make_shared<make_shared_enabler>();
}
public:
void add(int i = 1) {
mCounter += i;
}
void done() {
mCounter--;
mCond.notify_all();
}
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;
});
}
private:
WaitGroup() :
mCounter(0) {
}
virtual ~WaitGroup() = default;
private:
std::mutex mMutex;
std::atomic<int> mCounter;
std::condition_variable mCond;
};

View File

@ -1,98 +0,0 @@
#ifndef _BRYNET_BASE_BASE64_H
#define _BRYNET_BASE_BASE64_H
#include <string>
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
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--) {
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) {
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 += '=';
}
return ret;
}
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 (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
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;
}
#endif

View File

@ -1,566 +0,0 @@
/*
100% free public domain implementation of the SHA-1 algorithm
by Dominik Reichl <dominik.reichl@t-online.de>
Web: http://www.dominik-reichl.de/
Version 2.1 - 2012-06-19
- Deconstructor (resetting internal variables) is now only
implemented if SHA1_WIPE_VARIABLES is defined (which is the
default).
- Renamed inclusion guard to contain a GUID.
- Demo application is now using C++/STL objects and functions.
- Unicode build of the demo application now outputs the hashes of both
the ANSI and Unicode representations of strings.
- Various other demo application improvements.
Version 2.0 - 2012-06-14
- Added 'limits.h' include.
- Renamed inclusion guard and macros for compliancy (names beginning
with an underscore are reserved).
Version 1.9 - 2011-11-10
- Added Unicode test vectors.
- Improved support for hashing files using the HashFile method that
are larger than 4 GB.
- Improved file hashing performance (by using a larger buffer).
- Disabled unnecessary compiler warnings.
- Internal variables are now private.
Version 1.8 - 2009-03-16
- Converted project files to Visual Studio 2008 format.
- Added Unicode support for HashFile utility method.
- Added support for hashing files using the HashFile method that are
larger than 2 GB.
- HashFile now returns an error code instead of copying an error
message into the output buffer.
- GetHash now returns an error code and validates the input parameter.
- Added ReportHashStl STL utility method.
- Added REPORT_HEX_SHORT reporting mode.
- Improved Linux compatibility of test program.
Version 1.7 - 2006-12-21
- Fixed buffer underrun warning that appeared when compiling with
Borland C Builder (thanks to Rex Bloom and Tim Gallagher for the
patch).
- Breaking change: ReportHash writes the final hash to the start
of the buffer, i.e. it's not appending it to the string anymore.
- Made some function parameters const.
- Added Visual Studio 2005 project files to demo project.
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
- You can set the endianness in your files, no need to modify the
header file of the CSHA1 class anymore.
- Aligned data support.
- Made support/compilation of the utility functions (ReportHash and
HashFile) optional (useful when bytes count, for example in embedded
environments).
Version 1.5 - 2005-01-01
- 64-bit compiler compatibility added.
- Made variable wiping optional (define SHA1_WIPE_VARIABLES).
- Removed unnecessary variable initializations.
- ROL32 improvement for the Microsoft compiler (using _rotl).
Version 1.4 - 2004-07-22
- CSHA1 now compiles fine with GCC 3.3 under Mac OS X (thanks to Larry
Hastings).
Version 1.3 - 2003-08-17
- Fixed a small memory bug and made a buffer array a class member to
ensure correct working when using multiple CSHA1 class instances at
one time.
Version 1.2 - 2002-11-16
- Borlands C++ compiler seems to have problems with string addition
using sprintf. Fixed the bug which caused the digest report function
not to work properly. CSHA1 is now Borland compatible.
Version 1.1 - 2002-10-11
- Removed two unnecessary header file includes and changed BOOL to
bool. Fixed some minor bugs in the web page contents.
Version 1.0 - 2002-06-20
- First official release.
================ Test Vectors ================
SHA1("abc" in ANSI) =
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
SHA1("abc" in Unicode LE) =
9F04F41A 84851416 2050E3D6 8C1A7ABB 441DC2B5
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
in ANSI) =
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
in Unicode LE) =
51D7D876 9AC72C40 9C5B0E3F 69C60ADC 9A039014
SHA1(A million repetitions of "a" in ANSI) =
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
SHA1(A million repetitions of "a" in Unicode LE) =
C4609560 A108A0C6 26AA7F2B 38A65566 739353C5
*/
#ifndef SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
#define SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
#define SHA1_UTILITY_FUNCTIONS
#endif
#if !defined(SHA1_STL_FUNCTIONS) && !defined(SHA1_NO_STL_FUNCTIONS)
#define SHA1_STL_FUNCTIONS
#if !defined(SHA1_UTILITY_FUNCTIONS)
#error STL functions require SHA1_UTILITY_FUNCTIONS.
#endif
#endif
#include <limits.h>
#include <memory.h>
#ifdef SHA1_UTILITY_FUNCTIONS
#include <stdio.h>
#include <string.h>
#endif
#ifdef SHA1_STL_FUNCTIONS
#include <string>
#endif
#ifdef _MSC_VER
#include <stdlib.h>
#endif
// You can define the endian mode in your files without modifying the SHA-1
// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
// in your files, before including the SHA1.h header file. If you don't
// define anything, the class defaults to little endian.
#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
#define SHA1_LITTLE_ENDIAN
#endif
// If you want variable wiping, #define SHA1_WIPE_VARIABLES, if not,
// #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
// defaults to wiping.
#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
#define SHA1_WIPE_VARIABLES
#endif
#if defined(SHA1_HAS_TCHAR)
#include <tchar.h>
#else
#ifdef _MSC_VER
#include <tchar.h>
#else
#ifndef TCHAR
#define TCHAR char
#endif
#ifndef _T
#define _T(__x) (__x)
#define _tmain main
#define _tprintf printf
#define _getts gets
#define _tcslen strlen
#define _tfopen fopen
#define _tcscpy strcpy
#define _tcscat strcat
#define _sntprintf snprintf
#endif
#endif
#endif
///////////////////////////////////////////////////////////////////////////
// Define variable types
#ifndef UINT_8
#ifdef _MSC_VER // Compiling with Microsoft compiler
#define UINT_8 unsigned __int8
#else // !_MSC_VER
#define UINT_8 unsigned char
#endif // _MSC_VER
#endif
#ifndef UINT_32
#ifdef _MSC_VER // Compiling with Microsoft compiler
#define UINT_32 unsigned __int32
#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
#ifndef INT_64
#ifdef _MSC_VER // Compiling with Microsoft compiler
#define INT_64 __int64
#else // !_MSC_VER
#define INT_64 long long
#endif // _MSC_VER
#endif // INT_64
#ifndef UINT_64
#ifdef _MSC_VER // Compiling with Microsoft compiler
#define UINT_64 unsigned __int64
#else // !_MSC_VER
#define UINT_64 unsigned long long
#endif // _MSC_VER
#endif // UINT_64
///////////////////////////////////////////////////////////////////////////
// Declare SHA-1 workspace
typedef union {
UINT_8 c[64];
UINT_32 l[16];
} SHA1_WORKSPACE_BLOCK;
#define SHA1_MAX_FILE_BUFFER (32 * 20 * 820)
// 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)
#else
#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))
#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))
// 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); \
}
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
};
#endif
// Constructor and destructor
CSHA1() {
(void)m_reserved0;
(void)m_reserved1;
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
Reset();
}
#ifdef SHA1_WIPE_VARIABLES
~CSHA1() {
Reset();
}
#endif
void Reset() {
// SHA1 initialization constants
m_state[0] = 0x67452301;
m_state[1] = 0xEFCDAB89;
m_state[2] = 0x98BADCFE;
m_state[3] = 0x10325476;
m_state[4] = 0xC3D2E1F0;
m_count[0] = 0;
m_count[1] = 0;
}
// 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] += (uLen >> 29);
UINT_32 i;
if ((j + uLen) > 63) {
i = 64 - j;
memcpy(&m_buffer[j], pbData, i);
Transform(m_state, m_buffer);
for (; (i + 63) < uLen; i += 64)
Transform(m_state, &pbData[i]);
j = 0;
} else
i = 0;
if ((uLen - i) != 0)
memcpy(&m_buffer[j], &pbData[i], uLen - i);
}
#ifdef SHA1_UTILITY_FUNCTIONS
// Hash in file contents
bool HashFile(const TCHAR *tszFileName) {
if (tszFileName == NULL)
return false;
FILE *fpIn = _tfopen(tszFileName, _T("rb"));
if (fpIn == NULL)
return false;
UINT_8 *pbData = new UINT_8[SHA1_MAX_FILE_BUFFER];
if (pbData == NULL) {
fclose(fpIn);
return false;
}
bool bSuccess = true;
while (true) {
const size_t uRead = fread(pbData, 1, SHA1_MAX_FILE_BUFFER, fpIn);
if (uRead > 0)
Update(pbData, static_cast<UINT_32>(uRead));
if (uRead < SHA1_MAX_FILE_BUFFER) {
if (feof(fpIn) == 0)
bSuccess = false;
break;
}
}
fclose(fpIn);
delete[] pbData;
return bSuccess;
}
#endif
// Finalize hash; call it before using ReportHash(Stl)
void Final() {
UINT_32 i;
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
Update((UINT_8 *)"\200", 1);
while ((m_count[0] & 504) != 448)
Update((UINT_8 *)"\0", 1);
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);
// Wipe variables for security reasons
#ifdef SHA1_WIPE_VARIABLES
memset(m_buffer, 0, 64);
memset(m_state, 0, 20);
memset(m_count, 0, 8);
memset(pbFinalCount, 0, 8);
Transform(m_state, m_buffer);
#endif
}
#ifdef SHA1_UTILITY_FUNCTIONS
bool ReportHash(TCHAR *tszReport, REPORT_TYPE rtReportType = REPORT_HEX) const {
if (tszReport == NULL)
return false;
TCHAR tszTemp[16];
if ((rtReportType == REPORT_HEX) || (rtReportType == REPORT_HEX_SHORT)) {
_sntprintf(tszTemp, 15, _T("%02X"), m_digest[0]);
_tcscpy(tszReport, tszTemp);
const TCHAR *lpFmt = ((rtReportType == REPORT_HEX) ? _T(" %02X") : _T("%02X"));
for (size_t i = 1; i < 20; ++i) {
_sntprintf(tszTemp, 15, lpFmt, m_digest[i]);
_tcscat(tszReport, tszTemp);
}
} else if (rtReportType == REPORT_DIGIT) {
_sntprintf(tszTemp, 15, _T("%u"), m_digest[0]);
_tcscpy(tszReport, tszTemp);
for (size_t i = 1; i < 20; ++i) {
_sntprintf(tszTemp, 15, _T(" %u"), m_digest[i]);
_tcscat(tszReport, tszTemp);
}
} else
return false;
return true;
}
#endif
#ifdef SHA1_STL_FUNCTIONS
bool ReportHashStl(std::basic_string<TCHAR> &strOut, REPORT_TYPE rtReportType =
REPORT_HEX) const {
TCHAR tszOut[84];
const bool bResult = ReportHash(tszOut, rtReportType);
if (bResult)
strOut = tszOut;
return bResult;
}
#endif
// Get the raw message digest (20 bytes)
bool GetHash(UINT_8 *pbDest20) const {
if (pbDest20 == NULL)
return false;
memcpy(pbDest20, m_digest, 20);
return true;
}
private:
// 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];
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);
// Add the working vars back into state
pState[0] += a;
pState[1] += b;
pState[2] += c;
pState[3] += d;
pState[4] += e;
// Wipe variables
#ifdef SHA1_WIPE_VARIABLES
a = b = c = d = e = 0;
#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
UINT_8 m_workspace[64];
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
};
#endif // SHA1_H_A545E61D43E9404E8D736869AB3CBFE7

View File

@ -1,115 +0,0 @@
#pragma once
#include <brynet/net/SocketLibTypes.hpp>
#include <cassert>
#include <cstdbool>
#include <cstdint>
#include <cstring>
#ifdef BRYNET_PLATFORM_LINUX
#include <endian.h>
#elif defined BRYNET_PLATFORM_DARWIN
#include <sys/_endian.h>
#endif
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;
return ret;
}
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;
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 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 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;
}
#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 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 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;
}
#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 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 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;
}
#endif

View File

@ -1,32 +0,0 @@
#pragma once
#include <brynet/net/detail/ConnectorDetail.hpp>
using ConnectOption = ConnectOption;
class AsyncConnector : public AsyncConnectorDetail,
public std::enable_shared_from_this<AsyncConnector> {
public:
using Ptr = std::shared_ptr<AsyncConnector>;
void startWorkerThread() {
AsyncConnectorDetail::startWorkerThread();
}
void stopWorkerThread() {
AsyncConnectorDetail::stopWorkerThread();
}
void asyncConnect(const ConnectOption &option) {
AsyncConnectorDetail::asyncConnect(option);
}
static Ptr Create() {
class make_shared_enabler : public AsyncConnector {
};
return std::make_shared<make_shared_enabler>();
}
private:
AsyncConnector() = default;
};

View File

@ -1,15 +0,0 @@
#pragma once
class EventLoop;
class Channel {
public:
virtual ~Channel() = default;
private:
virtual void canSend() = 0;
virtual void canRecv(bool willClose) = 0;
virtual void onClose() = 0;
friend class EventLoop;
};

View File

@ -1,50 +0,0 @@
#pragma once
#include <brynet/base/Platform.hpp>
#ifdef BRYNET_PLATFORM_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winsock2.h>
#elif defined BRYNET_PLATFORM_LINUX
#include <linux/unistd.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#elif defined BRYNET_PLATFORM_DARWIN
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef BRYNET_PLATFORM_WINDOWS
using THREAD_ID_TYPE = DWORD;
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
using THREAD_ID_TYPE = int;
#endif
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
cachedTid = GetCurrentThreadId();
#elif defined BRYNET_PLATFORM_LINUX
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;
#endif
}
return cachedTid;
}

View File

@ -1,382 +0,0 @@
#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 <memory>
#include <mutex>
#include <unordered_map>
#include <vector>
class Channel;
class TcpConnection;
using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
class EventLoop : public NonCopyable {
public:
using Ptr = std::shared_ptr<EventLoop>;
using UserFunctor = std::function<void(void)>;
public:
EventLoop()
BRYNET_NOEXCEPT
:
#ifdef BRYNET_PLATFORM_WINDOWS
mIOCP(CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)),
mWakeupChannel(std::make_unique<detail::WakeupChannel>(mIOCP))
#elif defined BRYNET_PLATFORM_LINUX
mEpollFd(epoll_create(1))
#elif defined BRYNET_PLATFORM_DARWIN
mKqueueFd(kqueue())
#endif
{
#ifdef BRYNET_PLATFORM_WINDOWS
mPGetQueuedCompletionStatusEx = NULL;
auto kernel32_module = GetModuleHandleA("kernel32.dll");
if (kernel32_module != NULL) {
mPGetQueuedCompletionStatusEx = reinterpret_cast<sGetQueuedCompletionStatusEx>(GetProcAddress(
kernel32_module,
"GetQueuedCompletionStatusEx"));
FreeLibrary(kernel32_module);
}
#elif defined BRYNET_PLATFORM_LINUX
auto eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
mWakeupChannel.reset(new 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 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);
#endif
mIsAlreadyPostWakeup = false;
mIsInBlock = true;
reAllocEventSize(1024);
mSelfThreadID = -1;
mTimer = std::make_shared<TimerMgr>();
}
virtual ~EventLoop() BRYNET_NOEXCEPT {
#ifdef BRYNET_PLATFORM_WINDOWS
CloseHandle(mIOCP);
mIOCP = INVALID_HANDLE_VALUE;
#elif defined BRYNET_PLATFORM_LINUX
close(mEpollFd);
mEpollFd = -1;
#elif defined BRYNET_PLATFORM_DARWIN
close(mKqueueFd);
mKqueueFd = -1;
#endif
}
void loop(int64_t milliseconds) {
tryInitThreadID();
#ifndef NDEBUG
assert(isInLoopThread());
#endif
if (!isInLoopThread()) {
throw BrynetCommonException("only loop in io thread");
}
if (!mAfterLoopFunctors.empty()) {
milliseconds = 0;
}
#ifdef BRYNET_PLATFORM_WINDOWS
ULONG numComplete = 0;
if (mPGetQueuedCompletionStatusEx != nullptr) {
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) {
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 {
assert(false);
}
}
#elif defined BRYNET_PLATFORM_LINUX
int numComplete = epoll_wait(mEpollFd, mEventEntries.data(), mEventEntries.size(), milliseconds);
mIsInBlock = false;
for (int i = 0; i < numComplete; ++i) {
auto channel = (Channel *)(mEventEntries[i].data.ptr);
auto event_data = mEventEntries[i].events;
if (event_data & EPOLLRDHUP) {
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);
mIsInBlock = false;
for (int i = 0; i < numComplete; ++i) {
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(false);
}
if (event.filter == EVFILT_WRITE) {
channel->canSend();
}
}
#endif
mIsAlreadyPostWakeup = false;
mIsInBlock = true;
processAsyncFunctors();
processAfterLoopFunctors();
if (static_cast<size_t>(numComplete) == mEventEntries.size()) {
reAllocEventSize(mEventEntries.size() + 128);
}
mTimer->schedule();
}
// loop指定毫秒数,但如果定时器不为空,则loop时间为当前最近定时器的剩余时间和milliseconds的较小值
void loopCompareNearTimer(int64_t milliseconds) {
tryInitThreadID();
#ifndef NDEBUG
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);
}
// 返回true表示实际发生了wakeup所需的操作(此返回值不代表接口本身操作成功与否,因为此函数永远成功)
bool wakeup() {
if (!isInLoopThread() && mIsInBlock && !mIsAlreadyPostWakeup.exchange(true)) {
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));
}
Timer::WeakPtr runAfter(std::chrono::nanoseconds timeout, UserFunctor &&callback) {
auto timer = std::make_shared<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;
}
inline bool isInLoopThread() const {
return mSelfThreadID == tid();
}
private:
void reAllocEventSize(size_t size) {
mEventEntries.resize(size);
}
void processAfterLoopFunctors() {
mCopyAfterLoopFunctors.swap(mAfterLoopFunctors);
for (const auto &x : mCopyAfterLoopFunctors) {
x();
}
mCopyAfterLoopFunctors.clear();
}
void processAsyncFunctors() {
swapAsyncFunctors();
for (const auto &x : mCopyAsyncFunctors) {
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;
}
#elif defined BRYNET_PLATFORM_DARWIN
int getKqueueHandle() const {
return mKqueueFd;
}
#endif
bool linkChannel(BrynetSocketFD fd, const Channel *ptr) BRYNET_NOEXCEPT {
#ifdef BRYNET_PLATFORM_WINDOWS
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;
#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 timespec now = { 0, 0 };
return kevent(mKqueueFd, ev, n, NULL, 0, &now) == 0;
#endif
}
TcpConnectionPtr getTcpConnection(BrynetSocketFD fd) {
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 = tid();
});
}
private:
#ifdef BRYNET_PLATFORM_WINDOWS
std::vector<OVERLAPPED_ENTRY> mEventEntries;
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;
#elif defined BRYNET_PLATFORM_DARWIN
std::vector<struct kevent> mEventEntries;
int mKqueueFd;
#endif
std::unique_ptr<WakeupChannel> mWakeupChannel;
std::atomic_bool mIsInBlock;
std::atomic_bool mIsAlreadyPostWakeup;
std::mutex mAsyncFunctorsMutex;
std::vector<UserFunctor> mAsyncFunctors;
std::vector<UserFunctor> mCopyAsyncFunctors;
std::vector<UserFunctor> mAfterLoopFunctors;
std::vector<UserFunctor> mCopyAfterLoopFunctors;
std::once_flag mOnceInitThreadID;
THREAD_ID_TYPE mSelfThreadID;
TimerMgr::Ptr mTimer;
std::unordered_map<BrynetSocketFD, TcpConnectionPtr> mTcpConnections;
friend class TcpConnection;
};

View File

@ -1,26 +0,0 @@
#pragma once
#include <stdexcept>
#include <string>
class ConnectException : public std::runtime_error {
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 {
public:
explicit BrynetCommonException(const std::string &message) :
std::runtime_error(message) {
}
explicit BrynetCommonException(const char *message) :
std::runtime_error(message) {
}
};

View File

@ -1,48 +0,0 @@
#pragma once
#include <brynet/net/detail/ListenThreadDetail.hpp>
class ListenThread : public 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() {
ListenThreadDetail::startListen();
}
void stopListen() {
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 {
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);
}
protected:
ListenThread(bool isIPV6,
const std::string &ip,
int port,
const AccepCallback &callback,
const std::vector<TcpSocketProcessCallback> &processCallbacks,
bool enabledReusePort) :
ListenThreadDetail(isIPV6, ip, port, callback, processCallbacks, enabledReusePort) {}
};

View File

@ -1,212 +0,0 @@
#pragma once
#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>
#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 {
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) {
return;
}
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;
}
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) {
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 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) {
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;
}
}
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)) {
stack_push(result, &self->pollFds[i].fd);
}
}
}
static int poller_poll(struct poller_s *self, long overtime) {
#ifdef BRYNET_PLATFORM_WINDOWS
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);
#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) {
const struct pollfd *pf = find_pollfd(self, fd);
if (pf == NULL) {
return false;
}
return check_event(pf, type);
}

View File

@ -1,128 +0,0 @@
#pragma once
#include <brynet/net/TcpService.hpp>
/* 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 (needlepos = 0; needlepos < needlesize; needlepos++) {
if (hay[haypos + needlepos] != needle[needlepos]) {
// Next character in haystack.
break;
}
}
if (needlepos == needlesize) {
result = haypos;
isOK = true;
return;
}
}
isOK = false;
}
class 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) {
return receive(std::make_shared<size_t>(len), std::move(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()) {
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 {
break;
}
}
return procLen;
}
private:
struct PendingReceive {
std::shared_ptr<size_t> len;
std::string str;
Handle handle;
};
std::deque<std::shared_ptr<PendingReceive> > mPendingReceives;
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](BasePacketReader &reader) {
auto procLen = promiseReceive->process(reader.begin(), reader.size());
reader.addPos(procLen);
reader.savePos();
});
return promiseReceive;
}

View File

@ -1,151 +0,0 @@
#pragma once
#include <brynet/base/Noexcept.hpp>
#include <brynet/base/NonCopyable.hpp>
#include <brynet/base/Platform.hpp>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#ifdef BRYNET_USE_OPENSSL
#ifdef __cplusplus
extern "C" {
#endif
#include <openssl/err.h>
#include <openssl/ssl.h>
#ifdef __cplusplus
}
#endif
#endif
#ifdef BRYNET_USE_OPENSSL
#ifndef CRYPTO_THREADID_set_callback
static void cryptoSetThreadIDCallback(CRYPTO_THREADID *id) {
#ifdef BRYNET_PLATFORM_WINDOWS
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()));
#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) {
(void)file;
(void)line;
if (mode & CRYPTO_LOCK) {
cryptoLocks[type]->lock();
} else if (mode & CRYPTO_UNLOCK) {
cryptoLocks[type]->unlock();
}
}
#endif
static std::once_flag initCryptoThreadSafeSupportOnceFlag;
static void InitCryptoThreadSafeSupport() {
#ifndef CRYPTO_THREADID_set_callback
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);
#endif
}
#endif
class SSLHelper : public 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
static Ptr Create() {
class make_shared_enabler : public SSLHelper {
};
return std::make_shared<make_shared_enabler>();
}
protected:
SSLHelper() BRYNET_NOEXCEPT {
#ifdef BRYNET_USE_OPENSSL
mOpenSSLCTX = nullptr;
#endif
}
virtual ~SSLHelper() BRYNET_NOEXCEPT {
#ifdef BRYNET_USE_OPENSSL
destroySSL();
#endif
}
private:
#ifdef BRYNET_USE_OPENSSL
SSL_CTX *mOpenSSLCTX;
#endif
};

View File

@ -1,47 +0,0 @@
#include <memory>
#include <string>
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));
}

View File

@ -1,186 +0,0 @@
#pragma once
#include <brynet/base/NonCopyable.hpp>
#include <brynet/net/SocketLibFunction.hpp>
#include <exception>
#include <memory>
#include <stdexcept>
#include <string>
class TcpConnection;
class UniqueFd final : public NonCopyable {
public:
explicit UniqueFd(BrynetSocketFD fd) :
mFD(fd) {}
~UniqueFd() {
SocketClose(mFD);
}
UniqueFd(const UniqueFd &other) = delete;
UniqueFd &operator=(const UniqueFd &other) = delete;
BrynetSocketFD getFD() const {
return mFD;
}
private:
BrynetSocketFD mFD;
};
class TcpSocket : public NonCopyable {
private:
class TcpSocketDeleter {
public:
void operator()(TcpSocket *ptr) const {
delete ptr;
}
};
public:
using Ptr = std::unique_ptr<TcpSocket, TcpSocketDeleter>;
public:
static Ptr Create(BrynetSocketFD fd, bool serverSide) {
class make_unique_enabler : public TcpSocket {
public:
make_unique_enabler(BrynetSocketFD fd, bool serverSide) :
TcpSocket(fd, serverSide) {}
};
return Ptr(new make_unique_enabler(fd, serverSide));
}
public:
void setNodelay() const {
SocketNodelay(mFD);
}
bool setNonblock() const {
return SocketNonblock(mFD);
}
void setSendSize(int sdSize) const {
SocketSetSendSize(mFD, sdSize);
}
void setRecvSize(int rdSize) const {
SocketSetRecvSize(mFD, rdSize);
}
std::string getRemoteIP() const {
return GetIPOfSocket(mFD);
}
bool isServerSide() const {
return mServerSide;
}
protected:
TcpSocket(BrynetSocketFD fd, bool serverSide) :
mFD(fd),
mServerSide(serverSide) {
}
virtual ~TcpSocket() {
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 NonCopyable {
private:
class ListenSocketDeleter {
public:
void operator()(ListenSocket *ptr) const {
delete ptr;
}
};
public:
using Ptr = std::unique_ptr<ListenSocket, ListenSocketDeleter>;
public:
TcpSocket::Ptr accept() {
const auto clientFD = Accept(mFD, nullptr, nullptr);
if (clientFD == BRYNET_INVALID_SOCKET) {
#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(Accept(mFD, nullptr, nullptr), true);
mIdle = 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);
}
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) {
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
mIdle = TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
#endif
}
virtual ~ListenSocket() {
SocketClose(mFD);
}
private:
const BrynetSocketFD mFD;
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
TcpSocket::Ptr mIdle;
#endif
friend class TcpConnection;
};

View File

@ -1,287 +0,0 @@
#pragma once
#include <string.h>
#include <brynet/net/SocketLibTypes.hpp>
#include <string>
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;
}
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
signal(SIGPIPE, SIG_IGN);
#endif
return ret;
}
static void DestroySocket() {
#ifdef BRYNET_PLATFORM_WINDOWS
WSACleanup();
#endif
}
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;
#ifdef BRYNET_PLATFORM_WINDOWS
err = ioctlsocket(fd, FIONBIO, &ul);
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
err = ioctl(fd, FIONBIO, &ul);
#endif
return err != BRYNET_SOCKET_ERROR;
}
static bool SocketNonblock(BrynetSocketFD fd) {
int err;
unsigned long ul = true;
#ifdef BRYNET_PLATFORM_WINDOWS
err = ioctlsocket(fd, FIONBIO, &ul);
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
err = ioctl(fd, FIONBIO, &ul);
#endif
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 SocketSetRecvSize(BrynetSocketFD fd, int rd_size) {
return ::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&rd_size, sizeof(rd_size));
}
static int SocketSetReusePort(BrynetSocketFD fd) {
#ifdef BRYNET_PLATFORM_WINDOWS
return 0;
#else
int enable = 1;
return ::setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
#endif
}
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) {
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 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));
break;
case AF_INET6:
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) {
#ifdef BRYNET_PLATFORM_WINDOWS
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);
}
#endif
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;
}
/* send error if transnum < 0 */
return transnum;
}
static BrynetSocketFD Accept(BrynetSocketFD listenSocket, struct sockaddr *addr, socklen_t *addrLen) {
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;
}
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) {
return localaddr;
}
return localaddr;
}
static bool IsSelfConnect(BrynetSocketFD fd) {
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;
}
}

View File

@ -1,72 +0,0 @@
#pragma once
#include <brynet/base/Platform.hpp>
#ifdef BRYNET_PLATFORM_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <WinError.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/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 <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.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."
#endif
#ifdef BRYNET_PLATFORM_WINDOWS
typedef SOCKET BrynetSocketFD;
#define BRYNET_ERRNO WSAGetLastError()
#define BRYNET_ENOTSOCK WSAENOTSOCK
#define BRYNET_EWOULDBLOCK WSAEWOULDBLOCK
#define BRYNET_EINTR WSAEINTR
#define BRYNET_ECONNABORTED WSAECONNABORTED
#define BRYNET_SOCKET_ERROR SOCKET_ERROR
#define BRYNET_INVALID_SOCKET INVALID_SOCKET
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
#define BRYNET_ERRNO errno
#define BRYNET_ENOTSOCK EBADF
#define BRYNET_EWOULDBLOCK EAGAIN
#define BRYNET_EINTR EINTR
#define BRYNET_ECONNABORTED ECONNABORTED
typedef int BrynetSocketFD;
#define BRYNET_SOCKET_ERROR (-1)
#define BRYNET_INVALID_SOCKET (-1)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
#pragma once
#include <brynet/net/detail/TCPServiceDetail.hpp>
using ConnectionOption = ConnectionOption;
class TcpService : public TcpServiceDetail,
public std::enable_shared_from_this<TcpService> {
public:
using Ptr = std::shared_ptr<TcpService>;
using FrameCallback = TcpServiceDetail::FrameCallback;
public:
static Ptr Create() {
struct make_shared_enabler : public TcpService {
};
return std::make_shared<make_shared_enabler>();
}
void startWorkerThread(size_t threadNum,
FrameCallback callback = nullptr) {
TcpServiceDetail::startWorkerThread(threadNum, callback);
}
void stopWorkerThread() {
TcpServiceDetail::stopWorkerThread();
}
bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption options) {
return TcpServiceDetail::addTcpConnection(std::move(socket), options);
}
EventLoop::Ptr getRandomEventLoop() {
return TcpServiceDetail::getRandomEventLoop();
}
private:
TcpService() = default;
};

View File

@ -1,13 +0,0 @@
#pragma once
#include <brynet/net/SSLHelper.hpp>
#include <brynet/net/TcpConnection.hpp>
class ConnectionOption final {
public:
std::vector<TcpConnection::EnterCallback> enterCallback;
SSLHelper::Ptr sslHelper;
bool useSSL = false;
bool forceSameThreadLoop = false;
size_t maxRecvBufferSize = 128;
};

View File

@ -1,128 +0,0 @@
#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 <thread>
#ifdef BRYNET_HAVE_LANG_CXX17
#include <shared_mutex>
#else
#include <mutex>
#endif
class AsyncConnectorDetail : public NonCopyable {
protected:
void startWorkerThread() {
#ifdef BRYNET_HAVE_LANG_CXX17
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
#else
std::lock_guard<std::mutex> lck(mThreadGuard);
#endif
if (mThread != nullptr) {
return;
}
mIsRun = std::make_shared<bool>(true);
mWorkInfo = std::make_shared<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) {
RunOnceCheckConnect(eventLoop, workerInfo);
}
workerInfo->causeAllFailed();
});
}
void stopWorkerThread() {
#ifdef BRYNET_HAVE_LANG_CXX17
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
#else
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;
}
void asyncConnect(ConnectOption option) {
#ifdef BRYNET_HAVE_LANG_CXX17
std::shared_lock<std::shared_mutex> lck(mThreadGuard);
#else
std::lock_guard<std::mutex> lck(mThreadGuard);
#endif
if (option.completedCallback == nullptr && option.failedCallback == 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 = 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<ConnectorWorkInfo> mWorkInfo;
std::shared_ptr<std::thread> mThread;
#ifdef BRYNET_HAVE_LANG_CXX17
std::shared_mutex mThreadGuard;
#else
std::mutex mThreadGuard;
#endif
std::shared_ptr<bool> mIsRun;
};

View File

@ -1,301 +0,0 @@
#pragma once
#include <brynet/base/CPP_VERSION.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>
#else
#include <mutex>
#endif
class AsyncConnectAddr final {
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 NonCopyable {
public:
using Ptr = std::shared_ptr<ConnectorWorkInfo>;
ConnectorWorkInfo() BRYNET_NOEXCEPT {
mPoller.reset(poller_new());
mPollResult.reset(stack_new(1024, sizeof(BrynetSocketFD)));
}
void checkConnectStatus(int millSecond) {
if (poller_poll(mPoller.get(), millSecond) <= 0) {
return;
}
std::set<BrynetSocketFD> totalFds;
std::set<BrynetSocketFD> successFds;
poller_visitor(mPoller.get(), WriteCheck, mPollResult.get());
while (true) {
auto p = stack_popfront(mPollResult.get());
if (p == nullptr) {
break;
}
const auto fd = *(BrynetSocketFD *)p;
totalFds.insert(fd);
if (isConnectSuccess(fd, false) &&
!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);
}
}
bool isConnectSuccess(BrynetSocketFD clientfd, bool willCheckWrite) const {
if (willCheckWrite && !poller_check(mPoller.get(), clientfd, WriteCheck)) {
return false;
}
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++);
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;
InitSocket();
clientfd = SocketCreate(AF_INET, SOCK_STREAM, 0);
if (clientfd == BRYNET_INVALID_SOCKET) {
goto FAILED;
}
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 (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, 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) {
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);
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;
};
std::map<BrynetSocketFD, ConnectingInfo> mConnectingInfos;
class PollerDeleter {
public:
void operator()(struct poller_s *ptr) const {
poller_delete(ptr);
}
};
class StackDeleter {
public:
void operator()(struct stack_s *ptr) const {
stack_delete(ptr);
}
};
std::unique_ptr<struct poller_s, PollerDeleter> mPoller;
std::unique_ptr<struct stack_s, StackDeleter> mPollResult;
};
static void RunOnceCheckConnect(
const std::shared_ptr<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;
};

View File

@ -1,51 +0,0 @@
#pragma once
#include <brynet/base/NonCopyable.hpp>
#include <brynet/net/EventLoop.hpp>
#include <memory>
#include <thread>
class TcpServiceDetail;
class IOLoopData : public 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) {
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)) {}
};
return std::make_shared<make_shared_enabler>(std::move(eventLoop),
std::move(ioThread));
}
const EventLoop::Ptr &getEventLoop() const {
return mEventLoop;
}
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;
const EventLoop::Ptr mEventLoop;
private:
std::shared_ptr<std::thread> mIOThread;
friend class TcpServiceDetail;
};
using IOLoopDataPtr = std::shared_ptr<IOLoopData>;

View File

@ -1,140 +0,0 @@
#pragma once
#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 <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
class ListenThreadDetail : public NonCopyable {
protected:
using AccepCallback = std::function<void(TcpSocket::Ptr)>;
using TcpSocketProcessCallback = std::function<void(TcpSocket &)>;
void startListen() {
std::lock_guard<std::mutex> lck(mListenThreadGuard);
if (mListenThread != nullptr) {
return;
}
const auto fd = Listen(mIsIPV6, mIP.c_str(), mPort, 512, mEnabledReusePort);
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));
}
}
});
}
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.
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,
bool enabledReusePort) :
mIsIPV6(isIPV6),
mIP(ip),
mPort(port),
mCallback(callback),
mProcessCallbacks(processCallbacks),
mEnabledReusePort(enabledReusePort) {
if (mCallback == nullptr) {
throw BrynetCommonException("accept callback is nullptr");
}
mRunListen = std::make_shared<bool>(false);
}
virtual ~ListenThreadDetail() BRYNET_NOEXCEPT {
stopListen();
}
private:
static 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;
}
return nullptr;
}
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;
};

View File

@ -1,142 +0,0 @@
#pragma once
#include <brynet/base/Noexcept.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 <functional>
#include <memory>
#include <random>
#include <thread>
#include <vector>
class TcpServiceDetail : public NonCopyable {
protected:
using FrameCallback = std::function<void(const EventLoop::Ptr &)>;
const static unsigned int sDefaultLoopTimeOutMS = 100;
void startWorkerThread(size_t threadNum,
FrameCallback callback = nullptr) {
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);
}
}
}));
}
}
void stopWorkerThread() {
std::lock_guard<std::mutex> lck(mServiceGuard);
std::lock_guard<std::mutex> lock(mIOLoopGuard);
*mRunIOLoop = false;
for (const auto &v : mIOLoopDatas) {
v->getEventLoop()->wakeup();
try {
if (v->getIOThread()->joinable()) {
v->getIOThread()->join();
}
} catch (std::system_error &e) {
(void)e;
}
}
mIOLoopDatas.clear();
}
bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption option) {
if (option.maxRecvBufferSize <= 0) {
throw BrynetCommonException("buffer size is zero");
}
EventLoop::Ptr eventLoop;
if (option.forceSameThreadLoop) {
eventLoop = getSameThreadEventLoop();
} else {
eventLoop = getRandomEventLoop();
}
if (eventLoop == nullptr) {
return false;
}
auto wrapperEnterCallback = [option](const TcpConnection::Ptr &tcpConnection) {
for (const auto &callback : option.enterCallback) {
callback(tcpConnection);
}
};
if (option.useSSL && option.sslHelper == nullptr) {
option.sslHelper = SSLHelper::Create();
}
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) {
return nullptr;
} else if (ioLoopSize == 1) {
return mIOLoopDatas.front()->getEventLoop();
} else {
return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop();
}
}
TcpServiceDetail() BRYNET_NOEXCEPT
: mRandom(static_cast<unsigned int>(
std::chrono::system_clock::now().time_since_epoch().count())) {
mRunIOLoop = std::make_shared<bool>(false);
}
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;
};

View File

@ -1,106 +0,0 @@
#pragma once
#include <brynet/base/NonCopyable.hpp>
#ifdef BRYNET_PLATFORM_WINDOWS
#include <brynet/net/port/Win.hpp>
#endif
#include <brynet/net/Channel.hpp>
#include <brynet/net/Socket.hpp>
#ifdef BRYNET_PLATFORM_WINDOWS
class WakeupChannel final : public Channel, public NonCopyable {
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);
}
private:
void canRecv(bool) BRYNET_NOEXCEPT override {
;
}
void canSend() BRYNET_NOEXCEPT override {
;
}
void onClose() BRYNET_NOEXCEPT override {
;
}
HANDLE mIOCP;
port::Win::OverlappedExt mWakeupOvl;
};
#elif defined BRYNET_PLATFORM_LINUX
class WakeupChannel final : public Channel, public NonCopyable {
public:
explicit WakeupChannel(BrynetSocketFD fd) :
mUniqueFd(fd) {
}
bool wakeup() {
uint64_t one = 1;
return write(mUniqueFd.getFD(), &one, sizeof one) > 0;
}
private:
void canRecv(bool) override {
char temp[1024 * 10];
while (true) {
auto n = read(mUniqueFd.getFD(), temp, sizeof(temp));
if (n == -1 || static_cast<size_t>(n) < sizeof(temp)) {
break;
}
}
}
void canSend() override {
}
void onClose() override {
}
private:
UniqueFd mUniqueFd;
};
#elif defined BRYNET_PLATFORM_DARWIN
class WakeupChannel final : public Channel, public NonCopyable {
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);
struct timespec timeout = { 0, 0 };
return kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout) == 0;
}
private:
void canRecv(bool) override {
}
void canSend() override {
}
void onClose() override {
}
private:
int mKqueueFd;
int mUserEvent;
};
#endif

View File

@ -1,196 +0,0 @@
#pragma once
#include <array>
#include <cassert>
#include <map>
#include <string>
class HttpQueryParameter final {
public:
void add(const std::string &k, const std::string &v) {
if (!mParameter.empty()) {
mParameter += "&";
}
mParameter += k;
mParameter += "=";
mParameter += v;
}
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
};
HttpRequest() {
setMethod(HTTP_METHOD::HTTP_METHOD_GET);
}
void setMethod(HTTP_METHOD protocol) {
mMethod = protocol;
assert(mMethod > HTTP_METHOD::HTTP_METHOD_HEAD &&
mMethod < HTTP_METHOD::HTTP_METHOD_MAX);
}
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) {
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 += "\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,
};
HttpResponse() :
mStatus(HTTP_RESPONSE_STATUS::OK) {
}
void setStatus(HTTP_RESPONSE_STATUS status) {
mStatus = status;
}
void setContentType(const std::string &v) {
addHeadValue("Content-Type", v);
}
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(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 ";
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;
};

View File

@ -1,282 +0,0 @@
#pragma once
#include <brynet/net/http/WebSocketFormat.hpp>
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include "http_parser.h"
class HttpService;
class HTTPParser {
public:
using Ptr = std::shared_ptr<HTTPParser>;
explicit HTTPParser(http_parser_type parserType) :
mParserType(parserType) {
mLastWasValue = true;
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()) {
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;
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);
}
return nparsed;
}
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 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",
httpParser->mUrl.c_str());
return -1;
}
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,
u.field_data[UF_QUERY].len);
}
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->mCurrentField.clear();
}
httpParser->mCurrentField.append(at, length);
httpParser->mLastWasValue = false;
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;
}
static int sBodyHandle(http_parser *hp, const char *at, size_t length) {
HTTPParser *httpParser = (HTTPParser *)hp->data;
httpParser->mBody.append(at, length);
return 0;
}
private:
const http_parser_type mParserType;
http_parser mParser;
http_parser_settings mSettings;
int mMethod = -1;
bool mIsUpgrade = false;
bool mIsWebSocket = false;
bool mIsKeepAlive;
bool mISCompleted;
bool mLastWasValue;
std::string mCurrentField;
std::string mCurrentValue;
std::string mPath;
std::string mQuery;
std::string mStatus;
std::map<std::string, std::string> mHeadValues;
int mStatusCode;
std::string mUrl;
std::string mBody;
std::string mWSCacheFrame;
std::string mWSParsePayload;
WebSocketFormat::WebSocketFrameType mWSFrameType;
private:
friend class HttpService;
};

View File

@ -1,299 +0,0 @@
#pragma once
#include <brynet/base/NonCopyable.hpp>
#include <brynet/net/TcpService.hpp>
#include <brynet/net/http/HttpParser.hpp>
#include <brynet/net/http/WebSocketFormat.hpp>
#include <memory>
class HttpService;
class HttpSessionHandlers;
class HttpSession : public 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) {
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 {
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();
auto httpParser = std::make_shared<HTTPParser>(HTTP_BOTH);
session->setDisConnectCallback([httpSession, httpParser](const TcpConnection::Ptr &) {
if (!httpParser->isCompleted()) {
// 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](
BasePacketReader &reader) {
size_t retLen = 0;
if (httpParser->isWebSocket()) {
retLen = HttpService::ProcessWebSocket(reader.begin(),
reader.size(),
httpParser,
httpSession);
} else if (httpParser->isUpgrade()) {
// TODO::not support other upgrade protocol
} else {
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()) {
httpSession->postClose();
}
}
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;
}
};

View File

@ -1,204 +0,0 @@
#pragma once
#include <stdint.h>
#include <brynet/base/crypto/Base64.hpp>
#include <brynet/base/crypto/SHA1.hpp>
#include <chrono>
#include <random>
#include <string>
class WebSocketFormat {
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
};
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);
std::string base64Str = base64_encode((const unsigned char *)puDest, 20);
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";
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));
}
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;
}
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);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +0,0 @@
#pragma once
#include <brynet/net/SocketLibTypes.hpp>
#ifdef BRYNET_PLATFORM_WINDOWS
class Win {
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));
}
};
};
#endif

View File

@ -1,177 +0,0 @@
#pragma once
#include <brynet/net/AsyncConnector.hpp>
#include <brynet/net/Exception.hpp>
#include <brynet/net/TcpService.hpp>
#include <future>
#include <utility>
using CompletedCallback = AsyncConnectAddr::CompletedCallback;
using ProcessTcpSocketCallback = AsyncConnectAddr::ProcessTcpSocketCallback;
using FailedCallback = AsyncConnectAddr::FailedCallback;
template <typename Derived>
class BaseSocketConnectBuilder {
public:
virtual ~BaseSocketConnectBuilder() = default;
Derived &WithConnector(AsyncConnector::Ptr connector) {
mConnector = std::move(connector);
return static_cast<Derived &>(*this);
}
Derived &WithAddr(std::string ip, size_t port) {
mConnectOption.ip = std::move(ip);
mConnectOption.port = port;
return static_cast<Derived &>(*this);
}
Derived &WithTimeout(std::chrono::nanoseconds timeout) {
mConnectOption.timeout = timeout;
return static_cast<Derived &>(*this);
}
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> {
};

View File

@ -1,77 +0,0 @@
#pragma once
#include <brynet/net/http/HttpService.hpp>
#include <brynet/net/wrapper/ConnectionBuilder.hpp>
#include <utility>
class HttpConnectionBuilder {
public:
HttpConnectionBuilder &WithService(TcpService::Ptr service) {
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(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) {
throw BrynetCommonException("not setting http enter callback");
}
auto callback = mHttpEnterCallback;
auto builder = mBuilder;
builder.AddEnterCallback([callback](const TcpConnection::Ptr &session) {
HttpService::setup(session, callback);
});
builder.asyncConnect();
}
private:
HttpSession::EnterCallback mHttpEnterCallback;
ConnectionBuilder mBuilder;
};

View File

@ -1,64 +0,0 @@
#pragma once
#include <brynet/net/http/HttpService.hpp>
#include <brynet/net/wrapper/ServiceBuilder.hpp>
#include <utility>
class HttpListenerBuilder {
public:
HttpListenerBuilder &WithService(TcpService::Ptr service) {
mBuilder.WithService(std::move(service));
return *this;
}
HttpListenerBuilder &WithEnterCallback(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) {
throw BrynetCommonException("not setting http enter callback");
}
auto callback = mHttpEnterCallback;
mBuilder.AddEnterCallback([callback](const TcpConnection::Ptr &session) {
HttpService::setup(session, callback);
});
mBuilder.asyncRun();
}
private:
HttpSession::EnterCallback mHttpEnterCallback;
ListenerBuilder mBuilder;
};

View File

@ -1,97 +0,0 @@
#pragma once
#include <brynet/net/Exception.hpp>
#include <brynet/net/ListenThread.hpp>
#include <brynet/net/TcpService.hpp>
#include <brynet/net/detail/ConnectionOption.hpp>
#include <utility>
template <typename Derived>
class BaseListenerBuilder {
public:
virtual ~BaseListenerBuilder() = default;
Derived &WithService(TcpService::Ptr service) {
mTcpService = std::move(service);
return static_cast<Derived &>(*this);
}
Derived &WithAddr(bool ipV6, std::string ip, size_t port) {
mIsIpV6 = ipV6;
mListenAddr = std::move(ip);
mPort = port;
return static_cast<Derived &>(*this);
}
Derived &WithReusePort() {
mEnabledReusePort = true;
return static_cast<Derived &>(*this);
}
Derived &AddSocketProcess(const ListenThread::TcpSocketProcessCallback &callback) {
mSocketProcessCallbacks.push_back(callback);
return static_cast<Derived &>(*this);
}
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) {
throw BrynetCommonException("tcp service is nullptr");
}
if (mListenAddr.empty()) {
throw BrynetCommonException("not config listen addr");
}
auto service = mTcpService;
auto option = mSocketOption;
mListenThread = ListenThread::Create(
mIsIpV6,
mListenAddr,
mPort,
[service, option](TcpSocket::Ptr socket) {
service->addTcpConnection(std::move(socket), option);
},
mSocketProcessCallbacks,
mEnabledReusePort);
mListenThread->startListen();
}
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> {
};