mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2025-02-20 15:14:26 +01:00
Removed brynet.
This commit is contained in:
parent
a1afe210d1
commit
2133be9254
@ -1,4 +1,3 @@
|
||||
RapidJSON 0ccdbf364c577803e2a751f5aededce935314313
|
||||
brynet a63ac30364641000ccf8f831eea864aa98f1d50d
|
||||
rapidxml 1.13
|
||||
maddy adb1a910d4aadea09cb7b200f2ec204f61214596
|
@ -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.
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define BRYNET_VERSION 1010000
|
@ -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
|
@ -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
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class NonCopyable {
|
||||
public:
|
||||
NonCopyable(const NonCopyable &) = delete;
|
||||
const NonCopyable &operator=(const NonCopyable &) = delete;
|
||||
|
||||
protected:
|
||||
NonCopyable() = default;
|
||||
~NonCopyable() = default;
|
||||
};
|
||||
|
@ -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>;
|
@ -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
|
@ -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;
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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
|
@ -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
|
@ -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
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
@ -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;
|
||||
};
|
@ -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) {
|
||||
}
|
||||
};
|
@ -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) {}
|
||||
};
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
@ -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>;
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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
@ -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
|
@ -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> {
|
||||
};
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
@ -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> {
|
||||
};
|
Loading…
Reference in New Issue
Block a user