diff --git a/core/http_server.cpp b/core/http_server.cpp index 4394674..81edfd6 100644 --- a/core/http_server.cpp +++ b/core/http_server.cpp @@ -85,22 +85,16 @@ void HTTPServer::initialize() { delete listenBuilder; listenBuilder = new wrapper::HttpListenerBuilder(); - listenBuilder->configureService(service); + listenBuilder->WithService(service); - listenBuilder->configureSocketOptions({ - [](TcpSocket &socket) { + listenBuilder->AddSocketProcess([](TcpSocket &socket) { socket.setNodelay(); socket.setNonblock(); - }, - }); + }); - listenBuilder->configureConnectionOptions({ AddSocketOption::WithMaxRecvBufferSize(1024) }); + listenBuilder->WithAddr(false, "0.0.0.0", p_port); - listenBuilder->configureListen([p_port](wrapper::BuildListenConfig builder) { - builder.setAddr(false, "0.0.0.0", p_port); - }); - - listenBuilder->configureEnterCallback([this](const HttpSession::Ptr &httpSession, HttpSessionHandlers &handlers) { + listenBuilder->WithEnterCallback([this](const HttpSession::Ptr &httpSession, HttpSessionHandlers &handlers) { handlers.setHttpCallback([this](const HTTPParser &httpParser, const HttpSession::Ptr &session){ this->httpEnterCallbackDefault(httpParser, session); }); handlers.setWSCallback([this](const HttpSession::Ptr &httpSession, WebSocketFormat::WebSocketFrameType opcode, const std::string &payload){ this->wsEnterCallbackDefault(httpSession, opcode, payload); }); handlers.setClosedCallback([this](const HttpSession::Ptr &session){ this->closedCallbackDefault(session); }); diff --git a/libs/HEADS b/libs/HEADS index 7654232..7f78a64 100644 --- a/libs/HEADS +++ b/libs/HEADS @@ -1,4 +1,4 @@ RapidJSON 0ccdbf364c577803e2a751f5aededce935314313 -brynet b0d13e7419628d0f7051a2bb310daaf8a506e08b +brynet a63ac30364641000ccf8f831eea864aa98f1d50d rapidxml 1.13 maddy adb1a910d4aadea09cb7b200f2ec204f61214596 \ No newline at end of file diff --git a/libs/brynet/Version.hpp b/libs/brynet/Version.hpp index 80b0939..64e3a5d 100644 --- a/libs/brynet/Version.hpp +++ b/libs/brynet/Version.hpp @@ -1,3 +1,3 @@ #pragma once -#define BRYNET_VERSION 1009000 +#define BRYNET_VERSION 1010000 diff --git a/libs/brynet/base/Any.hpp b/libs/brynet/base/Any.hpp index 6e3d58a..d8dd1d2 100644 --- a/libs/brynet/base/Any.hpp +++ b/libs/brynet/base/Any.hpp @@ -11,20 +11,20 @@ namespace brynet { namespace base { #ifdef BRYNET_HAVE_LANG_CXX17 - using BrynetAny = std::any; +using BrynetAny = std::any; - template - auto cast(const BrynetAny& ud) - { - return std::any_cast(&ud); - } +template +auto cast(const BrynetAny& ud) +{ + return std::any_cast(&ud); +} #else - using BrynetAny = int64_t; - template - const T* cast(const BrynetAny& ud) - { - return static_cast(&ud); - } +using BrynetAny = int64_t; +template +const T* cast(const BrynetAny& ud) +{ + return static_cast(&ud); +} #endif -} } +}}// namespace brynet::base diff --git a/libs/brynet/base/AppStatus.hpp b/libs/brynet/base/AppStatus.hpp index 88867fc..a4bff91 100644 --- a/libs/brynet/base/AppStatus.hpp +++ b/libs/brynet/base/AppStatus.hpp @@ -1,47 +1,47 @@ #pragma once -#include -#include #include #include +#include +#include #ifdef BRYNET_PLATFORM_WINDOWS #include #else +#include #include #include -#include #endif namespace brynet { namespace base { - static bool app_kbhit() - { +static bool app_kbhit() +{ #ifdef BRYNET_PLATFORM_WINDOWS - return _kbhit(); + return _kbhit(); #else - struct termios oldt; - tcgetattr(STDIN_FILENO, &oldt); - auto newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - const auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0); - fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + struct termios oldt; + tcgetattr(STDIN_FILENO, &oldt); + auto newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + const auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); - const auto ch = getchar(); + const auto ch = getchar(); - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - fcntl(STDIN_FILENO, F_SETFL, oldf); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); - if (ch != EOF) - { - ungetc(ch, stdin); - return true; - } - - return false; -#endif + if (ch != EOF) + { + ungetc(ch, stdin); + return true; } -} } \ No newline at end of file + return false; +#endif +} + +}}// namespace brynet::base diff --git a/libs/brynet/base/Array.hpp b/libs/brynet/base/Array.hpp index 0b0624f..71f8019 100644 --- a/libs/brynet/base/Array.hpp +++ b/libs/brynet/base/Array.hpp @@ -1,129 +1,128 @@ #pragma once -#include -#include -#include #include +#include +#include namespace brynet { namespace base { - struct array_s +struct array_s +{ + void* buffer; + size_t buffer_size; + size_t element_size; + size_t element_num; +}; + +static void array_delete(struct array_s* self) +{ + if (self == nullptr) { - void* buffer; - size_t buffer_size; - size_t element_size; - size_t element_num; - }; - - static void array_delete(struct array_s* self) - { - if (self == nullptr) - { - return; - } - - if (self->buffer != nullptr) - { - free(self->buffer); - self->buffer = nullptr; - } - - self->element_num = 0; - free(self); - self = nullptr; + return; } - static struct array_s* array_new(size_t num, size_t element_size) + if (self->buffer != nullptr) { - auto ret = (struct array_s*)malloc(sizeof(struct array_s)); - if (ret == nullptr) - { - return nullptr; - } - - const auto buffer_size = num * element_size; - - ret->buffer_size = 0; - ret->element_size = 0; - ret->element_num = 0; - ret->buffer = malloc(buffer_size); - - if (ret->buffer != nullptr) - { - ret->element_size = element_size; - ret->element_num = num; - ret->buffer_size = buffer_size; - } - else - { - array_delete(ret); - ret = nullptr; - } - - return ret; + free(self->buffer); + self->buffer = nullptr; } - static void* array_at(struct array_s* self, size_t index) + self->element_num = 0; + free(self); + self = nullptr; +} + +static struct array_s* array_new(size_t num, size_t element_size) +{ + auto ret = (struct array_s*) malloc(sizeof(struct array_s)); + if (ret == nullptr) { - void* ret = nullptr; - - if (index < self->element_num) - { - ret = (char*)(self->buffer) + (index * self->element_size); - } - else - { - assert(false); - } - - return ret; + return nullptr; } - static bool array_set(struct array_s* self, size_t index, const void* data) - { - void* old_data = array_at(self, index); + const auto buffer_size = num * element_size; - if (old_data != nullptr) - { - memcpy(old_data, data, self->element_size); - return true; - } - else - { - return false; - } + ret->buffer_size = 0; + ret->element_size = 0; + ret->element_num = 0; + ret->buffer = malloc(buffer_size); + + if (ret->buffer != nullptr) + { + ret->element_size = element_size; + ret->element_num = num; + ret->buffer_size = buffer_size; + } + else + { + array_delete(ret); + ret = nullptr; } - static bool array_increase(struct array_s* self, size_t increase_num) + return ret; +} + +static void* array_at(struct array_s* self, size_t index) +{ + void* ret = nullptr; + + if (index < self->element_num) { - if (increase_num == 0) - { - return false; - } - - const auto new_buffer_size = self->buffer_size + increase_num * self->element_size; - auto new_buffer = malloc(new_buffer_size); - - if (new_buffer != nullptr) - { - memcpy(new_buffer, self->buffer, self->buffer_size); - free(self->buffer); - self->buffer = new_buffer; - self->element_num += increase_num; - self->buffer_size = new_buffer_size; - - return true; - } - else - { - assert(false); - return false; - } + ret = (char*) (self->buffer) + (index * self->element_size); + } + else + { + assert(false); } - static size_t array_num(const struct array_s* self) + return ret; +} + +static bool array_set(struct array_s* self, size_t index, const void* data) +{ + void* old_data = array_at(self, index); + + if (old_data != nullptr) { - return self->element_num; + memcpy(old_data, data, self->element_size); + return true; + } + else + { + return false; + } +} + +static bool array_increase(struct array_s* self, size_t increase_num) +{ + if (increase_num == 0) + { + return false; } -} } \ No newline at end of file + const auto new_buffer_size = self->buffer_size + increase_num * self->element_size; + auto new_buffer = malloc(new_buffer_size); + + if (new_buffer != nullptr) + { + memcpy(new_buffer, self->buffer, self->buffer_size); + free(self->buffer); + self->buffer = new_buffer; + self->element_num += increase_num; + self->buffer_size = new_buffer_size; + + return true; + } + else + { + assert(false); + return false; + } +} + +static size_t array_num(const struct array_s* self) +{ + return self->element_num; +} + +}}// namespace brynet::base diff --git a/libs/brynet/base/Buffer.hpp b/libs/brynet/base/Buffer.hpp index f1ed8b3..b8c1e40 100644 --- a/libs/brynet/base/Buffer.hpp +++ b/libs/brynet/base/Buffer.hpp @@ -1,189 +1,186 @@ #pragma once -#include -#include #include #include namespace brynet { namespace base { - struct buffer_s +struct buffer_s +{ + char* data; + size_t data_len; + + size_t write_pos; + size_t read_pos; +}; + +static void buffer_delete(struct buffer_s* self) +{ + if (self == nullptr) { - char* data; - size_t data_len; - - size_t write_pos; - size_t read_pos; - }; - - static void buffer_delete(struct buffer_s* self) - { - if (self == nullptr) - { - return; - } - - if (self->data != nullptr) - { - free(self->data); - self->data = nullptr; - } - - free(self); - self = nullptr; + return; } - static struct buffer_s* buffer_new(size_t buffer_size) + if (self->data != nullptr) { - struct buffer_s* ret = (struct buffer_s*)malloc(sizeof(struct buffer_s)); - if (ret == nullptr) - { - return nullptr; - } + free(self->data); + self->data = nullptr; + } - ret->data_len = 0; - ret->read_pos = 0; - ret->write_pos = 0; - ret->data = (char*)malloc(sizeof(char) * buffer_size); + free(self); + self = nullptr; +} - if (ret->data != nullptr) +static struct buffer_s* buffer_new(size_t buffer_size) +{ + struct buffer_s* ret = (struct buffer_s*) malloc(sizeof(struct buffer_s)); + if (ret == nullptr) + { + return nullptr; + } + + ret->data_len = 0; + ret->read_pos = 0; + ret->write_pos = 0; + ret->data = (char*) malloc(sizeof(char) * buffer_size); + + if (ret->data != nullptr) + { + ret->data_len = buffer_size; + } + else + { + buffer_delete(ret); + ret = nullptr; + } + + return ret; +} + +static size_t buffer_getreadvalidcount(struct buffer_s* self) +{ + return self->write_pos - self->read_pos; +} + +static void buffer_adjustto_head(struct buffer_s* self) +{ + if (self->read_pos == 0) + { + return; + } + + const auto len = buffer_getreadvalidcount(self); + if (len > 0) + { + memmove(self->data, self->data + self->read_pos, len); + } + + self->read_pos = 0; + self->write_pos = len; +} + +static void buffer_init(struct buffer_s* self) +{ + self->read_pos = 0; + self->write_pos = 0; +} + +static size_t buffer_getwritepos(struct buffer_s* self) +{ + return self->write_pos; +} + +static size_t buffer_getreadpos(struct buffer_s* self) +{ + return self->read_pos; +} + +static bool buffer_addwritepos(struct buffer_s* self, size_t value) +{ + const size_t temp = self->write_pos + value; + if (temp <= self->data_len) + { + self->write_pos = temp; + return true; + } + else + { + return false; + } +} + +static bool buffer_addreadpos(struct buffer_s* self, size_t value) +{ + const size_t temp = self->read_pos + value; + if (temp <= self->data_len) + { + self->read_pos = temp; + return true; + } + else + { + return false; + } +} + +static size_t buffer_getwritevalidcount(struct buffer_s* self) +{ + return self->data_len - self->write_pos; +} + +static size_t buffer_getsize(struct buffer_s* self) +{ + return self->data_len; +} + +static char* buffer_getwriteptr(struct buffer_s* self) +{ + if (self->write_pos < self->data_len) + { + return self->data + self->write_pos; + } + else + { + return nullptr; + } +} + +static char* buffer_getreadptr(struct buffer_s* self) +{ + if (self->read_pos < self->data_len) + { + return self->data + self->read_pos; + } + else + { + return nullptr; + } +} + +static bool buffer_write(struct buffer_s* self, const char* data, size_t len) +{ + bool write_ret = true; + + if (buffer_getwritevalidcount(self) >= len) + { + memcpy(buffer_getwriteptr(self), data, len); + buffer_addwritepos(self, len); + } + else + { + size_t left_len = self->data_len - buffer_getreadvalidcount(self); + if (left_len >= len) { - ret->data_len = buffer_size; + buffer_adjustto_head(self); + buffer_write(self, data, len); } else { - buffer_delete(ret); - ret = nullptr; - } - - return ret; - } - - static size_t buffer_getreadvalidcount(struct buffer_s* self) - { - return self->write_pos - self->read_pos; - } - - static void buffer_adjustto_head(struct buffer_s* self) - { - if (self->read_pos == 0) - { - return; - } - - const auto len = buffer_getreadvalidcount(self); - if (len > 0) - { - memmove(self->data, self->data + self->read_pos, len); - } - - self->read_pos = 0; - self->write_pos = len; - } - - static void buffer_init(struct buffer_s* self) - { - self->read_pos = 0; - self->write_pos = 0; - } - - static size_t buffer_getwritepos(struct buffer_s* self) - { - return self->write_pos; - } - - static size_t buffer_getreadpos(struct buffer_s* self) - { - return self->read_pos; - } - - static bool buffer_addwritepos(struct buffer_s* self, size_t value) - { - const size_t temp = self->write_pos + value; - if (temp <= self->data_len) - { - self->write_pos = temp; - return true; - } - else - { - return false; + write_ret = false; } } - static bool buffer_addreadpos(struct buffer_s* self, size_t value) - { - const size_t temp = self->read_pos + value; - if (temp <= self->data_len) - { - self->read_pos = temp; - return true; - } - else - { - return false; - } - } + return write_ret; +} - static size_t buffer_getwritevalidcount(struct buffer_s* self) - { - return self->data_len - self->write_pos; - } - - static size_t buffer_getsize(struct buffer_s* self) - { - return self->data_len; - } - - static char* buffer_getwriteptr(struct buffer_s* self) - { - if (self->write_pos < self->data_len) - { - return self->data + self->write_pos; - } - else - { - return nullptr; - } - } - - static char* buffer_getreadptr(struct buffer_s* self) - { - if (self->read_pos < self->data_len) - { - return self->data + self->read_pos; - } - else - { - return nullptr; - } - } - - static bool buffer_write(struct buffer_s* self, const char* data, size_t len) - { - bool write_ret = true; - - if (buffer_getwritevalidcount(self) >= len) - { - /* 直接写入 */ - memcpy(buffer_getwriteptr(self), data, len); - buffer_addwritepos(self, len); - } - else - { - size_t left_len = self->data_len - buffer_getreadvalidcount(self); - if (left_len >= len) - { - buffer_adjustto_head(self); - buffer_write(self, data, len); - } - else - { - write_ret = false; - } - } - - return write_ret; - } - -} } \ No newline at end of file +}}// namespace brynet::base diff --git a/libs/brynet/base/CPP_VERSION.hpp b/libs/brynet/base/CPP_VERSION.hpp index fb65c91..2047b2d 100644 --- a/libs/brynet/base/CPP_VERSION.hpp +++ b/libs/brynet/base/CPP_VERSION.hpp @@ -13,4 +13,4 @@ #if (__cplusplus >= 201703L || \ (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) #define BRYNET_HAVE_LANG_CXX17 1 -#endif \ No newline at end of file +#endif diff --git a/libs/brynet/base/NonCopyable.hpp b/libs/brynet/base/NonCopyable.hpp index 5de4493..62a14e0 100644 --- a/libs/brynet/base/NonCopyable.hpp +++ b/libs/brynet/base/NonCopyable.hpp @@ -2,15 +2,15 @@ namespace brynet { namespace base { - class NonCopyable - { - public: - NonCopyable(const NonCopyable&) = delete; - const NonCopyable& operator=(const NonCopyable&) = delete; +class NonCopyable +{ +public: + NonCopyable(const NonCopyable&) = delete; + const NonCopyable& operator=(const NonCopyable&) = delete; - protected: - NonCopyable() = default; - ~NonCopyable() = default; - }; +protected: + NonCopyable() = default; + ~NonCopyable() = default; +}; -} } \ No newline at end of file +}}// namespace brynet::base diff --git a/libs/brynet/base/Packet.hpp b/libs/brynet/base/Packet.hpp index 8cd451d..72b1773 100644 --- a/libs/brynet/base/Packet.hpp +++ b/libs/brynet/base/Packet.hpp @@ -1,435 +1,432 @@ #pragma once -#include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include namespace brynet { namespace base { - class BasePacketWriter : public NonCopyable +class BasePacketWriter : public NonCopyable +{ +public: + BasePacketWriter(char* buffer, + size_t len, + bool useBigEndian = false, + bool isAutoMalloc = false) + : mIsAutoMalloc(isAutoMalloc), + mBigEndian(useBigEndian) { - public: - BasePacketWriter(char* buffer, - size_t len, - bool useBigEndian = false, - bool isAutoMalloc = false) - : - mIsAutoMalloc(isAutoMalloc), - mBigEndian(useBigEndian) + mMaxLen = len; + mPos = 0; + mBuffer = buffer; + mMallocBuffer = nullptr; + } + + virtual ~BasePacketWriter() + { + if (mMallocBuffer != nullptr) { - mMaxLen = len; - mPos = 0; - mBuffer = buffer; + free(mMallocBuffer); + mMallocBuffer = nullptr; + } + } + + void init() + { + mPos = 0; + } + + size_t getMaxLen() const + { + return mMaxLen; + } + + size_t getPos() const + { + return mPos; + } + + const char* getData() const + { + return mBuffer; + } + + bool isAutoGrow() const + { + return mIsAutoMalloc; + } + + bool writeBool(bool value) + { + static_assert(sizeof(bool) == sizeof(int8_t), ""); + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeINT8(int8_t value) + { + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeUINT8(uint8_t value) + { + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeINT16(int16_t value) + { + value = endian::hostToNetwork16(value, mBigEndian); + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeUINT16(uint16_t value) + { + value = endian::hostToNetwork16(value, mBigEndian); + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeINT32(int32_t value) + { + value = endian::hostToNetwork32(value, mBigEndian); + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeUINT32(uint32_t value) + { + value = endian::hostToNetwork32(value, mBigEndian); + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeINT64(int64_t value) + { + value = endian::hostToNetwork64(value, mBigEndian); + return writeBuffer((char*) &value, sizeof(value)); + } + bool writeUINT64(uint64_t value) + { + value = endian::hostToNetwork64(value, mBigEndian); + return writeBuffer((char*) &value, sizeof(value)); + } + + bool writeBinary(const std::string& binary) + { + return writeBuffer(binary.c_str(), binary.size()); + } + bool writeBinary(const char* binary, size_t binaryLen) + { + return writeBuffer(binary, binaryLen); + } + bool writeBuffer(const char* buffer, size_t len) + { + growBuffer(len); + + if (mMaxLen < (mPos + len)) + { + return false; + } + + memcpy(mBuffer + mPos, buffer, len); + mPos += len; + return true; + } + + BasePacketWriter& operator<<(const bool& v) + { + writeBool(v); + return *this; + } + BasePacketWriter& operator<<(const uint8_t& v) + { + writeUINT8(v); + return *this; + } + BasePacketWriter& operator<<(const int8_t& v) + { + writeINT8(v); + return *this; + } + BasePacketWriter& operator<<(const int16_t& v) + { + writeINT16(v); + return *this; + } + BasePacketWriter& operator<<(const uint16_t& v) + { + writeUINT16(v); + return *this; + } + BasePacketWriter& operator<<(const int32_t& v) + { + writeINT32(v); + return *this; + } + BasePacketWriter& operator<<(const uint32_t& v) + { + writeUINT32(v); + return *this; + } + BasePacketWriter& operator<<(const int64_t& v) + { + writeINT64(v); + return *this; + } + BasePacketWriter& operator<<(const uint64_t& v) + { + writeUINT64(v); + return *this; + } + BasePacketWriter& operator<<(const char* const& v) + { + writeBinary(v); + return *this; + } + BasePacketWriter& operator<<(const std::string& v) + { + writeBinary(v); + return *this; + } + +private: + // 涓轰簡閬垮厤鐩存帴<<瀵艰嚧娌℃湁鎸囧畾瀛楄妭搴忓鑷撮殣钘廈UG,鍥犱负姝ゅ嚱鏁拌缃负绉佹湁 + template + BasePacketWriter& operator<<(const T& v) + { + static_assert(!std::is_pointer::value, "T must is't a pointer"); + static_assert(std::is_class::value, "T must a class or struct type"); + static_assert(std::is_pod::value, "T must a pod type"); + writeBuffer((const char*) &v, sizeof(v)); + return *this; + } + + template + void writev(const Arg1& arg1, const Args&... args) + { + this->operator<<(arg1); + writev(args...); + } + + void writev() + { + } + +protected: + void growBuffer(size_t len) + { + if (!mIsAutoMalloc || (mPos + len) <= mMaxLen) + { + return; + } + + auto newBuffer = (char*) malloc(mMaxLen + len); + if (newBuffer == nullptr) + { + return; + } + + memcpy(newBuffer, mBuffer, mPos); + + if (mMallocBuffer != nullptr) + { + free(mMallocBuffer); mMallocBuffer = nullptr; } - virtual ~BasePacketWriter() - { - if (mMallocBuffer != nullptr) - { - free(mMallocBuffer); - mMallocBuffer = nullptr; - } - } + mMaxLen += len; + mMallocBuffer = newBuffer; + mBuffer = newBuffer; + } - void init() - { - mPos = 0; - } +protected: + const bool mIsAutoMalloc; + bool mBigEndian; + size_t mPos; + size_t mMaxLen; + char* mBuffer; + char* mMallocBuffer; +}; - size_t getMaxLen() const - { - return mMaxLen; - } - - size_t getPos() const - { - return mPos; - } - - const char* getData() const - { - return mBuffer; - } - - bool isAutoGrow() const - { - return mIsAutoMalloc; - } - - bool writeBool(bool value) - { - static_assert(sizeof(bool) == sizeof(int8_t), ""); - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeINT8(int8_t value) - { - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeUINT8(uint8_t value) - { - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeINT16(int16_t value) - { - value = endian::hostToNetwork16(value, mBigEndian); - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeUINT16(uint16_t value) - { - value = endian::hostToNetwork16(value, mBigEndian); - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeINT32(int32_t value) - { - value = endian::hostToNetwork32(value, mBigEndian); - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeUINT32(uint32_t value) - { - value = endian::hostToNetwork32(value, mBigEndian); - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeINT64(int64_t value) - { - value = endian::hostToNetwork64(value, mBigEndian); - return writeBuffer((char*)&value, sizeof(value)); - } - bool writeUINT64(uint64_t value) - { - value = endian::hostToNetwork64(value, mBigEndian); - return writeBuffer((char*)&value, sizeof(value)); - } - - bool writeBinary(const std::string& binary) - { - return writeBuffer(binary.c_str(), binary.size()); - } - bool writeBinary(const char* binary, size_t binaryLen) - { - return writeBuffer(binary, binaryLen); - } - bool writeBuffer(const char* buffer, size_t len) - { - growBuffer(len); - - if (mMaxLen < (mPos + len)) - { - return false; - } - - memcpy(mBuffer + mPos, buffer, len); - mPos += len; - return true; - } - - BasePacketWriter & operator << (const bool &v) - { - writeBool(v); - return *this; - } - BasePacketWriter & operator << (const uint8_t &v) - { - writeUINT8(v); - return *this; - } - BasePacketWriter & operator << (const int8_t &v) - { - writeINT8(v); - return *this; - } - BasePacketWriter & operator << (const int16_t &v) - { - writeINT16(v); - return *this; - } - BasePacketWriter & operator << (const uint16_t &v) - { - writeUINT16(v); - return *this; - } - BasePacketWriter & operator << (const int32_t &v) - { - writeINT32(v); - return *this; - } - BasePacketWriter & operator << (const uint32_t &v) - { - writeUINT32(v); - return *this; - } - BasePacketWriter & operator << (const int64_t &v) - { - writeINT64(v); - return *this; - } - BasePacketWriter & operator << (const uint64_t &v) - { - writeUINT64(v); - return *this; - } - BasePacketWriter & operator << (const char* const &v) - { - writeBinary(v); - return *this; - } - BasePacketWriter & operator << (const std::string &v) - { - writeBinary(v); - return *this; - } - - private: - // 涓轰簡閬垮厤鐩存帴<<瀵艰嚧娌℃湁鎸囧畾瀛楄妭搴忓鑷撮殣钘廈UG,鍥犱负姝ゅ嚱鏁拌缃负绉佹湁 - template - BasePacketWriter & operator << (const T& v) - { - static_assert(!std::is_pointer::value, "T must is't a pointer"); - static_assert(std::is_class ::value, "T must a class or struct type"); - static_assert(std::is_pod ::value, "T must a pod type"); - writeBuffer((const char*)&v, sizeof(v)); - return *this; - } - - template - void writev(const Arg1& arg1, const Args&... args) - { - this->operator<<(arg1); - writev(args...); - } - - void writev() - { - } - - protected: - void growBuffer(size_t len) - { - if (!mIsAutoMalloc || (mPos + len) <= mMaxLen) - { - return; - } - - auto newBuffer = (char*)malloc(mMaxLen + len); - if (newBuffer == nullptr) - { - return; - } - - memcpy(newBuffer, mBuffer, mPos); - - if (mMallocBuffer != nullptr) - { - free(mMallocBuffer); - mMallocBuffer = nullptr; - } - - mMaxLen += len; - mMallocBuffer = newBuffer; - mBuffer = newBuffer; - } - - protected: - const bool mIsAutoMalloc; - bool mBigEndian; - size_t mPos; - size_t mMaxLen; - char* mBuffer; - char* mMallocBuffer; - }; - - class BasePacketReader +class BasePacketReader +{ +public: + BasePacketReader(const char* buffer, + size_t len, + bool useBigEndian = false) + : mBigEndian(useBigEndian), + mSize(len) { - public: - BasePacketReader(const char* buffer, - size_t len, - bool useBigEndian = false) : - mBigEndian(useBigEndian), - mSize(len) - { - mPos = 0; - mSavedPos = 0; - mBuffer = buffer; - } + mPos = 0; + mSavedPos = 0; + mBuffer = buffer; + } - virtual ~BasePacketReader() = default; + virtual ~BasePacketReader() = default; - void useBigEndian() - { - mBigEndian = true; - } - - void useLittleEndian() - { - mBigEndian = false; - } - - void savePos() - { - mSavedPos = mPos; - } - - size_t savedPos() const - { - return mSavedPos; - } - - size_t getLeft() const - { - if (mPos > mSize) - { - throw std::out_of_range("current pos is greater than max len"); - } - return mSize - mPos; - } - - bool enough(size_t len) const - { - if (mPos > mSize) - { - return false; - } - return (mSize - mPos) >= len; - } - - const char* begin() const - { - return mBuffer; - } - - const char* currentBuffer() const - { - return mBuffer+mPos; - } - - void consumeAll() - { - mPos = mSize; - savePos(); - } - - size_t currentPos() const - { - return mPos; - } - - size_t size() const - { - return mSize; - } - - void addPos(size_t diff) - { - const auto tmpPos = mPos + diff; - if (tmpPos > mSize) - { - throw std::out_of_range("diff is to big"); - } - - mPos = tmpPos; - } - - bool readBool() - { - static_assert(sizeof(bool) == sizeof(int8_t), ""); - bool value = false; - read(value); - return value; - } - int8_t readINT8() - { - int8_t value = 0; - read(value); - return value; - } - uint8_t readUINT8() - { - uint8_t value = 0; - read(value); - return value; - } - int16_t readINT16() - { - int16_t value = 0; - read(value); - return endian::networkToHost16(value, mBigEndian); - } - uint16_t readUINT16() - { - uint16_t value = 0; - read(value); - return endian::networkToHost16(value, mBigEndian); - } - int32_t readINT32() - { - int32_t value = 0; - read(value); - return endian::networkToHost32(value, mBigEndian); - } - uint32_t readUINT32() - { - uint32_t value = 0; - read(value); - return endian::networkToHost32(value, mBigEndian); - } - int64_t readINT64() - { - int64_t value = 0; - read(value); - return endian::networkToHost64(value, mBigEndian); - } - uint64_t readUINT64() - { - uint64_t value = 0; - read(value); - return endian::networkToHost64(value, mBigEndian); - } - - private: - // 涓轰簡閬垮厤鐩存帴read(uintXXX)瀵艰嚧娌℃湁鎸囧畾瀛楄妭搴忛犳垚闅愭偅BUG,鍥犱负姝ゅ嚱鏁拌缃负绉佹湁 - template - void read(T& value) - { - static_assert(std::is_same::type>::value, - "T must a normal type"); - static_assert(std::is_pod::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 - class AutoMallocPacket : public BasePacketWriter + void useBigEndian() { - public: - explicit AutoMallocPacket(bool useBigEndian = false, - bool isAutoMalloc = false) - : - BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc) - {} - private: - char mData[SIZE]; - }; + mBigEndian = true; + } - using BigPacket = AutoMallocPacket<32 * 1024>; + void useLittleEndian() + { + mBigEndian = false; + } -} } \ No newline at end of file + void savePos() + { + mSavedPos = mPos; + } + + size_t savedPos() const + { + return mSavedPos; + } + + size_t getLeft() const + { + if (mPos > mSize) + { + throw std::out_of_range("current pos is greater than max len"); + } + return mSize - mPos; + } + + bool enough(size_t len) const + { + if (mPos > mSize) + { + return false; + } + return (mSize - mPos) >= len; + } + + const char* begin() const + { + return mBuffer; + } + + const char* currentBuffer() const + { + return mBuffer + mPos; + } + + void consumeAll() + { + mPos = mSize; + savePos(); + } + + size_t currentPos() const + { + return mPos; + } + + size_t size() const + { + return mSize; + } + + void addPos(size_t diff) + { + const auto tmpPos = mPos + diff; + if (tmpPos > mSize) + { + throw std::out_of_range("diff is to big"); + } + + mPos = tmpPos; + } + + bool readBool() + { + static_assert(sizeof(bool) == sizeof(int8_t), ""); + bool value = false; + read(value); + return value; + } + int8_t readINT8() + { + int8_t value = 0; + read(value); + return value; + } + uint8_t readUINT8() + { + uint8_t value = 0; + read(value); + return value; + } + int16_t readINT16() + { + int16_t value = 0; + read(value); + return endian::networkToHost16(value, mBigEndian); + } + uint16_t readUINT16() + { + uint16_t value = 0; + read(value); + return endian::networkToHost16(value, mBigEndian); + } + int32_t readINT32() + { + int32_t value = 0; + read(value); + return endian::networkToHost32(value, mBigEndian); + } + uint32_t readUINT32() + { + uint32_t value = 0; + read(value); + return endian::networkToHost32(value, mBigEndian); + } + int64_t readINT64() + { + int64_t value = 0; + read(value); + return endian::networkToHost64(value, mBigEndian); + } + uint64_t readUINT64() + { + uint64_t value = 0; + read(value); + return endian::networkToHost64(value, mBigEndian); + } + +private: + // 涓轰簡閬垮厤鐩存帴read(uintXXX)瀵艰嚧娌℃湁鎸囧畾瀛楄妭搴忛犳垚闅愭偅BUG,鍥犱负姝ゅ嚱鏁拌缃负绉佹湁 + template + void read(T& value) + { + static_assert(std::is_same::type>::value, + "T must a normal type"); + static_assert(std::is_pod::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 +class AutoMallocPacket : public BasePacketWriter +{ +public: + explicit AutoMallocPacket(bool useBigEndian = false, + bool isAutoMalloc = false) + : BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc) + {} + +private: + char mData[SIZE]; +}; + +using BigPacket = AutoMallocPacket<32 * 1024>; + +}}// namespace brynet::base diff --git a/libs/brynet/base/Stack.hpp b/libs/brynet/base/Stack.hpp index 339bad3..494be22 100644 --- a/libs/brynet/base/Stack.hpp +++ b/libs/brynet/base/Stack.hpp @@ -1,175 +1,169 @@ #pragma once -#include -#include -#include -#include -#include - #include +#include namespace brynet { namespace base { - struct stack_s - { - struct array_s* array; - size_t element_size; +struct stack_s +{ + struct array_s* array; + size_t element_size; - size_t element_num; - size_t front; /* 栈底 */ - size_t num; /* 栈有效元素大小 */ - }; + size_t element_num; + size_t front; + size_t num; +}; - static void stack_delete(struct stack_s* self) +static void stack_delete(struct stack_s* self) +{ + if (self == nullptr) { - if (self == nullptr) + return; + } + + if (self->array != nullptr) + { + array_delete(self->array); + self->array = nullptr; + } + + self->element_num = 0; + self->front = 0; + self->num = 0; + free(self); + self = nullptr; +} + +static struct stack_s* stack_new(size_t num, size_t element_size) +{ + struct stack_s* ret = (struct stack_s*) malloc(sizeof(struct stack_s)); + if (ret == nullptr) + { + return nullptr; + } + + ret->element_size = 0; + ret->element_num = 0; + ret->front = 0; + ret->num = 0; + ret->array = array_new(num, element_size); + + if (ret->array != nullptr) + { + ret->element_size = element_size; + ret->element_num = num; + } + else + { + stack_delete(ret); + ret = nullptr; + } + + return ret; +} + +static void stack_init(struct stack_s* self) +{ + self->front = 0; + self->num = 0; +} + +static size_t stack_num(struct stack_s* self) +{ + return self->num; +} + +static bool stack_increase(struct stack_s* self, size_t increase_num) +{ + struct array_s* tmp = array_new(self->element_num + increase_num, + self->element_size); + if (tmp == nullptr) + { + return false; + } + + { + size_t current_num = self->element_num; + size_t current_stack_num = stack_num(self); + for (size_t i = 0; i < current_stack_num; ++i) { - return; + array_set(tmp, i, array_at(self->array, (self->front + i) % current_num)); } - if (self->array != nullptr) - { - array_delete(self->array); - self->array = nullptr; - } - - self->element_num = 0; self->front = 0; - self->num = 0; - free(self); - self = nullptr; + array_delete(self->array); + self->array = tmp; + self->element_num = array_num(self->array); } - static struct stack_s* stack_new(size_t num, size_t element_size) + return true; +} + +static size_t stack_size(struct stack_s* self) +{ + return self->element_num; +} + +static bool stack_isfull(struct stack_s* self) +{ + return (self->num == self->element_num); +} + +static bool stack_push(struct stack_s* self, const void* data) +{ + if (stack_isfull(self)) { - struct stack_s* ret = (struct stack_s*)malloc(sizeof(struct stack_s)); - if (ret == nullptr) - { - return nullptr; - } - - ret->element_size = 0; - ret->element_num = 0; - ret->front = 0; - ret->num = 0; - ret->array = array_new(num, element_size); - - if (ret->array != nullptr) - { - ret->element_size = element_size; - ret->element_num = num; - } - else - { - stack_delete(ret); - ret = nullptr; - } - - return ret; + stack_increase(self, stack_size(self)); } - static void stack_init(struct stack_s* self) + if (stack_isfull(self)) { - self->front = 0; - self->num = 0; + return false; } - static size_t stack_num(struct stack_s* self) + array_set(self->array, (self->front + self->num) % self->element_num, data); + self->num++; + return true; +} + +static void* stack_front(struct stack_s* self) +{ + void* ret = nullptr; + + if (stack_num(self) > 0) { - return self->num; + ret = array_at(self->array, self->front); } - static bool stack_increase(struct stack_s* self, size_t increase_num) + return ret; +} + +static void* stack_popfront(struct stack_s* self) +{ + void* ret = stack_front(self); + + if (ret != nullptr) { - struct array_s* tmp = array_new(self->element_num + increase_num, - self->element_size); - if (tmp == nullptr) - { - return false; - } - - { - size_t current_num = self->element_num; - size_t current_stack_num = stack_num(self); - for (size_t i = 0; i < current_stack_num; ++i) - { - array_set(tmp, i, array_at(self->array, (self->front + i) % current_num)); - } - - self->front = 0; - array_delete(self->array); - self->array = tmp; - self->element_num = array_num(self->array); - } - - return true; + self->num--; + self->front++; + self->front %= self->element_num; } - static size_t stack_size(struct stack_s* self) + return ret; +} + +static void* stack_popback(struct stack_s* self) +{ + void* ret = nullptr; + + if (stack_num(self) > 0) { - return self->element_num; + self->num--; + ret = array_at(self->array, (self->front + self->num) % self->element_num); } - static bool stack_isfull(struct stack_s* self) - { - return (self->num == self->element_num); - } - - /* stack的stack_push会在空间不足的时候自动增长(通过stack_increase) */ - static bool stack_push(struct stack_s* self, const void* data) - { - if (stack_isfull(self)) - { - stack_increase(self, stack_size(self)); - } + return ret; +} - if (stack_isfull(self)) - { - return false; - } - - array_set(self->array, (self->front + self->num) % self->element_num, data); - self->num++; - return true; - } - - static void* stack_front(struct stack_s* self) - { - void* ret = nullptr; - - if (stack_num(self) > 0) - { - ret = array_at(self->array, self->front); - } - - return ret; - } - - static void* stack_popfront(struct stack_s* self) - { - void* ret = stack_front(self); - - if (ret != nullptr) - { - self->num--; - self->front++; - self->front %= self->element_num; - } - - return ret; - } - - static void* stack_popback(struct stack_s* self) - { - void* ret = nullptr; - - if (stack_num(self) > 0) - { - self->num--; - ret = array_at(self->array, (self->front + self->num) % self->element_num); - } - - return ret; - } - -} } +}}// namespace brynet::base diff --git a/libs/brynet/base/Timer.hpp b/libs/brynet/base/Timer.hpp index 363d48e..4876794 100644 --- a/libs/brynet/base/Timer.hpp +++ b/libs/brynet/base/Timer.hpp @@ -1,167 +1,165 @@ #pragma once -#include -#include -#include -#include -#include -#include - #include +#include +#include +#include +#include +#include +#include namespace brynet { namespace base { - class TimerMgr; +class TimerMgr; - class Timer final +class Timer final +{ +public: + using Ptr = std::shared_ptr; + using WeakPtr = std::weak_ptr; + using Callback = std::function; + + Timer(std::chrono::steady_clock::time_point startTime, + std::chrono::nanoseconds lastTime, + Callback&& callback) BRYNET_NOEXCEPT + : mCallback(std::move(callback)), + mStartTime(startTime), + mLastTime(lastTime) { - public: - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - using Callback = std::function; + } - Timer(std::chrono::steady_clock::time_point startTime, - std::chrono::nanoseconds lastTime, - Callback&& callback) BRYNET_NOEXCEPT - : - mCallback(std::move(callback)), - mStartTime(startTime), - mLastTime(lastTime) - { - } - - const std::chrono::steady_clock::time_point& getStartTime() const - { - return mStartTime; - } - - const std::chrono::nanoseconds& getLastTime() const - { - return mLastTime; - } - - std::chrono::nanoseconds getLeftTime() const - { - const auto now = std::chrono::steady_clock::now(); - return getLastTime() - (now - getStartTime()); - } - - void cancel() - { - std::call_once(mExecuteOnceFlag, [this]() { - mCallback = nullptr; - }); - } - - private: - void operator() () - { - Callback callback; - std::call_once(mExecuteOnceFlag, [&callback, this]() { - callback = std::move(mCallback); - mCallback = nullptr; - }); - - if (callback != nullptr) - { - callback(); - } - } - - private: - std::once_flag mExecuteOnceFlag; - Callback mCallback; - const std::chrono::steady_clock::time_point mStartTime; - const std::chrono::nanoseconds mLastTime; - - friend class TimerMgr; - }; - - class TimerMgr final + const std::chrono::steady_clock::time_point& getStartTime() const { - public: - using Ptr = std::shared_ptr; + return mStartTime; + } - template - Timer::WeakPtr addTimer( + const std::chrono::nanoseconds& getLastTime() const + { + return mLastTime; + } + + std::chrono::nanoseconds getLeftTime() const + { + const auto now = std::chrono::steady_clock::now(); + return getLastTime() - (now - getStartTime()); + } + + void cancel() + { + std::call_once(mExecuteOnceFlag, [this]() { + mCallback = nullptr; + }); + } + +private: + void operator()() + { + Callback callback; + std::call_once(mExecuteOnceFlag, [&callback, this]() { + callback = std::move(mCallback); + mCallback = nullptr; + }); + + if (callback != nullptr) + { + callback(); + } + } + +private: + std::once_flag mExecuteOnceFlag; + Callback mCallback; + const std::chrono::steady_clock::time_point mStartTime; + const std::chrono::nanoseconds mLastTime; + + friend class TimerMgr; +}; + +class TimerMgr final +{ +public: + using Ptr = std::shared_ptr; + + template + Timer::WeakPtr addTimer( std::chrono::nanoseconds timeout, - F&& callback, - TArgs&& ...args) - { - auto timer = std::make_shared( + F&& callback, + TArgs&&... args) + { + auto timer = std::make_shared( std::chrono::steady_clock::now(), std::chrono::nanoseconds(timeout), std::bind(std::forward(callback), std::forward(args)...)); - mTimers.push(timer); + mTimers.push(timer); - return timer; - } + return timer; + } - void addTimer(const Timer::Ptr& timer) + void addTimer(const Timer::Ptr& timer) + { + mTimers.push(timer); + } + + void schedule() + { + while (!mTimers.empty()) { - mTimers.push(timer); - } - - void schedule() - { - while (!mTimers.empty()) + auto tmp = mTimers.top(); + if (tmp->getLeftTime() > std::chrono::nanoseconds::zero()) { - auto tmp = mTimers.top(); - if (tmp->getLeftTime() > std::chrono::nanoseconds::zero()) - { - break; - } - - mTimers.pop(); - (*tmp)(); - } - } - - bool isEmpty() const - { - return mTimers.empty(); - } - - // if timer empty, return zero - std::chrono::nanoseconds nearLeftTime() const - { - if (mTimers.empty()) - { - return std::chrono::nanoseconds::zero(); + break; } - auto result = mTimers.top()->getLeftTime(); - if (result < std::chrono::nanoseconds::zero()) - { - return std::chrono::nanoseconds::zero(); - } + mTimers.pop(); + (*tmp)(); + } + } - return result; + bool isEmpty() const + { + return mTimers.empty(); + } + + // if timer empty, return zero + std::chrono::nanoseconds nearLeftTime() const + { + if (mTimers.empty()) + { + return std::chrono::nanoseconds::zero(); } - void clear() + auto result = mTimers.top()->getLeftTime(); + if (result < std::chrono::nanoseconds::zero()) { - while (!mTimers.empty()) - { - mTimers.pop(); - } + return std::chrono::nanoseconds::zero(); } - private: - class CompareTimer - { - public: - bool operator() (const Timer::Ptr& left, - const Timer::Ptr& right) const - { - const auto startDiff = left->getStartTime() - right->getStartTime(); - const auto lastDiff = left->getLastTime() - right->getLastTime(); - const auto diff = startDiff.count() + lastDiff.count(); - return diff > 0; - } - }; + return result; + } - std::priority_queue, CompareTimer> mTimers; + void clear() + { + while (!mTimers.empty()) + { + mTimers.pop(); + } + } + +private: + class CompareTimer + { + public: + bool operator()(const Timer::Ptr& left, + const Timer::Ptr& right) const + { + const auto startDiff = left->getStartTime() - right->getStartTime(); + const auto lastDiff = left->getLastTime() - right->getLastTime(); + const auto diff = startDiff.count() + lastDiff.count(); + return diff > 0; + } }; -} } \ No newline at end of file + std::priority_queue, CompareTimer> mTimers; +}; + +}}// namespace brynet::base diff --git a/libs/brynet/base/WaitGroup.hpp b/libs/brynet/base/WaitGroup.hpp index 1d44fcc..f640246 100644 --- a/libs/brynet/base/WaitGroup.hpp +++ b/libs/brynet/base/WaitGroup.hpp @@ -1,65 +1,67 @@ #pragma once -#include #include -#include -#include -#include - #include +#include +#include +#include +#include namespace brynet { namespace base { - class WaitGroup : public NonCopyable +class WaitGroup : public NonCopyable +{ +public: + typedef std::shared_ptr Ptr; + + static Ptr Create() { - public: - typedef std::shared_ptr Ptr; - - static Ptr Create() + struct make_shared_enabler : public WaitGroup { - struct make_shared_enabler : public WaitGroup {}; - return std::make_shared(); - } + }; + return std::make_shared(); + } - public: - void add(int i = 1) - { - mCounter += i; - } +public: + void add(int i = 1) + { + mCounter += i; + } - void done() - { - mCounter--; - mCond.notify_all(); - } + void done() + { + mCounter--; + mCond.notify_all(); + } - void wait() - { - std::unique_lock l(mMutex); - mCond.wait(l, [&] { return mCounter <= 0; }); - } + void wait() + { + std::unique_lock l(mMutex); + mCond.wait(l, [&] { + return mCounter <= 0; + }); + } - template - void wait(const std::chrono::duration& timeout) - { - std::unique_lock l(mMutex); - mCond.wait_for(l, timeout, [&] { - return mCounter <= 0; - }); - } + template + void wait(const std::chrono::duration& timeout) + { + std::unique_lock l(mMutex); + mCond.wait_for(l, timeout, [&] { + return mCounter <= 0; + }); + } - private: - WaitGroup() - : - mCounter(0) - { - } +private: + WaitGroup() + : mCounter(0) + { + } - virtual ~WaitGroup() = default; + virtual ~WaitGroup() = default; - private: - std::mutex mMutex; - std::atomic mCounter; - std::condition_variable mCond; - }; -} } \ No newline at end of file +private: + std::mutex mMutex; + std::atomic mCounter; + std::condition_variable mCond; +}; +}}// namespace brynet::base diff --git a/libs/brynet/base/crypto/Base64.hpp b/libs/brynet/base/crypto/Base64.hpp index 135a77e..2cec2e5 100644 --- a/libs/brynet/base/crypto/Base64.hpp +++ b/libs/brynet/base/crypto/Base64.hpp @@ -5,101 +5,106 @@ namespace brynet { namespace base { namespace crypto { - static const std::string base64_chars = +static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; - static bool is_base64(unsigned char c) +static bool is_base64(unsigned char c) +{ + return (isalnum(c) || (c == '+') || (c == '/')); +} + +static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) +{ + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { - return (isalnum(c) || (c == '+') || (c == '/')); - } - - static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) - { - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (i = 0; (i < 4); i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { - for (j = i; j < 3; j++) - char_array_3[j] = '\0'; - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while ((i++ < 3)) - ret += '='; - + for (i = 0; (i < 4); i++) + ret += base64_chars[char_array_4[i]]; + i = 0; } - - return ret; } - static std::string base64_decode(std::string const& encoded_string) + if (i) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; + for (j = i; j < 3; j++) + char_array_3[j] = '\0'; - while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i == 4) { - for (i = 0; i < 4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } + while ((i++ < 3)) + ret += '='; + } - if (i) { - for (j = i; j < 4; j++) - char_array_4[j] = 0; + return ret; +} - for (j = 0; j < 4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); +static std::string base64_decode(std::string const& encoded_string) +{ + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) + { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i == 4) + { + for (i = 0; i < 4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; } - - return ret; } -} } } + if (i) + { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} + +}}}// namespace brynet::base::crypto #endif \ No newline at end of file diff --git a/libs/brynet/base/crypto/SHA1.hpp b/libs/brynet/base/crypto/SHA1.hpp index 197d3cc..06c29f9 100644 --- a/libs/brynet/base/crypto/SHA1.hpp +++ b/libs/brynet/base/crypto/SHA1.hpp @@ -116,8 +116,8 @@ #endif #endif -#include #include +#include #ifdef SHA1_UTILITY_FUNCTIONS #include @@ -174,48 +174,47 @@ // Define variable types #ifndef UINT_8 -#ifdef _MSC_VER // Compiling with Microsoft compiler +#ifdef _MSC_VER// Compiling with Microsoft compiler #define UINT_8 unsigned __int8 -#else // !_MSC_VER +#else// !_MSC_VER #define UINT_8 unsigned char -#endif // _MSC_VER +#endif// _MSC_VER #endif #ifndef UINT_32 -#ifdef _MSC_VER // Compiling with Microsoft compiler +#ifdef _MSC_VER// Compiling with Microsoft compiler #define UINT_32 unsigned __int32 -#else // !_MSC_VER +#else// !_MSC_VER #if (ULONG_MAX == 0xFFFFFFFFUL) #define UINT_32 unsigned long #else #define UINT_32 unsigned int #endif -#endif // _MSC_VER -#endif // UINT_32 +#endif// _MSC_VER +#endif// UINT_32 #ifndef INT_64 -#ifdef _MSC_VER // Compiling with Microsoft compiler +#ifdef _MSC_VER// Compiling with Microsoft compiler #define INT_64 __int64 -#else // !_MSC_VER +#else// !_MSC_VER #define INT_64 long long -#endif // _MSC_VER -#endif // INT_64 +#endif// _MSC_VER +#endif// INT_64 #ifndef UINT_64 -#ifdef _MSC_VER // Compiling with Microsoft compiler +#ifdef _MSC_VER// Compiling with Microsoft compiler #define UINT_64 unsigned __int64 -#else // !_MSC_VER +#else// !_MSC_VER #define UINT_64 unsigned long long -#endif // _MSC_VER -#endif // UINT_64 +#endif// _MSC_VER +#endif// UINT_64 /////////////////////////////////////////////////////////////////////////// // Declare SHA-1 workspace -typedef union -{ - UINT_8 c[64]; - UINT_32 l[16]; +typedef union { + UINT_8 c[64]; + UINT_32 l[16]; } SHA1_WORKSPACE_BLOCK; @@ -224,49 +223,70 @@ typedef union // Rotate p_val32 by p_nBits bits to the left #ifndef ROL32 #ifdef _MSC_VER -#define ROL32(p_val32,p_nBits) _rotl(p_val32,p_nBits) +#define ROL32(p_val32, p_nBits) _rotl(p_val32, p_nBits) #else -#define ROL32(p_val32,p_nBits) (((p_val32)<<(p_nBits))|((p_val32)>>(32-(p_nBits)))) +#define ROL32(p_val32, p_nBits) (((p_val32) << (p_nBits)) | ((p_val32) >> (32 - (p_nBits)))) #endif #endif #ifdef SHA1_LITTLE_ENDIAN #define SHABLK0(i) (m_block->l[i] = \ - (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF)) + (ROL32(m_block->l[i], 24) & 0xFF00FF00) | (ROL32(m_block->l[i], 8) & 0x00FF00FF)) #else #define SHABLK0(i) (m_block->l[i]) #endif -#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ \ - m_block->l[(i+8)&15] ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1)) +#define SHABLK(i) (m_block->l[i & 15] = ROL32(m_block->l[(i + 13) & 15] ^ \ + m_block->l[(i + 8) & 15] ^ m_block->l[(i + 2) & 15] ^ m_block->l[i & 15], \ + 1)) // SHA-1 rounds -#define S_R0(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);} -#define S_R1(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);} -#define S_R2(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5);w=ROL32(w,30);} -#define S_R3(v,w,x,y,z,i) {z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5);w=ROL32(w,30);} -#define S_R4(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5);w=ROL32(w,30);} +#define S_R0(v, w, x, y, z, i) \ + { \ + z += ((w & (x ^ y)) ^ y) + SHABLK0(i) + 0x5A827999 + ROL32(v, 5); \ + w = ROL32(w, 30); \ + } +#define S_R1(v, w, x, y, z, i) \ + { \ + z += ((w & (x ^ y)) ^ y) + SHABLK(i) + 0x5A827999 + ROL32(v, 5); \ + w = ROL32(w, 30); \ + } +#define S_R2(v, w, x, y, z, i) \ + { \ + z += (w ^ x ^ y) + SHABLK(i) + 0x6ED9EBA1 + ROL32(v, 5); \ + w = ROL32(w, 30); \ + } +#define S_R3(v, w, x, y, z, i) \ + { \ + z += (((w | x) & y) | (w & x)) + SHABLK(i) + 0x8F1BBCDC + ROL32(v, 5); \ + w = ROL32(w, 30); \ + } +#define S_R4(v, w, x, y, z, i) \ + { \ + z += (w ^ x ^ y) + SHABLK(i) + 0xCA62C1D6 + ROL32(v, 5); \ + w = ROL32(w, 30); \ + } class CSHA1 { public: #ifdef SHA1_UTILITY_FUNCTIONS - // Different formats for ReportHash(Stl) - enum REPORT_TYPE - { - REPORT_HEX = 0, - REPORT_DIGIT = 1, - REPORT_HEX_SHORT = 2 - }; + // Different formats for ReportHash(Stl) + enum REPORT_TYPE + { + REPORT_HEX = 0, + REPORT_DIGIT = 1, + REPORT_HEX_SHORT = 2 + }; #endif - // Constructor and destructor + // Constructor and destructor CSHA1() { - (void)m_reserved0; - (void)m_reserved1; - m_block = (SHA1_WORKSPACE_BLOCK*)m_workspace; + (void) m_reserved0; + (void) m_reserved1; + m_block = (SHA1_WORKSPACE_BLOCK*) m_workspace; Reset(); } @@ -291,13 +311,13 @@ public: m_count[1] = 0; } - // Hash in binary data and strings + // Hash in binary data and strings void Update(const UINT_8* pbData, UINT_32 uLen) { UINT_32 j = ((m_count[0] >> 3) & 0x3F); if ((m_count[0] += (uLen << 3)) < (uLen << 3)) - ++m_count[1]; // Overflow + ++m_count[1];// Overflow m_count[1] += (uLen >> 29); @@ -313,23 +333,30 @@ public: j = 0; } - else i = 0; + else + i = 0; if ((uLen - i) != 0) memcpy(&m_buffer[j], &pbData[i], uLen - i); } #ifdef SHA1_UTILITY_FUNCTIONS - // Hash in file contents + // Hash in file contents bool HashFile(const TCHAR* tszFileName) { - if (tszFileName == NULL) return false; + if (tszFileName == NULL) + return false; FILE* fpIn = _tfopen(tszFileName, _T("rb")); - if (fpIn == NULL) return false; + if (fpIn == NULL) + return false; UINT_8* pbData = new UINT_8[SHA1_MAX_FILE_BUFFER]; - if (pbData == NULL) { fclose(fpIn); return false; } + if (pbData == NULL) + { + fclose(fpIn); + return false; + } bool bSuccess = true; while (true) @@ -341,7 +368,8 @@ public: if (uRead < SHA1_MAX_FILE_BUFFER) { - if (feof(fpIn) == 0) bSuccess = false; + if (feof(fpIn) == 0) + bSuccess = false; break; } } @@ -352,7 +380,7 @@ public: } #endif - // Finalize hash; call it before using ReportHash(Stl) + // Finalize hash; call it before using ReportHash(Stl) void Final() { UINT_32 i; @@ -360,20 +388,23 @@ public: UINT_8 pbFinalCount[8]; for (i = 0; i < 8; ++i) pbFinalCount[i] = static_cast((m_count[((i >= 4) ? 0 : 1)] >> - ((3 - (i & 3)) * 8)) & 0xFF); // Endian independent + ((3 - (i & 3)) * 8)) & + 0xFF);// Endian independent - Update((UINT_8*)"\200", 1); + Update((UINT_8*) "\200", 1); while ((m_count[0] & 504) != 448) - Update((UINT_8*)"\0", 1); + Update((UINT_8*) "\0", 1); - Update(pbFinalCount, 8); // Cause a Transform() + Update(pbFinalCount, 8);// Cause a Transform() for (i = 0; i < 20; ++i) m_digest[i] = static_cast((m_state[i >> 2] >> ((3 - - (i & 3)) * 8)) & 0xFF); + (i & 3)) * + 8)) & + 0xFF); - // Wipe variables for security reasons + // Wipe variables for security reasons #ifdef SHA1_WIPE_VARIABLES memset(m_buffer, 0, 64); memset(m_state, 0, 20); @@ -386,7 +417,8 @@ public: #ifdef SHA1_UTILITY_FUNCTIONS bool ReportHash(TCHAR* tszReport, REPORT_TYPE rtReportType = REPORT_HEX) const { - if (tszReport == NULL) return false; + if (tszReport == NULL) + return false; TCHAR tszTemp[16]; @@ -413,7 +445,8 @@ public: _tcscat(tszReport, tszTemp); } } - else return false; + else + return false; return true; } @@ -421,25 +454,27 @@ public: #ifdef SHA1_STL_FUNCTIONS bool ReportHashStl(std::basic_string& strOut, REPORT_TYPE rtReportType = - REPORT_HEX) const + REPORT_HEX) const { TCHAR tszOut[84]; const bool bResult = ReportHash(tszOut, rtReportType); - if (bResult) strOut = tszOut; + if (bResult) + strOut = tszOut; return bResult; } #endif - // Get the raw message digest (20 bytes) + // Get the raw message digest (20 bytes) bool GetHash(UINT_8* pbDest20) const { - if (pbDest20 == NULL) return false; + if (pbDest20 == NULL) + return false; memcpy(pbDest20, m_digest, 20); return true; } private: - // Private SHA-1 transformation + // Private SHA-1 transformation void Transform(UINT_32* pState, const UINT_8* pBuffer) { UINT_32 a = pState[0], b = pState[1], c = pState[2], d = pState[3], e = pState[4]; @@ -447,26 +482,86 @@ private: memcpy(m_block, pBuffer, 64); // 4 rounds of 20 operations each, loop unrolled - S_R0(a, b, c, d, e, 0); S_R0(e, a, b, c, d, 1); S_R0(d, e, a, b, c, 2); S_R0(c, d, e, a, b, 3); - S_R0(b, c, d, e, a, 4); S_R0(a, b, c, d, e, 5); S_R0(e, a, b, c, d, 6); S_R0(d, e, a, b, c, 7); - S_R0(c, d, e, a, b, 8); S_R0(b, c, d, e, a, 9); S_R0(a, b, c, d, e, 10); S_R0(e, a, b, c, d, 11); - S_R0(d, e, a, b, c, 12); S_R0(c, d, e, a, b, 13); S_R0(b, c, d, e, a, 14); S_R0(a, b, c, d, e, 15); - S_R1(e, a, b, c, d, 16); S_R1(d, e, a, b, c, 17); S_R1(c, d, e, a, b, 18); S_R1(b, c, d, e, a, 19); - S_R2(a, b, c, d, e, 20); S_R2(e, a, b, c, d, 21); S_R2(d, e, a, b, c, 22); S_R2(c, d, e, a, b, 23); - S_R2(b, c, d, e, a, 24); S_R2(a, b, c, d, e, 25); S_R2(e, a, b, c, d, 26); S_R2(d, e, a, b, c, 27); - S_R2(c, d, e, a, b, 28); S_R2(b, c, d, e, a, 29); S_R2(a, b, c, d, e, 30); S_R2(e, a, b, c, d, 31); - S_R2(d, e, a, b, c, 32); S_R2(c, d, e, a, b, 33); S_R2(b, c, d, e, a, 34); S_R2(a, b, c, d, e, 35); - S_R2(e, a, b, c, d, 36); S_R2(d, e, a, b, c, 37); S_R2(c, d, e, a, b, 38); S_R2(b, c, d, e, a, 39); - S_R3(a, b, c, d, e, 40); S_R3(e, a, b, c, d, 41); S_R3(d, e, a, b, c, 42); S_R3(c, d, e, a, b, 43); - S_R3(b, c, d, e, a, 44); S_R3(a, b, c, d, e, 45); S_R3(e, a, b, c, d, 46); S_R3(d, e, a, b, c, 47); - S_R3(c, d, e, a, b, 48); S_R3(b, c, d, e, a, 49); S_R3(a, b, c, d, e, 50); S_R3(e, a, b, c, d, 51); - S_R3(d, e, a, b, c, 52); S_R3(c, d, e, a, b, 53); S_R3(b, c, d, e, a, 54); S_R3(a, b, c, d, e, 55); - S_R3(e, a, b, c, d, 56); S_R3(d, e, a, b, c, 57); S_R3(c, d, e, a, b, 58); S_R3(b, c, d, e, a, 59); - S_R4(a, b, c, d, e, 60); S_R4(e, a, b, c, d, 61); S_R4(d, e, a, b, c, 62); S_R4(c, d, e, a, b, 63); - S_R4(b, c, d, e, a, 64); S_R4(a, b, c, d, e, 65); S_R4(e, a, b, c, d, 66); S_R4(d, e, a, b, c, 67); - S_R4(c, d, e, a, b, 68); S_R4(b, c, d, e, a, 69); S_R4(a, b, c, d, e, 70); S_R4(e, a, b, c, d, 71); - S_R4(d, e, a, b, c, 72); S_R4(c, d, e, a, b, 73); S_R4(b, c, d, e, a, 74); S_R4(a, b, c, d, e, 75); - S_R4(e, a, b, c, d, 76); S_R4(d, e, a, b, c, 77); S_R4(c, d, e, a, b, 78); S_R4(b, c, d, e, a, 79); + S_R0(a, b, c, d, e, 0); + S_R0(e, a, b, c, d, 1); + S_R0(d, e, a, b, c, 2); + S_R0(c, d, e, a, b, 3); + S_R0(b, c, d, e, a, 4); + S_R0(a, b, c, d, e, 5); + S_R0(e, a, b, c, d, 6); + S_R0(d, e, a, b, c, 7); + S_R0(c, d, e, a, b, 8); + S_R0(b, c, d, e, a, 9); + S_R0(a, b, c, d, e, 10); + S_R0(e, a, b, c, d, 11); + S_R0(d, e, a, b, c, 12); + S_R0(c, d, e, a, b, 13); + S_R0(b, c, d, e, a, 14); + S_R0(a, b, c, d, e, 15); + S_R1(e, a, b, c, d, 16); + S_R1(d, e, a, b, c, 17); + S_R1(c, d, e, a, b, 18); + S_R1(b, c, d, e, a, 19); + S_R2(a, b, c, d, e, 20); + S_R2(e, a, b, c, d, 21); + S_R2(d, e, a, b, c, 22); + S_R2(c, d, e, a, b, 23); + S_R2(b, c, d, e, a, 24); + S_R2(a, b, c, d, e, 25); + S_R2(e, a, b, c, d, 26); + S_R2(d, e, a, b, c, 27); + S_R2(c, d, e, a, b, 28); + S_R2(b, c, d, e, a, 29); + S_R2(a, b, c, d, e, 30); + S_R2(e, a, b, c, d, 31); + S_R2(d, e, a, b, c, 32); + S_R2(c, d, e, a, b, 33); + S_R2(b, c, d, e, a, 34); + S_R2(a, b, c, d, e, 35); + S_R2(e, a, b, c, d, 36); + S_R2(d, e, a, b, c, 37); + S_R2(c, d, e, a, b, 38); + S_R2(b, c, d, e, a, 39); + S_R3(a, b, c, d, e, 40); + S_R3(e, a, b, c, d, 41); + S_R3(d, e, a, b, c, 42); + S_R3(c, d, e, a, b, 43); + S_R3(b, c, d, e, a, 44); + S_R3(a, b, c, d, e, 45); + S_R3(e, a, b, c, d, 46); + S_R3(d, e, a, b, c, 47); + S_R3(c, d, e, a, b, 48); + S_R3(b, c, d, e, a, 49); + S_R3(a, b, c, d, e, 50); + S_R3(e, a, b, c, d, 51); + S_R3(d, e, a, b, c, 52); + S_R3(c, d, e, a, b, 53); + S_R3(b, c, d, e, a, 54); + S_R3(a, b, c, d, e, 55); + S_R3(e, a, b, c, d, 56); + S_R3(d, e, a, b, c, 57); + S_R3(c, d, e, a, b, 58); + S_R3(b, c, d, e, a, 59); + S_R4(a, b, c, d, e, 60); + S_R4(e, a, b, c, d, 61); + S_R4(d, e, a, b, c, 62); + S_R4(c, d, e, a, b, 63); + S_R4(b, c, d, e, a, 64); + S_R4(a, b, c, d, e, 65); + S_R4(e, a, b, c, d, 66); + S_R4(d, e, a, b, c, 67); + S_R4(c, d, e, a, b, 68); + S_R4(b, c, d, e, a, 69); + S_R4(a, b, c, d, e, 70); + S_R4(e, a, b, c, d, 71); + S_R4(d, e, a, b, c, 72); + S_R4(c, d, e, a, b, 73); + S_R4(b, c, d, e, a, 74); + S_R4(a, b, c, d, e, 75); + S_R4(e, a, b, c, d, 76); + S_R4(d, e, a, b, c, 77); + S_R4(c, d, e, a, b, 78); + S_R4(b, c, d, e, a, 79); // Add the working vars back into state pState[0] += a; @@ -481,16 +576,16 @@ private: #endif } - // Member variables - UINT_32 m_state[5]; - UINT_32 m_count[2]; - UINT_32 m_reserved0[1]; // Memory alignment padding - UINT_8 m_buffer[64]; - UINT_8 m_digest[20]; - UINT_32 m_reserved1[3]; // Memory alignment padding + // Member variables + UINT_32 m_state[5]; + UINT_32 m_count[2]; + UINT_32 m_reserved0[1];// Memory alignment padding + UINT_8 m_buffer[64]; + UINT_8 m_digest[20]; + UINT_32 m_reserved1[3];// Memory alignment padding - UINT_8 m_workspace[64]; - SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above + UINT_8 m_workspace[64]; + SHA1_WORKSPACE_BLOCK* m_block;// SHA1 pointer to the byte array above }; -#endif // SHA1_H_A545E61D43E9404E8D736869AB3CBFE7 +#endif// SHA1_H_A545E61D43E9404E8D736869AB3CBFE7 diff --git a/libs/brynet/base/endian/Endian.hpp b/libs/brynet/base/endian/Endian.hpp index c797e83..384352e 100644 --- a/libs/brynet/base/endian/Endian.hpp +++ b/libs/brynet/base/endian/Endian.hpp @@ -1,12 +1,10 @@ #pragma once -#include -#include -#include -#include -#include - #include +#include +#include +#include +#include #ifdef BRYNET_PLATFORM_LINUX #include @@ -16,125 +14,125 @@ namespace brynet { namespace base { namespace endian { - inline uint64_t hl64ton(uint64_t hostValue) - { - uint64_t ret = 0; - uint32_t high, low; +inline uint64_t hl64ton(uint64_t hostValue) +{ + uint64_t ret = 0; + uint32_t high, low; - low = hostValue & 0xFFFFFFFF; - high = (hostValue >> 32) & 0xFFFFFFFF; - low = htonl(low); - high = htonl(high); - ret = low; - ret <<= 32; - ret |= high; + low = hostValue & 0xFFFFFFFF; + high = (hostValue >> 32) & 0xFFFFFFFF; + low = htonl(low); + high = htonl(high); + ret = low; + ret <<= 32; + ret |= high; - return ret; - } + return ret; +} - inline uint64_t ntohl64(uint64_t netValue) - { - uint64_t ret = 0; - uint32_t high, low; +inline uint64_t ntohl64(uint64_t netValue) +{ + uint64_t ret = 0; + uint32_t high, low; - low = netValue & 0xFFFFFFFF; - high = (netValue >> 32) & 0xFFFFFFFF; - low = ntohl(low); - high = ntohl(high); - ret = low; - ret <<= 32; - ret |= high; + low = netValue & 0xFFFFFFFF; + high = (netValue >> 32) & 0xFFFFFFFF; + low = ntohl(low); + high = ntohl(high); + ret = low; + ret <<= 32; + ret |= high; - return ret; - } + return ret; +} #ifdef BRYNET_PLATFORM_WINDOWS - inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true) - { - return convert ? hl64ton(host64) : host64; - } - inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true) - { - return convert ? htonl(host32) : host32; - } +inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true) +{ + return convert ? hl64ton(host64) : host64; +} +inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true) +{ + return convert ? htonl(host32) : host32; +} - inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true) - { - return convert ? htons(host16) : host16; - } +inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true) +{ + return convert ? htons(host16) : host16; +} - inline uint64_t networkToHost64(uint64_t net64, bool convert = true) - { - return convert ? ntohl64(net64) : net64; - } +inline uint64_t networkToHost64(uint64_t net64, bool convert = true) +{ + return convert ? ntohl64(net64) : net64; +} - inline uint32_t networkToHost32(uint32_t net32, bool convert = true) - { - return convert ? ntohl(net32) : net32; - } +inline uint32_t networkToHost32(uint32_t net32, bool convert = true) +{ + return convert ? ntohl(net32) : net32; +} - inline uint16_t networkToHost16(uint16_t net16, bool convert = true) - { - return convert ? ntohs(net16) : net16; - } +inline uint16_t networkToHost16(uint16_t net16, bool convert = true) +{ + return convert ? ntohs(net16) : net16; +} #elif defined BRYNET_PLATFORM_LINUX - inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true) - { - return convert ? htobe64(host64) : host64; - } - inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true) - { - return convert ? htobe32(host32) : host32; - } +inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true) +{ + return convert ? htobe64(host64) : host64; +} +inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true) +{ + return convert ? htobe32(host32) : host32; +} - inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true) - { - return convert ? htobe16(host16) : host16; - } +inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true) +{ + return convert ? htobe16(host16) : host16; +} - inline uint64_t networkToHost64(uint64_t net64, bool convert = true) - { - return convert ? be64toh(net64) : net64; - } +inline uint64_t networkToHost64(uint64_t net64, bool convert = true) +{ + return convert ? be64toh(net64) : net64; +} - inline uint32_t networkToHost32(uint32_t net32, bool convert = true) - { - return convert ? be32toh(net32) : net32; - } +inline uint32_t networkToHost32(uint32_t net32, bool convert = true) +{ + return convert ? be32toh(net32) : net32; +} - inline uint16_t networkToHost16(uint16_t net16, bool convert = true) - { - return convert ? be16toh(net16) : net16; - } +inline uint16_t networkToHost16(uint16_t net16, bool convert = true) +{ + return convert ? be16toh(net16) : net16; +} #elif defined BRYNET_PLATFORM_DARWIN - inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true) - { - return convert ? hl64ton(host64) : host64; - } - inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true) - { - return convert ? htonl(host32) : host32; - } +inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true) +{ + return convert ? hl64ton(host64) : host64; +} +inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true) +{ + return convert ? htonl(host32) : host32; +} - inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true) - { - return convert ? htons(host16) : host16; - } +inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true) +{ + return convert ? htons(host16) : host16; +} - inline uint64_t networkToHost64(uint64_t net64, bool convert = true) - { - return convert ? ntohl64(net64) : net64; - } +inline uint64_t networkToHost64(uint64_t net64, bool convert = true) +{ + return convert ? ntohl64(net64) : net64; +} - inline uint32_t networkToHost32(uint32_t net32, bool convert = true) - { - return convert ? ntohl(net32) : net32; - } +inline uint32_t networkToHost32(uint32_t net32, bool convert = true) +{ + return convert ? ntohl(net32) : net32; +} - inline uint16_t networkToHost16(uint16_t net16, bool convert = true) - { - return convert ? ntohs(net16) : net16; - } +inline uint16_t networkToHost16(uint16_t net16, bool convert = true) +{ + return convert ? ntohs(net16) : net16; +} #endif -} } } \ No newline at end of file +}}}// namespace brynet::base::endian \ No newline at end of file diff --git a/libs/brynet/net/AsyncConnector.hpp b/libs/brynet/net/AsyncConnector.hpp index 8d7dd75..e54753d 100644 --- a/libs/brynet/net/AsyncConnector.hpp +++ b/libs/brynet/net/AsyncConnector.hpp @@ -4,86 +4,38 @@ namespace brynet { namespace net { - class ConnectOption final +using ConnectOption = detail::ConnectOption; +class AsyncConnector : public detail::AsyncConnectorDetail, + public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + + void startWorkerThread() { - public: - using CompletedCallback = std::function; - using ProcessTcpSocketCallback = std::function; - using FailedCallback = std::function; - using ConnectOptionFunc = detail::ConnectOptionFunc; + detail::AsyncConnectorDetail::startWorkerThread(); + } - static ConnectOptionFunc WithAddr(const std::string& ip, int port) - { - return [ip, port](detail::ConnectOptionsInfo& option) { - option.ip = ip; - option.port = port; - }; - } - static ConnectOptionFunc WithTimeout(std::chrono::nanoseconds timeout) - { - return [timeout](detail::ConnectOptionsInfo& option) { - option.timeout = timeout; - }; - } - static ConnectOptionFunc WithCompletedCallback(CompletedCallback callback) - { - return [callback](detail::ConnectOptionsInfo& option) { - option.completedCallback = callback; - }; - } - static ConnectOptionFunc AddProcessTcpSocketCallback(ProcessTcpSocketCallback process) - { - return [process](detail::ConnectOptionsInfo& option) { - option.processCallbacks.push_back(process); - }; - } - static ConnectOptionFunc WithFailedCallback(FailedCallback callback) - { - return [callback](detail::ConnectOptionsInfo& option) { - option.faledCallback = callback; - }; - } - - static std::chrono::nanoseconds ExtractTimeout(const std::vector& options) - { - detail::ConnectOptionsInfo option; - for (const auto& func : options) - { - func(option); - } - return option.timeout; - } - }; - - class AsyncConnector : public detail::AsyncConnectorDetail, - public std::enable_shared_from_this + void stopWorkerThread() { - public: - using Ptr = std::shared_ptr; + detail::AsyncConnectorDetail::stopWorkerThread(); + } - void startWorkerThread() + void asyncConnect(const ConnectOption& option) + { + detail::AsyncConnectorDetail::asyncConnect(option); + } + + static Ptr Create() + { + class make_shared_enabler : public AsyncConnector { - detail::AsyncConnectorDetail::startWorkerThread(); - } + }; + return std::make_shared(); + } - void stopWorkerThread() - { - detail::AsyncConnectorDetail::stopWorkerThread(); - } +private: + AsyncConnector() = default; +}; - void asyncConnect(const std::vector& options) - { - detail::AsyncConnectorDetail::asyncConnect(options); - } - - static Ptr Create() - { - class make_shared_enabler : public AsyncConnector {}; - return std::make_shared(); - } - - private: - AsyncConnector() = default; - }; - -} } \ No newline at end of file +}}// namespace brynet::net diff --git a/libs/brynet/net/Channel.hpp b/libs/brynet/net/Channel.hpp index 979cd5f..5ef6dd5 100644 --- a/libs/brynet/net/Channel.hpp +++ b/libs/brynet/net/Channel.hpp @@ -2,19 +2,19 @@ namespace brynet { namespace net { - class EventLoop; +class EventLoop; - class Channel - { - public: - virtual ~Channel() = default; +class Channel +{ +public: + virtual ~Channel() = default; - private: - virtual void canSend() = 0; - virtual void canRecv() = 0; - virtual void onClose() = 0; +private: + virtual void canSend() = 0; + virtual void canRecv(bool willClose) = 0; + virtual void onClose() = 0; - friend class EventLoop; - }; + friend class EventLoop; +}; -} } \ No newline at end of file +}}// namespace brynet::net diff --git a/libs/brynet/net/CurrentThread.hpp b/libs/brynet/net/CurrentThread.hpp index b977360..6eab4bd 100644 --- a/libs/brynet/net/CurrentThread.hpp +++ b/libs/brynet/net/CurrentThread.hpp @@ -3,53 +3,54 @@ #include #ifdef BRYNET_PLATFORM_WINDOWS -#include +#define WIN32_LEAN_AND_MEAN #include +#include #elif defined BRYNET_PLATFORM_LINUX -#include +#include #include #include #include -#include -#elif defined BRYNET_PLATFORM_DARWIN #include +#elif defined BRYNET_PLATFORM_DARWIN #include #include +#include #endif namespace brynet { namespace net { namespace current_thread { #ifdef BRYNET_PLATFORM_WINDOWS - using THREAD_ID_TYPE = DWORD; +using THREAD_ID_TYPE = DWORD; #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - using THREAD_ID_TYPE = int; +using THREAD_ID_TYPE = int; #endif - static THREAD_ID_TYPE& tid() +static THREAD_ID_TYPE& tid() +{ +#ifdef BRYNET_PLATFORM_WINDOWS + static __declspec(thread) THREAD_ID_TYPE cachedTid = 0; +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + static __thread THREAD_ID_TYPE cachedTid = 0; +#endif + + if (cachedTid == 0) { #ifdef BRYNET_PLATFORM_WINDOWS - static __declspec(thread) THREAD_ID_TYPE cachedTid = 0; -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - static __thread THREAD_ID_TYPE cachedTid = 0; -#endif - - if (cachedTid == 0) - { -#ifdef BRYNET_PLATFORM_WINDOWS - cachedTid = GetCurrentThreadId(); + cachedTid = GetCurrentThreadId(); #elif defined BRYNET_PLATFORM_LINUX - cachedTid = static_cast(::syscall(SYS_gettid)); + cachedTid = static_cast(::syscall(SYS_gettid)); #elif defined BRYNET_PLATFORM_DARWIN - // warning: 'syscall' is deprecated: - // first deprecated in macOS 10.12 - syscall(2) is unsupported; - // please switch to a supported interface. - uint64_t tid64; - pthread_threadid_np(NULL, &tid64); - cachedTid = (pid_t)tid64; + // warning: 'syscall' is deprecated: + // first deprecated in macOS 10.12 - syscall(2) is unsupported; + // please switch to a supported interface. + uint64_t tid64; + pthread_threadid_np(NULL, &tid64); + cachedTid = (pid_t) tid64; #endif - } - - return cachedTid; } -} } } + return cachedTid; +} + +}}}// namespace brynet::net::current_thread diff --git a/libs/brynet/net/EventLoop.hpp b/libs/brynet/net/EventLoop.hpp index 012ee91..e39c468 100644 --- a/libs/brynet/net/EventLoop.hpp +++ b/libs/brynet/net/EventLoop.hpp @@ -1,444 +1,444 @@ 锘#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include #include -#include +#include #include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include +#include namespace brynet { namespace net { - class Channel; - class TcpConnection; - using TcpConnectionPtr = std::shared_ptr; +class Channel; +class TcpConnection; +using TcpConnectionPtr = std::shared_ptr; - class EventLoop : public brynet::base::NonCopyable - { - public: - using Ptr = std::shared_ptr; - using UserFunctor = std::function; +class EventLoop : public brynet::base::NonCopyable +{ +public: + using Ptr = std::shared_ptr; + using UserFunctor = std::function; - public: - EventLoop() +public: + EventLoop() BRYNET_NOEXCEPT - : + : #ifdef BRYNET_PLATFORM_WINDOWS - mIOCP(CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)), - mWakeupChannel(std::make_unique(mIOCP)) + mIOCP(CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)), + mWakeupChannel(std::make_unique(mIOCP)) #elif defined BRYNET_PLATFORM_LINUX - mEpollFd(epoll_create(1)) + mEpollFd(epoll_create(1)) #elif defined BRYNET_PLATFORM_DARWIN - mKqueueFd(kqueue()) + mKqueueFd(kqueue()) #endif - { + { #ifdef BRYNET_PLATFORM_WINDOWS - mPGetQueuedCompletionStatusEx = NULL; - auto kernel32_module = GetModuleHandleA("kernel32.dll"); - if (kernel32_module != NULL) { - mPGetQueuedCompletionStatusEx = reinterpret_cast(GetProcAddress( + mPGetQueuedCompletionStatusEx = NULL; + auto kernel32_module = GetModuleHandleA("kernel32.dll"); + if (kernel32_module != NULL) + { + mPGetQueuedCompletionStatusEx = reinterpret_cast(GetProcAddress( kernel32_module, "GetQueuedCompletionStatusEx")); - FreeLibrary(kernel32_module); - } + FreeLibrary(kernel32_module); + } #elif defined BRYNET_PLATFORM_LINUX - auto eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - mWakeupChannel.reset(new detail::WakeupChannel(eventfd)); - linkChannel(eventfd, mWakeupChannel.get()); + auto eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + mWakeupChannel.reset(new detail::WakeupChannel(eventfd)); + linkChannel(eventfd, mWakeupChannel.get()); #elif defined BRYNET_PLATFORM_DARWIN - const int NOTIFY_IDENT = 42; // Magic number we use for our filter ID. - mWakeupChannel.reset(new detail::WakeupChannel(mKqueueFd, NOTIFY_IDENT)); - //Add user event - struct kevent ev; - EV_SET(&ev, NOTIFY_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); + const int NOTIFY_IDENT = 42;// Magic number we use for our filter ID. + mWakeupChannel.reset(new detail::WakeupChannel(mKqueueFd, NOTIFY_IDENT)); + //Add user event + struct kevent ev; + EV_SET(&ev, NOTIFY_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); - struct timespec timeout = { 0, 0 }; - kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout); + struct timespec timeout = {0, 0}; + kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout); #endif - mIsAlreadyPostWakeup = false; - mIsInBlock = true; + mIsAlreadyPostWakeup = false; + mIsInBlock = true; - reallocEventSize(1024); - mSelfThreadID = -1; - mTimer = std::make_shared(); - } + reAllocEventSize(1024); + mSelfThreadID = -1; + mTimer = std::make_shared(); + } - virtual ~EventLoop() BRYNET_NOEXCEPT - { + virtual ~EventLoop() BRYNET_NOEXCEPT + { #ifdef BRYNET_PLATFORM_WINDOWS - CloseHandle(mIOCP); - mIOCP = INVALID_HANDLE_VALUE; + CloseHandle(mIOCP); + mIOCP = INVALID_HANDLE_VALUE; #elif defined BRYNET_PLATFORM_LINUX - close(mEpollFd); - mEpollFd = -1; + close(mEpollFd); + mEpollFd = -1; #elif defined BRYNET_PLATFORM_DARWIN - close(mKqueueFd); - mKqueueFd = -1; + close(mKqueueFd); + mKqueueFd = -1; #endif - } + } - void loop(int64_t milliseconds) - { - tryInitThreadID(); + void loop(int64_t milliseconds) + { + tryInitThreadID(); #ifndef NDEBUG - assert(isInLoopThread()); + assert(isInLoopThread()); #endif - if (!isInLoopThread()) - { - throw BrynetCommonException("only loop in io thread"); - } + if (!isInLoopThread()) + { + throw BrynetCommonException("only loop in io thread"); + } - if (!mAfterLoopFunctors.empty()) - { - milliseconds = 0; - } + if (!mAfterLoopFunctors.empty()) + { + milliseconds = 0; + } #ifdef BRYNET_PLATFORM_WINDOWS - ULONG numComplete = 0; - if (mPGetQueuedCompletionStatusEx != nullptr) + ULONG numComplete = 0; + if (mPGetQueuedCompletionStatusEx != nullptr) + { + if (!mPGetQueuedCompletionStatusEx(mIOCP, + mEventEntries.data(), + static_cast(mEventEntries.size()), + &numComplete, + static_cast(milliseconds), + false)) { - if (!mPGetQueuedCompletionStatusEx(mIOCP, - mEventEntries.data(), - static_cast(mEventEntries.size()), - &numComplete, - static_cast(milliseconds), - false)) + numComplete = 0; + } + } + else + { + for (auto& e : mEventEntries) + { + const auto timeout = (numComplete == 0) ? static_cast(milliseconds) : 0; + /* don't check the return value of GQCS */ + GetQueuedCompletionStatus(mIOCP, + &e.dwNumberOfBytesTransferred, + &e.lpCompletionKey, + &e.lpOverlapped, + timeout); + if (e.lpOverlapped == nullptr) { - numComplete = 0; + break; } + ++numComplete; + } + } + + mIsInBlock = false; + + for (ULONG i = 0; i < numComplete; ++i) + { + auto channel = (Channel*) mEventEntries[i].lpCompletionKey; + assert(channel != nullptr); + const auto ovl = reinterpret_cast(mEventEntries[i].lpOverlapped); + if (ovl->OP == port::Win::OverlappedType::OverlappedRecv) + { + channel->canRecv(false); + } + else if (ovl->OP == port::Win::OverlappedType::OverlappedSend) + { + channel->canSend(); } else { - for (auto& e : mEventEntries) - { - const auto timeout = (numComplete == 0) ? static_cast(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(mEventEntries[i].lpOverlapped); - if (ovl->OP == port::Win::OverlappedType::OverlappedRecv) - { - channel->canRecv(); - } - else if (ovl->OP == port::Win::OverlappedType::OverlappedSend) - { - channel->canSend(); - } - else - { - assert(false); - } + assert(false); } + } #elif defined BRYNET_PLATFORM_LINUX - int numComplete = epoll_wait(mEpollFd, mEventEntries.data(), mEventEntries.size(), milliseconds); + int numComplete = epoll_wait(mEpollFd, mEventEntries.data(), mEventEntries.size(), milliseconds); - mIsInBlock = false; + mIsInBlock = false; - for (int i = 0; i < numComplete; ++i) + for (int i = 0; i < numComplete; ++i) + { + auto channel = (Channel*) (mEventEntries[i].data.ptr); + auto event_data = mEventEntries[i].events; + + if (event_data & EPOLLRDHUP) { - auto channel = (Channel*)(mEventEntries[i].data.ptr); - auto event_data = mEventEntries[i].events; - - if (event_data & EPOLLRDHUP) - { - channel->canRecv(); - channel->onClose(); - continue; - } - - if (event_data & EPOLLIN) - { - channel->canRecv(); - } - - if (event_data & EPOLLOUT) - { - channel->canSend(); - } + channel->canRecv(true); + channel->onClose(); + continue; } + + if (event_data & EPOLLIN) + { + channel->canRecv(false); + } + + if (event_data & EPOLLOUT) + { + channel->canSend(); + } + } #elif defined BRYNET_PLATFORM_DARWIN - struct timespec timeout = { milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000 }; - int numComplete = kevent(mKqueueFd, NULL, 0, mEventEntries.data(), mEventEntries.size(), &timeout); + struct timespec timeout = {milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000}; + int numComplete = kevent(mKqueueFd, NULL, 0, mEventEntries.data(), mEventEntries.size(), &timeout); - mIsInBlock = false; + mIsInBlock = false; - for (int i = 0; i < numComplete; ++i) + for (int i = 0; i < numComplete; ++i) + { + auto channel = (Channel*) (mEventEntries[i].udata); + const struct kevent& event = mEventEntries[i]; + + if (event.filter == EVFILT_USER) { - auto channel = (Channel*)(mEventEntries[i].udata); - const struct kevent& event = mEventEntries[i]; - - if (event.filter == EVFILT_USER) - { - continue; - } - - if (event.filter == EVFILT_READ) - { - channel->canRecv(); - } - - if (event.filter == EVFILT_WRITE) - { - channel->canSend(); - } + continue; } + + if (event.filter == EVFILT_READ) + { + channel->canRecv(false); + } + + if (event.filter == EVFILT_WRITE) + { + channel->canSend(); + } + } #endif - mIsAlreadyPostWakeup = false; - mIsInBlock = true; + mIsAlreadyPostWakeup = false; + mIsInBlock = true; - processAsyncFunctors(); - processAfterLoopFunctors(); + processAsyncFunctors(); + processAfterLoopFunctors(); - if (static_cast(numComplete) == mEventEntries.size()) - { - reallocEventSize(mEventEntries.size() + 128); - } - - mTimer->schedule(); + if (static_cast(numComplete) == mEventEntries.size()) + { + reAllocEventSize(mEventEntries.size() + 128); } - // loop鎸囧畾姣鏁,浣嗗鏋滃畾鏃跺櫒涓嶄负绌,鍒檒oop鏃堕棿涓哄綋鍓嶆渶杩戝畾鏃跺櫒鐨勫墿浣欐椂闂村拰milliseconds鐨勮緝灏忓 - void loopCompareNearTimer(int64_t milliseconds) - { - tryInitThreadID(); + mTimer->schedule(); + } + + // loop鎸囧畾姣鏁,浣嗗鏋滃畾鏃跺櫒涓嶄负绌,鍒檒oop鏃堕棿涓哄綋鍓嶆渶杩戝畾鏃跺櫒鐨勫墿浣欐椂闂村拰milliseconds鐨勮緝灏忓 + void loopCompareNearTimer(int64_t milliseconds) + { + tryInitThreadID(); #ifndef NDEBUG - assert(isInLoopThread()); + assert(isInLoopThread()); #endif - if (!isInLoopThread()) - { - throw BrynetCommonException("only loop in IO thread"); - } - - if (!mTimer->isEmpty()) - { - auto nearTimeout = std::chrono::duration_cast(mTimer->nearLeftTime()); - milliseconds = std::min(milliseconds, nearTimeout.count()); - } - - loop(milliseconds); + if (!isInLoopThread()) + { + throw BrynetCommonException("only loop in IO thread"); } - // 杩斿洖true琛ㄧず瀹為檯鍙戠敓浜唚akeup鎵闇鐨勬搷浣(姝よ繑鍥炲间笉浠h〃鎺ュ彛鏈韩鎿嶄綔鎴愬姛涓庡惁,鍥犱负姝ゅ嚱鏁版案杩滄垚鍔) - bool wakeup() + if (!mTimer->isEmpty()) { - if (!isInLoopThread() && mIsInBlock && !mIsAlreadyPostWakeup.exchange(true)) - { - return mWakeupChannel->wakeup(); - } - - return false; + auto nearTimeout = std::chrono::duration_cast(mTimer->nearLeftTime()); + milliseconds = std::min(milliseconds, nearTimeout.count()); } - void runAsyncFunctor(UserFunctor&& f) - { - if (isInLoopThread()) - { - f(); - } - else - { - pushAsyncFunctor(std::move(f)); - wakeup(); - } - } - void runFunctorAfterLoop(UserFunctor&& f) - { - assert(isInLoopThread()); - if (!isInLoopThread()) - { - throw BrynetCommonException("only push after functor in io thread"); - } + loop(milliseconds); + } - mAfterLoopFunctors.emplace_back(std::move(f)); - } - brynet::base::Timer::WeakPtr runAfter(std::chrono::nanoseconds timeout, UserFunctor&& callback) + // 杩斿洖true琛ㄧず瀹為檯鍙戠敓浜唚akeup鎵闇鐨勬搷浣(姝よ繑鍥炲间笉浠h〃鎺ュ彛鏈韩鎿嶄綔鎴愬姛涓庡惁,鍥犱负姝ゅ嚱鏁版案杩滄垚鍔) + bool wakeup() + { + if (!isInLoopThread() && mIsInBlock && !mIsAlreadyPostWakeup.exchange(true)) { - auto timer = std::make_shared( + return mWakeupChannel->wakeup(); + } + + return false; + } + + void runAsyncFunctor(UserFunctor&& f) + { + if (isInLoopThread()) + { + f(); + } + else + { + pushAsyncFunctor(std::move(f)); + wakeup(); + } + } + void runFunctorAfterLoop(UserFunctor&& f) + { + assert(isInLoopThread()); + if (!isInLoopThread()) + { + throw BrynetCommonException("only push after functor in io thread"); + } + + mAfterLoopFunctors.emplace_back(std::move(f)); + } + brynet::base::Timer::WeakPtr runAfter(std::chrono::nanoseconds timeout, UserFunctor&& callback) + { + auto timer = std::make_shared( std::chrono::steady_clock::now(), std::chrono::nanoseconds(timeout), std::move(callback)); - if (isInLoopThread()) - { - mTimer->addTimer(timer); - } - else - { - auto timerMgr = mTimer; - runAsyncFunctor([timerMgr, timer]() { - timerMgr->addTimer(timer); - }); - } - - return timer; + if (isInLoopThread()) + { + mTimer->addTimer(timer); + } + else + { + auto timerMgr = mTimer; + runAsyncFunctor([timerMgr, timer]() { + timerMgr->addTimer(timer); + }); } - inline bool isInLoopThread() const - { - return mSelfThreadID == current_thread::tid(); - } + return timer; + } - private: - void reallocEventSize(size_t size) - { - mEventEntries.resize(size); - } + inline bool isInLoopThread() const + { + return mSelfThreadID == current_thread::tid(); + } - void processAfterLoopFunctors() - { - mCopyAfterLoopFunctors.swap(mAfterLoopFunctors); - for (const auto& x : mCopyAfterLoopFunctors) - { - x(); - } - mCopyAfterLoopFunctors.clear(); - } - void processAsyncFunctors() - { - swapAsyncFunctors(); +private: + void reAllocEventSize(size_t size) + { + mEventEntries.resize(size); + } - for (const auto& x : mCopyAsyncFunctors) - { - x(); - } - mCopyAsyncFunctors.clear(); - } - void swapAsyncFunctors() + void processAfterLoopFunctors() + { + mCopyAfterLoopFunctors.swap(mAfterLoopFunctors); + for (const auto& x : mCopyAfterLoopFunctors) { - std::lock_guard lck(mAsyncFunctorsMutex); - assert(mCopyAsyncFunctors.empty()); - mCopyAsyncFunctors.swap(mAsyncFunctors); + x(); } - void pushAsyncFunctor(UserFunctor&& f) + mCopyAfterLoopFunctors.clear(); + } + void processAsyncFunctors() + { + swapAsyncFunctors(); + + for (const auto& x : mCopyAsyncFunctors) { - std::lock_guard lck(mAsyncFunctorsMutex); - mAsyncFunctors.emplace_back(std::move(f)); + x(); } + mCopyAsyncFunctors.clear(); + } + void swapAsyncFunctors() + { + std::lock_guard lck(mAsyncFunctorsMutex); + assert(mCopyAsyncFunctors.empty()); + mCopyAsyncFunctors.swap(mAsyncFunctors); + } + void pushAsyncFunctor(UserFunctor&& f) + { + std::lock_guard lck(mAsyncFunctorsMutex); + mAsyncFunctors.emplace_back(std::move(f)); + } #ifdef BRYNET_PLATFORM_LINUX - int getEpollHandle() const - { - return mEpollFd; - } + int getEpollHandle() const + { + return mEpollFd; + } #elif defined BRYNET_PLATFORM_DARWIN - int getKqueueHandle() const - { - return mKqueueFd; - } + int getKqueueHandle() const + { + return mKqueueFd; + } #endif - bool linkChannel(BrynetSocketFD fd, const Channel* ptr) BRYNET_NOEXCEPT - { + bool linkChannel(BrynetSocketFD fd, const Channel* ptr) BRYNET_NOEXCEPT + { #ifdef BRYNET_PLATFORM_WINDOWS - return CreateIoCompletionPort((HANDLE)fd, mIOCP, (ULONG_PTR)ptr, 0) != nullptr; + return CreateIoCompletionPort((HANDLE) fd, mIOCP, (ULONG_PTR) ptr, 0) != nullptr; #elif defined BRYNET_PLATFORM_LINUX - struct epoll_event ev = { 0, { nullptr } }; - ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP; - ev.data.ptr = (void*)ptr; - return epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &ev) == 0; + struct epoll_event ev = {0, + { + nullptr + }}; + ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP; + ev.data.ptr = (void*) ptr; + return epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &ev) == 0; #elif defined BRYNET_PLATFORM_DARWIN - struct kevent ev[2]; - memset(&ev, 0, sizeof(ev)); - int n = 0; - EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*)ptr); - EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*)ptr); + struct kevent ev[2]; + memset(&ev, 0, sizeof(ev)); + int n = 0; + EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*) ptr); + EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*) ptr); - struct timespec now = { 0, 0 }; - return kevent(mKqueueFd, ev, n, NULL, 0, &now) == 0; + struct timespec now = {0, 0}; + return kevent(mKqueueFd, ev, n, NULL, 0, &now) == 0; #endif - } - TcpConnectionPtr getTcpConnection(BrynetSocketFD fd) + } + TcpConnectionPtr getTcpConnection(BrynetSocketFD fd) + { + auto it = mTcpConnections.find(fd); + if (it != mTcpConnections.end()) { - auto it = mTcpConnections.find(fd); - if (it != mTcpConnections.end()) - { - return (*it).second; - } - return nullptr; - } - void addTcpConnection(BrynetSocketFD fd, TcpConnectionPtr tcpConnection) - { - mTcpConnections[fd] = std::move(tcpConnection); - } - void removeTcpConnection(BrynetSocketFD fd) - { - mTcpConnections.erase(fd); - } - void tryInitThreadID() - { - std::call_once(mOnceInitThreadID, [this]() { - mSelfThreadID = current_thread::tid(); - }); + return (*it).second; } + return nullptr; + } + void addTcpConnection(BrynetSocketFD fd, TcpConnectionPtr tcpConnection) + { + mTcpConnections[fd] = std::move(tcpConnection); + } + void removeTcpConnection(BrynetSocketFD fd) + { + mTcpConnections.erase(fd); + } + void tryInitThreadID() + { + std::call_once(mOnceInitThreadID, [this]() { + mSelfThreadID = current_thread::tid(); + }); + } - private: - +private: #ifdef BRYNET_PLATFORM_WINDOWS - std::vector mEventEntries; + std::vector mEventEntries; - typedef BOOL(WINAPI *sGetQueuedCompletionStatusEx) (HANDLE, LPOVERLAPPED_ENTRY, ULONG, PULONG, DWORD, BOOL); - sGetQueuedCompletionStatusEx mPGetQueuedCompletionStatusEx; - HANDLE mIOCP; + typedef BOOL(WINAPI* sGetQueuedCompletionStatusEx)(HANDLE, LPOVERLAPPED_ENTRY, ULONG, PULONG, DWORD, BOOL); + sGetQueuedCompletionStatusEx mPGetQueuedCompletionStatusEx; + HANDLE mIOCP; #elif defined BRYNET_PLATFORM_LINUX - std::vector mEventEntries; - int mEpollFd; + std::vector mEventEntries; + int mEpollFd; #elif defined BRYNET_PLATFORM_DARWIN - std::vector mEventEntries; - int mKqueueFd; + std::vector mEventEntries; + int mKqueueFd; #endif - std::unique_ptr mWakeupChannel; + std::unique_ptr mWakeupChannel; - std::atomic_bool mIsInBlock; - std::atomic_bool mIsAlreadyPostWakeup; + std::atomic_bool mIsInBlock; + std::atomic_bool mIsAlreadyPostWakeup; - std::mutex mAsyncFunctorsMutex; - std::vector mAsyncFunctors; - std::vector mCopyAsyncFunctors; + std::mutex mAsyncFunctorsMutex; + std::vector mAsyncFunctors; + std::vector mCopyAsyncFunctors; - std::vector mAfterLoopFunctors; - std::vector mCopyAfterLoopFunctors; + std::vector mAfterLoopFunctors; + std::vector mCopyAfterLoopFunctors; - std::once_flag mOnceInitThreadID; - current_thread::THREAD_ID_TYPE mSelfThreadID; + std::once_flag mOnceInitThreadID; + current_thread::THREAD_ID_TYPE mSelfThreadID; - brynet::base::TimerMgr::Ptr mTimer; - std::unordered_map mTcpConnections; + brynet::base::TimerMgr::Ptr mTimer; + std::unordered_map mTcpConnections; - friend class TcpConnection; - }; + friend class TcpConnection; +}; -} } \ No newline at end of file +}}// namespace brynet::net diff --git a/libs/brynet/net/Exception.hpp b/libs/brynet/net/Exception.hpp index 2fa103b..3cd34de 100644 --- a/libs/brynet/net/Exception.hpp +++ b/libs/brynet/net/Exception.hpp @@ -1,41 +1,36 @@ 锘#pragma once -#include -#include #include +#include namespace brynet { namespace net { - class ConnectException : public std::runtime_error +class ConnectException : public std::runtime_error +{ +public: + explicit ConnectException(const std::string& message) + : std::runtime_error(message) { - public: - explicit ConnectException(const std::string& message) - : - std::runtime_error(message) - { - } + } - explicit ConnectException(const char* message) - : - std::runtime_error(message) - { - } - }; - - class BrynetCommonException : public std::runtime_error + explicit ConnectException(const char* message) + : std::runtime_error(message) { - public: - explicit BrynetCommonException(const std::string& message) - : - std::runtime_error(message) - { - } + } +}; - explicit BrynetCommonException(const char* message) - : - std::runtime_error(message) - { - } - }; +class BrynetCommonException : public std::runtime_error +{ +public: + explicit BrynetCommonException(const std::string& message) + : std::runtime_error(message) + { + } -} } \ No newline at end of file + explicit BrynetCommonException(const char* message) + : std::runtime_error(message) + { + } +}; + +}}// namespace brynet::net diff --git a/libs/brynet/net/ListenThread.hpp b/libs/brynet/net/ListenThread.hpp index 3b9ef90..926a3a1 100644 --- a/libs/brynet/net/ListenThread.hpp +++ b/libs/brynet/net/ListenThread.hpp @@ -4,55 +4,56 @@ namespace brynet { namespace net { - class ListenThread : public detail::ListenThreadDetail, - public std::enable_shared_from_this +class ListenThread : public detail::ListenThreadDetail, + public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + using AccepCallback = std::function; + using TcpSocketProcessCallback = std::function; + + void startListen() { - public: - using Ptr = std::shared_ptr; - using AccepCallback = std::function;; - using TcpSocketProcessCallback = std::function; + detail::ListenThreadDetail::startListen(); + } - void startListen() + void stopListen() + { + detail::ListenThreadDetail::stopListen(); + } + +public: + static Ptr Create(bool isIPV6, + const std::string& ip, + int port, + const AccepCallback& callback, + const std::vector& processCallbacks = {}, + bool enabledReusePort = false) + { + class make_shared_enabler : public ListenThread { - detail::ListenThreadDetail::startListen(); - } + public: + make_shared_enabler(bool isIPV6, + const std::string& ip, + int port, + const AccepCallback& callback, + const std::vector& processCallbacks, + bool enabledReusePort) + : ListenThread(isIPV6, ip, port, callback, processCallbacks, enabledReusePort) + {} + }; + return std::make_shared(isIPV6, ip, port, callback, processCallbacks, enabledReusePort); + } - void stopListen() - { - detail::ListenThreadDetail::stopListen(); - } +protected: + ListenThread(bool isIPV6, + const std::string& ip, + int port, + const AccepCallback& callback, + const std::vector& processCallbacks, + bool enabledReusePort) + : detail::ListenThreadDetail(isIPV6, ip, port, callback, processCallbacks, enabledReusePort) + {} +}; - public: - static Ptr Create(bool isIPV6, - const std::string& ip, - int port, - const AccepCallback& callback, - const std::vector & processCallbacks = {}) - { - class make_shared_enabler : public ListenThread - { - public: - make_shared_enabler(bool isIPV6, - const std::string& ip, - int port, - const AccepCallback& callback, - const std::vector& processCallbacks) - : - ListenThread(isIPV6, ip, port, callback, processCallbacks) - {} - }; - return std::make_shared(isIPV6, ip, port, callback, processCallbacks); - } - - protected: - ListenThread(bool isIPV6, - const std::string& ip, - int port, - const AccepCallback& callback, - const std::vector& processCallbacks) - : - detail::ListenThreadDetail(isIPV6, ip, port, callback, processCallbacks) - {} - }; - -} } +}}// namespace brynet::net diff --git a/libs/brynet/net/Poller.hpp b/libs/brynet/net/Poller.hpp index 820a941..8c6bc11 100644 --- a/libs/brynet/net/Poller.hpp +++ b/libs/brynet/net/Poller.hpp @@ -1,13 +1,9 @@ #pragma once -#include -#include -#include -#include -#include - -#include #include +#include +#include +#include #if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN #include @@ -15,252 +11,252 @@ namespace brynet { namespace base { - #ifdef BRYNET_PLATFORM_WINDOWS - const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND); - const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM); - const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP); - #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI); - const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM | POLLWRBAND); - const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP); - #endif +#ifdef BRYNET_PLATFORM_WINDOWS +const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND); +const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM); +const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP); +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN +const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI); +const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM | POLLWRBAND); +const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP); +#endif - enum CheckType +enum CheckType +{ + ReadCheck = 0x1, + WriteCheck = 0x2, + ErrorCheck = 0x4, +}; + +struct poller_s +{ + struct pollfd* pollFds; + int nfds; + int limitSize; +}; + +static void upstep_pollfd(struct poller_s* self, int upSize) +{ + if (upSize <= 0) { - ReadCheck = 0x1, - WriteCheck = 0x2, - ErrorCheck = 0x4, - }; + return; + } - struct poller_s - { - struct pollfd* pollFds; - int nfds; - int limitSize; - }; - - static void upstep_pollfd(struct poller_s* self, int upSize) - { - if (upSize <= 0) - { - return; - } - - struct pollfd* newPollfds = (struct pollfd*)malloc( + struct pollfd* newPollfds = (struct pollfd*) malloc( sizeof(struct pollfd) * (self->limitSize + upSize)); - if (newPollfds == nullptr) - { - return; - } - - if (self->pollFds != nullptr) - { - memcpy(newPollfds, self->pollFds, sizeof(struct pollfd) * self->nfds); - free(self->pollFds); - self->pollFds = nullptr; - } - self->pollFds = newPollfds; - self->limitSize += upSize; + if (newPollfds == nullptr) + { + return; } - static struct pollfd* find_pollfd(struct poller_s* self, BrynetSocketFD fd) - { - for (int i = 0; i < self->nfds; i++) - { - if (self->pollFds[i].fd == fd) - { - return self->pollFds + i; - } - } - - return nullptr; - } - - static void try_remove_pollfd(struct poller_s* self, BrynetSocketFD fd) - { - int pos = -1; - for (int i = 0; i < self->nfds; i++) - { - if (self->pollFds[i].fd == fd) - { - pos = i; - break; - } - } - - if (pos != -1) - { - memmove(self->pollFds + pos, - self->pollFds + pos + 1, - sizeof(struct pollfd) * (self->nfds - pos - 1)); - self->nfds--; - assert(self->nfds >= 0); - } - } - - static struct poller_s* poller_new(void) - { - struct poller_s* ret = (struct poller_s*)malloc(sizeof(struct poller_s)); - if (ret != nullptr) - { - ret->pollFds = NULL; - ret->limitSize = 0; - ret->nfds = 0; - upstep_pollfd(ret, 1024); - } - - return ret; - } - - static void poller_delete(struct poller_s* self) + if (self->pollFds != nullptr) { + memcpy(newPollfds, self->pollFds, sizeof(struct pollfd) * self->nfds); free(self->pollFds); self->pollFds = nullptr; - self->nfds = 0; - self->limitSize = 0; - - free(self); - self = nullptr; } + self->pollFds = newPollfds; + self->limitSize += upSize; +} - static void poller_add(struct poller_s* self, BrynetSocketFD fd, int type) +static struct pollfd* find_pollfd(struct poller_s* self, BrynetSocketFD fd) +{ + for (int i = 0; i < self->nfds; i++) { - if (self->limitSize == self->nfds) + if (self->pollFds[i].fd == fd) { - upstep_pollfd(self, 128); - } - - if (self->limitSize <= self->nfds) - { - return; - } - - struct pollfd* pf = find_pollfd(self, fd); - if (pf == nullptr) - { - /*real add*/ - pf = self->pollFds + self->nfds; - pf->events = 0; - pf->fd = fd; - - self->nfds++; - } - - if (type & ReadCheck) - { - pf->events |= CHECK_READ_FLAG; - } - - if (type & WriteCheck) - { - pf->events |= CHECK_WRITE_FLAG; - } - - if (type & ErrorCheck) - { - //pf->events |= CHECK_ERROR_FLAG; TODO::on windows, not supports + return self->pollFds + i; } } - static void poller_del(struct poller_s* self, BrynetSocketFD fd, int type) + return nullptr; +} + +static void try_remove_pollfd(struct poller_s* self, BrynetSocketFD fd) +{ + int pos = -1; + for (int i = 0; i < self->nfds; i++) { - struct pollfd* pf = find_pollfd(self, fd); - if (pf == nullptr) + if (self->pollFds[i].fd == fd) { - return; - } - - if (type & ReadCheck) - { - pf->events &= ~CHECK_READ_FLAG; - } - - if (type & WriteCheck) - { - pf->events &= ~CHECK_WRITE_FLAG; - } - - if (type & ErrorCheck) - { - pf->events &= ~CHECK_ERROR_FLAG; - } - - if (pf->events == 0) - { - try_remove_pollfd(self, fd); + pos = i; + break; } } - static void poller_remove(struct poller_s* self, BrynetSocketFD fd) + if (pos != -1) + { + memmove(self->pollFds + pos, + self->pollFds + pos + 1, + sizeof(struct pollfd) * (self->nfds - pos - 1)); + self->nfds--; + assert(self->nfds >= 0); + } +} + +static struct poller_s* poller_new(void) +{ + struct poller_s* ret = (struct poller_s*) malloc(sizeof(struct poller_s)); + if (ret != nullptr) + { + ret->pollFds = NULL; + ret->limitSize = 0; + ret->nfds = 0; + upstep_pollfd(ret, 1024); + } + + return ret; +} + +static void poller_delete(struct poller_s* self) +{ + free(self->pollFds); + self->pollFds = nullptr; + self->nfds = 0; + self->limitSize = 0; + + free(self); + self = nullptr; +} + +static void poller_add(struct poller_s* self, BrynetSocketFD fd, int type) +{ + if (self->limitSize == self->nfds) + { + upstep_pollfd(self, 128); + } + + if (self->limitSize <= self->nfds) + { + return; + } + + struct pollfd* pf = find_pollfd(self, fd); + if (pf == nullptr) + { + /*real add*/ + pf = self->pollFds + self->nfds; + pf->events = 0; + pf->fd = fd; + + self->nfds++; + } + + if (type & ReadCheck) + { + pf->events |= CHECK_READ_FLAG; + } + + if (type & WriteCheck) + { + pf->events |= CHECK_WRITE_FLAG; + } + + if (type & ErrorCheck) + { + //pf->events |= CHECK_ERROR_FLAG; TODO::on windows, not supports + } +} + +static void poller_del(struct poller_s* self, BrynetSocketFD fd, int type) +{ + struct pollfd* pf = find_pollfd(self, fd); + if (pf == nullptr) + { + return; + } + + if (type & ReadCheck) + { + pf->events &= ~CHECK_READ_FLAG; + } + + if (type & WriteCheck) + { + pf->events &= ~CHECK_WRITE_FLAG; + } + + if (type & ErrorCheck) + { + pf->events &= ~CHECK_ERROR_FLAG; + } + + if (pf->events == 0) { try_remove_pollfd(self, fd); } +} - static bool check_event(const struct pollfd* pf, enum CheckType type) +static void poller_remove(struct poller_s* self, BrynetSocketFD fd) +{ + try_remove_pollfd(self, fd); +} + +static bool check_event(const struct pollfd* pf, enum CheckType type) +{ + if (pf == nullptr) { - if (pf == nullptr) - { - return false; - } - - if ((type & ReadCheck) && - (pf->revents & CHECK_READ_FLAG)) - { - return true; - } - else if ((type & WriteCheck) && - (pf->revents & CHECK_WRITE_FLAG)) - { - return true; - } - else if ((type & ErrorCheck) && - (pf->revents & CHECK_ERROR_FLAG)) - { - return true; - } - else - { - return false; - } + return false; } - static void poller_visitor(struct poller_s* self, - enum CheckType type, - struct stack_s* result) + if ((type & ReadCheck) && + (pf->revents & CHECK_READ_FLAG)) { - for (int i = 0; i < self->nfds; i++) + return true; + } + else if ((type & WriteCheck) && + (pf->revents & CHECK_WRITE_FLAG)) + { + return true; + } + else if ((type & ErrorCheck) && + (pf->revents & CHECK_ERROR_FLAG)) + { + return true; + } + else + { + return false; + } +} + +static void poller_visitor(struct poller_s* self, + enum CheckType type, + struct stack_s* result) +{ + for (int i = 0; i < self->nfds; i++) + { + if (check_event(self->pollFds + i, type)) { - if (check_event(self->pollFds + i, type)) - { - stack_push(result, &self->pollFds[i].fd); - } + stack_push(result, &self->pollFds[i].fd); } } +} - static int poller_poll(struct poller_s* self, long overtime) - { +static int poller_poll(struct poller_s* self, long overtime) +{ #ifdef BRYNET_PLATFORM_WINDOWS - int ret = WSAPoll(&self->pollFds[0], self->nfds, overtime); + int ret = WSAPoll(&self->pollFds[0], self->nfds, overtime); #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - int ret = poll(self->pollFds, self->nfds, overtime); + int ret = poll(self->pollFds, self->nfds, overtime); #endif - if (ret == BRYNET_SOCKET_ERROR) - { - ret = (BRYNET_ERRNO != BRYNET_EINTR) ? -1 : 0; - } - - return ret; - } - - static bool poller_check(struct poller_s* self, BrynetSocketFD fd, enum CheckType type) + if (ret == BRYNET_SOCKET_ERROR) { - const struct pollfd* pf = find_pollfd(self, fd); - if (pf == NULL) - { - return false; - } - return check_event(pf, type); + ret = (BRYNET_ERRNO != BRYNET_EINTR) ? -1 : 0; } -} } + return ret; +} + +static bool poller_check(struct poller_s* self, BrynetSocketFD fd, enum CheckType type) +{ + const struct pollfd* pf = find_pollfd(self, fd); + if (pf == NULL) + { + return false; + } + return check_event(pf, type); +} + +}}// namespace brynet::base diff --git a/libs/brynet/net/PromiseReceive.hpp b/libs/brynet/net/PromiseReceive.hpp index 2f372f3..57a7e7c 100644 --- a/libs/brynet/net/PromiseReceive.hpp +++ b/libs/brynet/net/PromiseReceive.hpp @@ -4,153 +4,153 @@ namespace brynet { namespace net { - /* binary search in memory */ - void memsearch(const char *hay, size_t haysize, const char *needle, size_t needlesize, size_t& result, bool& isOK) - { - size_t haypos, needlepos; - haysize -= needlesize; +/* binary search in memory */ +void memsearch(const char* hay, size_t haysize, const char* needle, size_t needlesize, size_t& result, bool& isOK) +{ + size_t haypos, needlepos; + haysize -= needlesize; - for (haypos = 0; haypos <= haysize; haypos++) + for (haypos = 0; haypos <= haysize; haypos++) + { + for (needlepos = 0; needlepos < needlesize; needlepos++) { - for (needlepos = 0; needlepos < needlesize; needlepos++) + if (hay[haypos + needlepos] != needle[needlepos]) { - if (hay[haypos + needlepos] != needle[needlepos]) - { - // Next character in haystack. - break; - } - } - if (needlepos == needlesize) - { - result = haypos; - isOK = true; - return; + // Next character in haystack. + break; } } - - isOK = false; + if (needlepos == needlesize) + { + result = haypos; + isOK = true; + return; + } } - class PromiseReceive; + isOK = false; +} - std::shared_ptr setupPromiseReceive(const TcpConnection::Ptr& session); +class PromiseReceive; - class PromiseReceive : public std::enable_shared_from_this +std::shared_ptr setupPromiseReceive(const TcpConnection::Ptr& session); + +class PromiseReceive : public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + using Handle = std::function; + + PromiseReceive::Ptr receive(size_t len, Handle handle) { - public: - using Ptr = std::shared_ptr; - using Handle = std::function; + return receive(std::make_shared(len), std::move(handle)); + } - PromiseReceive::Ptr receive(size_t len, Handle handle) + PromiseReceive::Ptr receive(std::shared_ptr len, Handle handle) + { + return helpReceive(std::move(len), "", std::move(handle)); + } + + PromiseReceive::Ptr receiveUntil(std::string str, Handle handle) + { + if (str.empty()) { - return receive(std::make_shared(len), std::move(handle)); + throw std::runtime_error("str is empty"); } - PromiseReceive::Ptr receive(std::shared_ptr len, Handle handle) - { - return helpReceive(std::move(len), "", std::move(handle)); - } + return helpReceive(nullptr, std::move(str), std::move(handle)); + } - PromiseReceive::Ptr receiveUntil(std::string str, Handle handle) +private: + PromiseReceive::Ptr helpReceive(std::shared_ptr len, std::string str, Handle handle) + { + auto pr = std::make_shared(); + pr->len = std::move(len); + pr->str = std::move(str); + pr->handle = std::move(handle); + mPendingReceives.push_back(std::move(pr)); + + return shared_from_this(); + } + + size_t process(const char* buffer, const size_t len) + { + size_t procLen = 0; + + while (!mPendingReceives.empty() && len >= procLen) { - if (str.empty()) + auto pendingReceive = mPendingReceives.front(); + if (pendingReceive->len != nullptr) { - throw std::runtime_error("str is empty"); - } - - return helpReceive(nullptr, std::move(str), std::move(handle)); - } - - private: - PromiseReceive::Ptr helpReceive(std::shared_ptr len, std::string str, Handle handle) - { - auto pr = std::make_shared(); - pr->len = std::move(len); - pr->str = std::move(str); - pr->handle = std::move(handle); - mPendingReceives.push_back(std::move(pr)); - - return shared_from_this(); - } - - size_t process(const char* buffer, const size_t len) - { - size_t procLen = 0; - - while (!mPendingReceives.empty() && len >= procLen) - { - auto pendingReceive = mPendingReceives.front(); - if (pendingReceive->len != nullptr) - { - const auto tryReceiveLen = *pendingReceive->len; - if ((len - procLen) < tryReceiveLen) - { - break; - } - - mPendingReceives.pop_front(); - procLen += tryReceiveLen; - if (pendingReceive->handle(buffer + procLen - tryReceiveLen, tryReceiveLen) && tryReceiveLen > 0) - { - mPendingReceives.push_front(pendingReceive); - } - } - else if (!pendingReceive->str.empty()) - { - size_t pos = 0; - bool isOK = false; - auto data = buffer + procLen; - memsearch(buffer + procLen, - len - procLen, - pendingReceive->str.c_str(), - pendingReceive->str.size(), - pos, - isOK); - - if (!isOK) - { - break; - } - - mPendingReceives.pop_front(); - procLen += (pos + pendingReceive->str.size()); - if (pendingReceive->handle(data, pos)) - { - mPendingReceives.push_front(pendingReceive); - } - } - else + const auto tryReceiveLen = *pendingReceive->len; + if ((len - procLen) < tryReceiveLen) { break; } - } - return procLen; + mPendingReceives.pop_front(); + procLen += tryReceiveLen; + if (pendingReceive->handle(buffer + procLen - tryReceiveLen, tryReceiveLen) && tryReceiveLen > 0) + { + mPendingReceives.push_front(pendingReceive); + } + } + else if (!pendingReceive->str.empty()) + { + size_t pos = 0; + bool isOK = false; + auto data = buffer + procLen; + memsearch(buffer + procLen, + len - procLen, + pendingReceive->str.c_str(), + pendingReceive->str.size(), + pos, + isOK); + + if (!isOK) + { + break; + } + + mPendingReceives.pop_front(); + procLen += (pos + pendingReceive->str.size()); + if (pendingReceive->handle(data, pos)) + { + mPendingReceives.push_front(pendingReceive); + } + } + else + { + break; + } } - private: - struct PendingReceive - { - std::shared_ptr len; - std::string str; - Handle handle; - }; + return procLen; + } - std::deque> mPendingReceives; - - friend std::shared_ptr setupPromiseReceive(const TcpConnection::Ptr& session); +private: + struct PendingReceive + { + std::shared_ptr len; + std::string str; + Handle handle; }; - std::shared_ptr setupPromiseReceive(const TcpConnection::Ptr& session) - { - auto promiseReceive = std::make_shared(); - session->setDataCallback([promiseReceive](brynet::base::BasePacketReader& reader) { - auto procLen = promiseReceive->process(reader.begin(), reader.size()); - reader.addPos(procLen); - reader.savePos(); - }); + std::deque> mPendingReceives; - return promiseReceive; - } + friend std::shared_ptr setupPromiseReceive(const TcpConnection::Ptr& session); +}; -} } +std::shared_ptr setupPromiseReceive(const TcpConnection::Ptr& session) +{ + auto promiseReceive = std::make_shared(); + session->setDataCallback([promiseReceive](brynet::base::BasePacketReader& reader) { + auto procLen = promiseReceive->process(reader.begin(), reader.size()); + reader.addPos(procLen); + reader.savePos(); + }); + + return promiseReceive; +} + +}}// namespace brynet::net diff --git a/libs/brynet/net/SSLHelper.hpp b/libs/brynet/net/SSLHelper.hpp index fb2598d..fecfcc4 100644 --- a/libs/brynet/net/SSLHelper.hpp +++ b/libs/brynet/net/SSLHelper.hpp @@ -1,23 +1,22 @@ #pragma once -#include -#include -#include -#include -#include - +#include #include #include -#include +#include +#include +#include +#include +#include #ifdef BRYNET_USE_OPENSSL -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif -#include #include -#ifdef __cplusplus +#include +#ifdef __cplusplus } #endif @@ -28,147 +27,149 @@ namespace brynet { namespace net { #ifdef BRYNET_USE_OPENSSL #ifndef CRYPTO_THREADID_set_callback - static void cryptoSetThreadIDCallback(CRYPTO_THREADID* id) - { +static void cryptoSetThreadIDCallback(CRYPTO_THREADID* id) +{ #ifdef BRYNET_PLATFORM_WINDOWS - CRYPTO_THREADID_set_numeric(id, - static_cast(GetCurrentThreadId())); + CRYPTO_THREADID_set_numeric(id, + static_cast(GetCurrentThreadId())); #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - CRYPTO_THREADID_set_numeric(id, - static_cast(pthread_self())); + CRYPTO_THREADID_set_numeric(id, + static_cast(pthread_self())); #endif - } +} #endif #ifndef CRYPTO_set_locking_callback - static std::unordered_map> cryptoLocks; - static void cryptoLockingCallback(int mode, - int type, - const char* file, int line) +static std::unordered_map> cryptoLocks; +static void cryptoLockingCallback(int mode, + int type, + const char* file, int line) +{ + (void) file; + (void) line; + if (mode & CRYPTO_LOCK) { - (void)file; - (void)line; - if (mode & CRYPTO_LOCK) - { - cryptoLocks[type]->lock(); - } - else if (mode & CRYPTO_UNLOCK) - { - cryptoLocks[type]->unlock(); - } + cryptoLocks[type]->lock(); } + else if (mode & CRYPTO_UNLOCK) + { + cryptoLocks[type]->unlock(); + } +} #endif - static std::once_flag initCryptoThreadSafeSupportOnceFlag; - static void InitCryptoThreadSafeSupport() - { +static std::once_flag initCryptoThreadSafeSupportOnceFlag; +static void InitCryptoThreadSafeSupport() +{ #ifndef CRYPTO_THREADID_set_callback - CRYPTO_THREADID_set_callback(cryptoSetThreadIDCallback); + CRYPTO_THREADID_set_callback(cryptoSetThreadIDCallback); #endif #ifndef CRYPTO_set_locking_callback - for (int i = 0; i < CRYPTO_num_locks(); i++) - { - cryptoLocks[i] = std::make_shared(); - } - CRYPTO_set_locking_callback(cryptoLockingCallback); + for (int i = 0; i < CRYPTO_num_locks(); i++) + { + cryptoLocks[i] = std::make_shared(); + } + CRYPTO_set_locking_callback(cryptoLockingCallback); #endif +} +#endif + +class SSLHelper : public brynet::base::NonCopyable, + public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + +#ifdef BRYNET_USE_OPENSSL + bool initSSL(const std::string& certificate, + const std::string& privatekey) + { + std::call_once(initCryptoThreadSafeSupportOnceFlag, + InitCryptoThreadSafeSupport); + + if (mOpenSSLCTX != nullptr) + { + return false; + } + if (certificate.empty() || privatekey.empty()) + { + return false; + } + + mOpenSSLCTX = SSL_CTX_new(SSLv23_method()); + SSL_CTX_set_client_CA_list(mOpenSSLCTX, + SSL_load_client_CA_file(certificate.c_str())); + SSL_CTX_set_verify_depth(mOpenSSLCTX, 10); + + if (SSL_CTX_use_certificate_chain_file(mOpenSSLCTX, + certificate.c_str()) <= 0) + { + SSL_CTX_free(mOpenSSLCTX); + mOpenSSLCTX = nullptr; + return false; + } + + if (SSL_CTX_use_PrivateKey_file(mOpenSSLCTX, + privatekey.c_str(), + SSL_FILETYPE_PEM) <= 0) + { + SSL_CTX_free(mOpenSSLCTX); + mOpenSSLCTX = nullptr; + return false; + } + + if (!SSL_CTX_check_private_key(mOpenSSLCTX)) + { + SSL_CTX_free(mOpenSSLCTX); + mOpenSSLCTX = nullptr; + return false; + } + + return true; + } + + void destroySSL() + { + if (mOpenSSLCTX != nullptr) + { + SSL_CTX_free(mOpenSSLCTX); + mOpenSSLCTX = nullptr; + } + } + + SSL_CTX* getOpenSSLCTX() + { + return mOpenSSLCTX; } #endif - - class SSLHelper : public brynet::base::NonCopyable, - public std::enable_shared_from_this + static Ptr Create() { - public: - using Ptr = std::shared_ptr; + class make_shared_enabler : public SSLHelper + { + }; + return std::make_shared(); + } +protected: + SSLHelper() BRYNET_NOEXCEPT + { #ifdef BRYNET_USE_OPENSSL - bool initSSL(const std::string& certificate, - const std::string& privatekey) - { - std::call_once(initCryptoThreadSafeSupportOnceFlag, - InitCryptoThreadSafeSupport); - - if (mOpenSSLCTX != nullptr) - { - return false; - } - if (certificate.empty() || privatekey.empty()) - { - return false; - } - - mOpenSSLCTX = SSL_CTX_new(SSLv23_method()); - SSL_CTX_set_client_CA_list(mOpenSSLCTX, - SSL_load_client_CA_file(certificate.c_str())); - SSL_CTX_set_verify_depth(mOpenSSLCTX, 10); - - if (SSL_CTX_use_certificate_chain_file(mOpenSSLCTX, - certificate.c_str()) <= 0) - { - SSL_CTX_free(mOpenSSLCTX); - mOpenSSLCTX = nullptr; - return false; - } - - if (SSL_CTX_use_PrivateKey_file(mOpenSSLCTX, - privatekey.c_str(), - SSL_FILETYPE_PEM) <= 0) - { - SSL_CTX_free(mOpenSSLCTX); - mOpenSSLCTX = nullptr; - return false; - } - - if (!SSL_CTX_check_private_key(mOpenSSLCTX)) - { - SSL_CTX_free(mOpenSSLCTX); - mOpenSSLCTX = nullptr; - return false; - } - - return true; - } - - void destroySSL() - { - if (mOpenSSLCTX != nullptr) - { - SSL_CTX_free(mOpenSSLCTX); - mOpenSSLCTX = nullptr; - } - } - - SSL_CTX* getOpenSSLCTX() - { - return mOpenSSLCTX; - } + mOpenSSLCTX = nullptr; #endif - static Ptr Create() - { - class make_shared_enabler : public SSLHelper {}; - return std::make_shared(); - } + } - protected: - SSLHelper() BRYNET_NOEXCEPT - { + virtual ~SSLHelper() BRYNET_NOEXCEPT + { #ifdef BRYNET_USE_OPENSSL - mOpenSSLCTX = nullptr; + destroySSL(); #endif - } + } - virtual ~SSLHelper() BRYNET_NOEXCEPT - { +private: #ifdef BRYNET_USE_OPENSSL - destroySSL(); + SSL_CTX* mOpenSSLCTX; #endif - } +}; - private: -#ifdef BRYNET_USE_OPENSSL - SSL_CTX* mOpenSSLCTX; -#endif - }; - -} } +}}// namespace brynet::net diff --git a/libs/brynet/net/SendableMsg.hpp b/libs/brynet/net/SendableMsg.hpp new file mode 100644 index 0000000..5a265f6 --- /dev/null +++ b/libs/brynet/net/SendableMsg.hpp @@ -0,0 +1,60 @@ +#include +#include + +namespace brynet { namespace net { + +class SendableMsg +{ +public: + using Ptr = std::shared_ptr; + + 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(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(buffer, len); +} + +static SendableMsg::Ptr MakeStringMsg(const std::string& buffer) +{ + return std::make_shared(buffer); +} + +static SendableMsg::Ptr MakeStringMsg(std::string&& buffer) +{ + return std::make_shared(std::move(buffer)); +} + +}}// namespace brynet::net \ No newline at end of file diff --git a/libs/brynet/net/Socket.hpp b/libs/brynet/net/Socket.hpp index 738f507..0c22da5 100644 --- a/libs/brynet/net/Socket.hpp +++ b/libs/brynet/net/Socket.hpp @@ -1,230 +1,226 @@ #pragma once -#include -#include -#include -#include - #include #include +#include +#include +#include +#include namespace brynet { namespace net { - class TcpConnection; +class TcpConnection; - class UniqueFd final : public brynet::base::NonCopyable +class UniqueFd final : public brynet::base::NonCopyable +{ +public: + explicit UniqueFd(BrynetSocketFD fd) + : mFD(fd) + {} + + ~UniqueFd() + { + brynet::net::base::SocketClose(mFD); + } + + UniqueFd(const UniqueFd& other) = delete; + UniqueFd& operator=(const UniqueFd& other) = delete; + + BrynetSocketFD getFD() const + { + return mFD; + } + +private: + BrynetSocketFD mFD; +}; + +class TcpSocket : public brynet::base::NonCopyable +{ +private: + class TcpSocketDeleter { public: - explicit UniqueFd(BrynetSocketFD fd) - : - mFD(fd) - {} - - ~UniqueFd() + void operator()(TcpSocket* ptr) const { - brynet::net::base::SocketClose(mFD); + delete ptr; } - - UniqueFd(const UniqueFd& other) = delete; - UniqueFd& operator=(const UniqueFd& other) = delete; - - BrynetSocketFD getFD() const - { - return mFD; - } - - private: - BrynetSocketFD mFD; }; - class TcpSocket : public brynet::base::NonCopyable +public: + using Ptr = std::unique_ptr; + +public: + static Ptr Create(BrynetSocketFD fd, bool serverSide) { - private: - class TcpSocketDeleter + class make_unique_enabler : public TcpSocket { public: - void operator()(TcpSocket* ptr) const - { - delete ptr; - } + make_unique_enabler(BrynetSocketFD fd, bool serverSide) + : TcpSocket(fd, serverSide) + {} }; - public: - using Ptr = std::unique_ptr; + return Ptr(new make_unique_enabler(fd, serverSide)); + } + +public: + void setNodelay() const + { + brynet::net::base::SocketNodelay(mFD); + } + + bool setNonblock() const + { + return brynet::net::base::SocketNonblock(mFD); + } + + void setSendSize(int sdSize) const + { + brynet::net::base::SocketSetSendSize(mFD, sdSize); + } + + void setRecvSize(int rdSize) const + { + brynet::net::base::SocketSetRecvSize(mFD, rdSize); + } + + std::string getRemoteIP() const + { + return brynet::net::base::GetIPOfSocket(mFD); + } + + bool isServerSide() const + { + return mServerSide; + } + +protected: + TcpSocket(BrynetSocketFD fd, bool serverSide) + : mFD(fd), + mServerSide(serverSide) + { + } + + virtual ~TcpSocket() + { + brynet::net::base::SocketClose(mFD); + } + + BrynetSocketFD getFD() const + { + return mFD; + } + +private: + const BrynetSocketFD mFD; + const bool mServerSide; + + friend class TcpConnection; +}; + +class EintrError : public std::exception +{ +}; + +class AcceptError : public std::runtime_error +{ +public: + explicit AcceptError(int errorCode) + : std::runtime_error(std::to_string(errorCode)), + mErrorCode(errorCode) + {} + + int getErrorCode() const + { + return mErrorCode; + } + +private: + int mErrorCode; +}; + +class ListenSocket : public brynet::base::NonCopyable +{ +private: + class ListenSocketDeleter + { public: - static Ptr Create(BrynetSocketFD fd, bool serverSide) + void operator()(ListenSocket* ptr) const { - class make_unique_enabler : public TcpSocket + delete ptr; + } + }; + +public: + using Ptr = std::unique_ptr; + +public: + TcpSocket::Ptr accept() + { + const auto clientFD = brynet::net::base::Accept(mFD, nullptr, nullptr); + if (clientFD == BRYNET_INVALID_SOCKET) + { +#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + if (BRYNET_ERRNO == EMFILE) { - public: - make_unique_enabler(BrynetSocketFD fd, bool serverSide) - : - TcpSocket(fd, serverSide) - {} - }; - - return Ptr(new make_unique_enabler(fd, serverSide)); + // Thanks libev and muduo. + // Read the section named "The special problem of + // accept()ing when you can't" in libev's doc. + // By Marc Lehmann, author of libev. + mIdle.reset(); + TcpSocket::Create(brynet::net::base::Accept(mFD, nullptr, nullptr), true); + mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true); + } +#endif + if (BRYNET_ERRNO == EINTR) + { + throw EintrError(); + } + else + { + throw AcceptError(BRYNET_ERRNO); + } } - public: - void setNodelay() const - { - brynet::net::base::SocketNodelay(mFD); - } + return TcpSocket::Create(clientFD, true); + } - bool setNonblock() const - { - return brynet::net::base::SocketNonblock(mFD); - } - - void setSendSize(int sdSize) const - { - brynet::net::base::SocketSetSendSize(mFD, sdSize); - } - - void setRecvSize(int rdSize) const - { - brynet::net::base::SocketSetRecvSize(mFD, rdSize); - } - - std::string getRemoteIP() const - { - return brynet::net::base::GetIPOfSocket(mFD); - } - - bool isServerSide() const - { - return mServerSide; - } - - protected: - TcpSocket(BrynetSocketFD fd, bool serverSide) - : - mFD(fd), - mServerSide(serverSide) - { - } - - virtual ~TcpSocket() - { - brynet::net::base::SocketClose(mFD); - } - - BrynetSocketFD getFD() const - { - return mFD; - } - - private: - const BrynetSocketFD mFD; - const bool mServerSide; - - friend class TcpConnection; - }; - - class EintrError : public std::exception +public: + static Ptr Create(BrynetSocketFD fd) { - }; - - class AcceptError : public std::runtime_error - { - public: - explicit AcceptError(int errorCode) - : - std::runtime_error(std::to_string(errorCode)), - mErrorCode(errorCode) - {} - - int getErrorCode() const - { - return mErrorCode; - } - - private: - int mErrorCode; - }; - - class ListenSocket : public brynet::base::NonCopyable - { - private: - class ListenSocketDeleter + class make_unique_enabler : public ListenSocket { public: - void operator()(ListenSocket* ptr) const - { - delete ptr; - } + explicit make_unique_enabler(BrynetSocketFD fd) + : ListenSocket(fd) + {} }; - public: - using Ptr = std::unique_ptr; - public: - TcpSocket::Ptr accept() - { - const auto clientFD = brynet::net::base::Accept(mFD, nullptr, nullptr); - if (clientFD == BRYNET_INVALID_SOCKET) - { + return Ptr(new make_unique_enabler(fd)); + } + +protected: + explicit ListenSocket(BrynetSocketFD fd) + : mFD(fd) + { #if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - if (BRYNET_ERRNO == EMFILE) - { - // Thanks libev and muduo. - // Read the section named "The special problem of - // accept()ing when you can't" in libev's doc. - // By Marc Lehmann, author of libev. - mIdle.reset(); - TcpSocket::Create(brynet::net::base::Accept(mFD, nullptr, nullptr), true); - mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true); - } + mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true); #endif - if (BRYNET_ERRNO == EINTR) - { - throw EintrError(); - } - else - { - throw AcceptError(BRYNET_ERRNO); - } - } + } - return TcpSocket::Create(clientFD, true); - } + virtual ~ListenSocket() + { + brynet::net::base::SocketClose(mFD); + } - public: - static Ptr Create(BrynetSocketFD fd) - { - class make_unique_enabler : public ListenSocket - { - public: - explicit make_unique_enabler(BrynetSocketFD fd) - : ListenSocket(fd) - {} - }; - - return Ptr(new make_unique_enabler(fd)); - } - - protected: - explicit ListenSocket(BrynetSocketFD fd) - : - mFD(fd) - { +private: + const BrynetSocketFD mFD; #if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true); -#endif - } - - virtual ~ListenSocket() - { - brynet::net::base::SocketClose(mFD); - } - - private: - const BrynetSocketFD mFD; -#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - brynet::net::TcpSocket::Ptr mIdle; + brynet::net::TcpSocket::Ptr mIdle; #endif - friend class TcpConnection; - }; + friend class TcpConnection; +}; -} } \ No newline at end of file +}}// namespace brynet::net diff --git a/libs/brynet/net/SocketLibFunction.hpp b/libs/brynet/net/SocketLibFunction.hpp index 97df382..5ade42c 100644 --- a/libs/brynet/net/SocketLibFunction.hpp +++ b/libs/brynet/net/SocketLibFunction.hpp @@ -1,329 +1,339 @@ #pragma once #include -#include + #include +#include namespace brynet { namespace net { namespace base { - static bool InitSocket() - { - bool ret = true; +static bool InitSocket() +{ + bool ret = true; #ifdef BRYNET_PLATFORM_WINDOWS - static WSADATA g_WSAData; - static bool WinSockIsInit = false; - if (WinSockIsInit) - { - return true; - } - if (WSAStartup(MAKEWORD(2, 2), &g_WSAData) == 0) - { - WinSockIsInit = true; - } - else - { - ret = false; - } + static WSADATA g_WSAData; + static bool WinSockIsInit = false; + if (WinSockIsInit) + { + return true; + } + if (WSAStartup(MAKEWORD(2, 2), &g_WSAData) == 0) + { + WinSockIsInit = true; + } + else + { + ret = false; + } #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - signal(SIGPIPE, SIG_IGN); + signal(SIGPIPE, SIG_IGN); #endif - return ret; - } + return ret; +} - static void DestroySocket() - { +static void DestroySocket() +{ #ifdef BRYNET_PLATFORM_WINDOWS - WSACleanup(); + WSACleanup(); #endif - } +} - static int SocketNodelay(BrynetSocketFD fd) - { - const int flag = 1; - return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag)); - } +static int SocketNodelay(BrynetSocketFD fd) +{ + const int flag = 1; + return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*) &flag, sizeof(flag)); +} - static bool SocketBlock(BrynetSocketFD fd) - { - int err; - unsigned long ul = false; +static bool SocketBlock(BrynetSocketFD fd) +{ + int err; + unsigned long ul = false; #ifdef BRYNET_PLATFORM_WINDOWS - err = ioctlsocket(fd, FIONBIO, &ul); + err = ioctlsocket(fd, FIONBIO, &ul); #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - err = ioctl(fd, FIONBIO, &ul); + err = ioctl(fd, FIONBIO, &ul); #endif - return err != BRYNET_SOCKET_ERROR; - } + return err != BRYNET_SOCKET_ERROR; +} - static bool SocketNonblock(BrynetSocketFD fd) - { - int err; - unsigned long ul = true; +static bool SocketNonblock(BrynetSocketFD fd) +{ + int err; + unsigned long ul = true; #ifdef BRYNET_PLATFORM_WINDOWS - err = ioctlsocket(fd, FIONBIO, &ul); + err = ioctlsocket(fd, FIONBIO, &ul); #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - err = ioctl(fd, FIONBIO, &ul); + err = ioctl(fd, FIONBIO, &ul); #endif - return err != BRYNET_SOCKET_ERROR; - } + return err != BRYNET_SOCKET_ERROR; +} - static int SocketSetSendSize(BrynetSocketFD fd, int sd_size) - { - return ::setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&sd_size, sizeof(sd_size)); - } +static int SocketSetSendSize(BrynetSocketFD fd, int sd_size) +{ + return ::setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*) &sd_size, sizeof(sd_size)); +} - static int SocketSetRecvSize(BrynetSocketFD fd, int rd_size) - { - return ::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&rd_size, sizeof(rd_size)); - } +static int SocketSetRecvSize(BrynetSocketFD fd, int rd_size) +{ + return ::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &rd_size, sizeof(rd_size)); +} - static BrynetSocketFD SocketCreate(int af, int type, int protocol) - { - return ::socket(af, type, protocol); - } - - static void SocketClose(BrynetSocketFD fd) - { +static int SocketSetReusePort(BrynetSocketFD fd) +{ #ifdef BRYNET_PLATFORM_WINDOWS - ::closesocket(fd); -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - ::close(fd); + return 0; +#else + int enable = 1; + return ::setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); #endif - } +} - static BrynetSocketFD Connect(bool isIPV6, const std::string& server_ip, int port) +static BrynetSocketFD SocketCreate(int af, int type, int protocol) +{ + return ::socket(af, type, protocol); +} + +static void SocketClose(BrynetSocketFD fd) +{ +#ifdef BRYNET_PLATFORM_WINDOWS + ::closesocket(fd); +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + ::close(fd); +#endif +} + +static BrynetSocketFD Connect(bool isIPV6, const std::string& server_ip, int port) +{ + InitSocket(); + + struct sockaddr_in ip4Addr = sockaddr_in(); + struct sockaddr_in6 ip6Addr = sockaddr_in6(); + struct sockaddr_in* paddr = &ip4Addr; + int addrLen = sizeof(ip4Addr); + + BrynetSocketFD clientfd = isIPV6 ? SocketCreate(AF_INET6, SOCK_STREAM, 0) : SocketCreate(AF_INET, SOCK_STREAM, 0); + + if (clientfd == BRYNET_INVALID_SOCKET) { - InitSocket(); - - struct sockaddr_in ip4Addr = sockaddr_in(); - struct sockaddr_in6 ip6Addr = sockaddr_in6(); - struct sockaddr_in* paddr = &ip4Addr; - int addrLen = sizeof(ip4Addr); - - BrynetSocketFD clientfd = isIPV6 ? - SocketCreate(AF_INET6, SOCK_STREAM, 0) : - SocketCreate(AF_INET, SOCK_STREAM, 0); - - if (clientfd == BRYNET_INVALID_SOCKET) - { - return clientfd; - } - - bool ptonResult = false; - if (isIPV6) - { - ip6Addr.sin6_family = AF_INET6; - ip6Addr.sin6_port = htons(port); - ptonResult = inet_pton(AF_INET6, - server_ip.c_str(), - &ip6Addr.sin6_addr) > 0; - paddr = (struct sockaddr_in*) & ip6Addr; - addrLen = sizeof(ip6Addr); - } - else - { - ip4Addr.sin_family = AF_INET; - ip4Addr.sin_port = htons(port); - ptonResult = inet_pton(AF_INET, - server_ip.c_str(), - &ip4Addr.sin_addr) > 0; - } - - if (!ptonResult) - { - SocketClose(clientfd); - return BRYNET_INVALID_SOCKET; - } - - while (::connect(clientfd, (struct sockaddr*)paddr, addrLen) < 0) - { - if (EINTR == BRYNET_ERRNO) - { - continue; - } - - SocketClose(clientfd); - return BRYNET_INVALID_SOCKET; - } - return clientfd; } - static BrynetSocketFD Listen(bool isIPV6, const char* ip, int port, int back_num) + bool ptonResult = false; + if (isIPV6) { - InitSocket(); - - struct sockaddr_in ip4Addr = sockaddr_in(); - struct sockaddr_in6 ip6Addr = sockaddr_in6(); - struct sockaddr_in* paddr = &ip4Addr; - int addrLen = sizeof(ip4Addr); - - const auto socketfd = isIPV6 ? - socket(AF_INET6, SOCK_STREAM, 0) : - socket(AF_INET, SOCK_STREAM, 0); - if (socketfd == BRYNET_INVALID_SOCKET) - { - return BRYNET_INVALID_SOCKET; - } - - bool ptonResult = false; - if (isIPV6) - { - ip6Addr.sin6_family = AF_INET6; - ip6Addr.sin6_port = htons(port); - ptonResult = inet_pton(AF_INET6, ip, &ip6Addr.sin6_addr) > 0; - paddr = (struct sockaddr_in*) & ip6Addr; - addrLen = sizeof(ip6Addr); - } - else - { - ip4Addr.sin_family = AF_INET; - ip4Addr.sin_port = htons(port); - ip4Addr.sin_addr.s_addr = INADDR_ANY; - ptonResult = inet_pton(AF_INET, ip, &ip4Addr.sin_addr) > 0; - } - - const int reuseaddr_value = 1; - if (!ptonResult || - ::setsockopt(socketfd, - SOL_SOCKET, - SO_REUSEADDR, - (const char*)&reuseaddr_value, - sizeof(int)) < 0) - { - SocketClose(socketfd); - return BRYNET_INVALID_SOCKET; - } - - const int bindRet = ::bind(socketfd, (struct sockaddr*)paddr, addrLen); - if (bindRet == BRYNET_SOCKET_ERROR || - listen(socketfd, back_num) == BRYNET_SOCKET_ERROR) - { - SocketClose(socketfd); - return BRYNET_INVALID_SOCKET; - } - - return socketfd; + ip6Addr.sin6_family = AF_INET6; + ip6Addr.sin6_port = htons(port); + ptonResult = inet_pton(AF_INET6, + server_ip.c_str(), + &ip6Addr.sin6_addr) > 0; + paddr = (struct sockaddr_in*) &ip6Addr; + addrLen = sizeof(ip6Addr); + } + else + { + ip4Addr.sin_family = AF_INET; + ip4Addr.sin_port = htons(port); + ptonResult = inet_pton(AF_INET, + server_ip.c_str(), + &ip4Addr.sin_addr) > 0; } - static std::string getIPString(const struct sockaddr* sa) + if (!ptonResult) { -#ifdef BRYNET_PLATFORM_WINDOWS - using PAddrType = PVOID; -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - using PAddrType = const void*; -#endif - char tmp[INET6_ADDRSTRLEN] = { 0 }; - switch (sa->sa_family) + SocketClose(clientfd); + return BRYNET_INVALID_SOCKET; + } + + while (::connect(clientfd, (struct sockaddr*) paddr, addrLen) < 0) + { + if (EINTR == BRYNET_ERRNO) { + continue; + } + + SocketClose(clientfd); + return BRYNET_INVALID_SOCKET; + } + + return clientfd; +} + +static BrynetSocketFD Listen(bool isIPV6, const char* ip, int port, int back_num, bool enabledReusePort) +{ + InitSocket(); + + struct sockaddr_in ip4Addr = sockaddr_in(); + struct sockaddr_in6 ip6Addr = sockaddr_in6(); + struct sockaddr_in* paddr = &ip4Addr; + int addrLen = sizeof(ip4Addr); + + const auto socketfd = isIPV6 ? socket(AF_INET6, SOCK_STREAM, 0) : socket(AF_INET, SOCK_STREAM, 0); + if (socketfd == BRYNET_INVALID_SOCKET) + { + return BRYNET_INVALID_SOCKET; + } + + bool ptonResult = false; + if (isIPV6) + { + ip6Addr.sin6_family = AF_INET6; + ip6Addr.sin6_port = htons(port); + ptonResult = inet_pton(AF_INET6, ip, &ip6Addr.sin6_addr) > 0; + paddr = (struct sockaddr_in*) &ip6Addr; + addrLen = sizeof(ip6Addr); + } + else + { + ip4Addr.sin_family = AF_INET; + ip4Addr.sin_port = htons(port); + ip4Addr.sin_addr.s_addr = INADDR_ANY; + ptonResult = inet_pton(AF_INET, ip, &ip4Addr.sin_addr) > 0; + } + + const int reuseaddr_value = 1; + if (!ptonResult || + ::setsockopt(socketfd, + SOL_SOCKET, + SO_REUSEADDR, + (const char*) &reuseaddr_value, + sizeof(int)) < 0) + { + SocketClose(socketfd); + return BRYNET_INVALID_SOCKET; + } + + if (enabledReusePort && SocketSetReusePort(socketfd) < 0) + { + SocketClose(socketfd); + return BRYNET_INVALID_SOCKET; + } + + const int bindRet = ::bind(socketfd, (struct sockaddr*) paddr, addrLen); + if (bindRet == BRYNET_SOCKET_ERROR || + listen(socketfd, back_num) == BRYNET_SOCKET_ERROR) + { + SocketClose(socketfd); + return BRYNET_INVALID_SOCKET; + } + + return socketfd; +} + +static std::string getIPString(const struct sockaddr* sa) +{ +#ifdef BRYNET_PLATFORM_WINDOWS + using PAddrType = PVOID; +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + using PAddrType = const void*; +#endif + char tmp[INET6_ADDRSTRLEN] = {0}; + switch (sa->sa_family) + { case AF_INET: - inet_ntop(AF_INET, (PAddrType)(&(((const struct sockaddr_in*)sa)->sin_addr)), - tmp, sizeof(tmp)); + inet_ntop(AF_INET, (PAddrType)(&(((const struct sockaddr_in*) sa)->sin_addr)), + tmp, sizeof(tmp)); break; case AF_INET6: - inet_ntop(AF_INET6, (PAddrType)(&(((const struct sockaddr_in6*)sa)->sin6_addr)), - tmp, sizeof(tmp)); + inet_ntop(AF_INET6, (PAddrType)(&(((const struct sockaddr_in6*) sa)->sin6_addr)), + tmp, sizeof(tmp)); break; default: return "Unknown AF"; - } - - return tmp; } - static std::string GetIPOfSocket(BrynetSocketFD fd) - { + return tmp; +} + +static std::string GetIPOfSocket(BrynetSocketFD fd) +{ #ifdef BRYNET_PLATFORM_WINDOWS - struct sockaddr name = sockaddr(); - int namelen = sizeof(name); - if (::getpeername(fd, (struct sockaddr*) & name, &namelen) == 0) - { - return getIPString(&name); - } + struct sockaddr name = sockaddr(); + int namelen = sizeof(name); + if (::getpeername(fd, (struct sockaddr*) &name, &namelen) == 0) + { + return getIPString(&name); + } #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - struct sockaddr_in name = sockaddr_in(); - socklen_t namelen = sizeof(name); - if (::getpeername(fd, (struct sockaddr*) & name, &namelen) == 0) - { - return getIPString((const struct sockaddr*) & name); - } + struct sockaddr_in name = sockaddr_in(); + socklen_t namelen = sizeof(name); + if (::getpeername(fd, (struct sockaddr*) &name, &namelen) == 0) + { + return getIPString((const struct sockaddr*) &name); + } #endif - return ""; + return ""; +} + +static int SocketSend(BrynetSocketFD fd, const char* buffer, int len) +{ + int transnum = ::send(fd, buffer, len, 0); + if (transnum < 0 && BRYNET_EWOULDBLOCK == BRYNET_ERRNO) + { + transnum = 0; } - static int SocketSend(BrynetSocketFD fd, const char* buffer, int len) - { - int transnum = ::send(fd, buffer, len, 0); - if (transnum < 0 && BRYNET_EWOULDBLOCK == BRYNET_ERRNO) - { - transnum = 0; - } + /* send error if transnum < 0 */ + return transnum; +} - /* send error if transnum < 0 */ - return transnum; - } +static BrynetSocketFD Accept(BrynetSocketFD listenSocket, struct sockaddr* addr, socklen_t* addrLen) +{ + return ::accept(listenSocket, addr, addrLen); +} - static BrynetSocketFD Accept(BrynetSocketFD listenSocket, struct sockaddr* addr, socklen_t* addrLen) +static struct sockaddr_in6 getPeerAddr(BrynetSocketFD sockfd) +{ + struct sockaddr_in6 peeraddr = sockaddr_in6(); + auto addrlen = static_cast(sizeof peeraddr); + if (::getpeername(sockfd, (struct sockaddr*) (&peeraddr), &addrlen) < 0) { - return ::accept(listenSocket, addr, addrLen); - } - - static struct sockaddr_in6 getPeerAddr(BrynetSocketFD sockfd) - { - struct sockaddr_in6 peeraddr = sockaddr_in6(); - auto addrlen = static_cast(sizeof peeraddr); - if (::getpeername(sockfd, (struct sockaddr*)(&peeraddr), &addrlen) < 0) - { - return peeraddr; - } return peeraddr; } + return peeraddr; +} - static struct sockaddr_in6 getLocalAddr(BrynetSocketFD sockfd) +static struct sockaddr_in6 getLocalAddr(BrynetSocketFD sockfd) +{ + struct sockaddr_in6 localaddr = sockaddr_in6(); + auto addrlen = static_cast(sizeof localaddr); + if (::getsockname(sockfd, (struct sockaddr*) (&localaddr), &addrlen) < 0) { - struct sockaddr_in6 localaddr = sockaddr_in6(); - auto addrlen = static_cast(sizeof localaddr); - if (::getsockname(sockfd, (struct sockaddr*)(&localaddr), &addrlen) < 0) - { - return localaddr; - } return localaddr; } + return localaddr; +} - static bool IsSelfConnect(BrynetSocketFD fd) +static bool IsSelfConnect(BrynetSocketFD fd) +{ + struct sockaddr_in6 localaddr = getLocalAddr(fd); + struct sockaddr_in6 peeraddr = getPeerAddr(fd); + + if (localaddr.sin6_family == AF_INET) { - struct sockaddr_in6 localaddr = getLocalAddr(fd); - struct sockaddr_in6 peeraddr = getPeerAddr(fd); - - if (localaddr.sin6_family == AF_INET) - { - const struct sockaddr_in* laddr4 = reinterpret_cast(&localaddr); - const struct sockaddr_in* raddr4 = reinterpret_cast(&peeraddr); - return laddr4->sin_port == raddr4->sin_port - && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr; - } - else if (localaddr.sin6_family == AF_INET6) - { -#ifdef BRYNET_PLATFORM_WINDOWS - return localaddr.sin6_port == peeraddr.sin6_port - && memcmp(&localaddr.sin6_addr.u.Byte, - &peeraddr.sin6_addr.u.Byte, - sizeof localaddr.sin6_addr.u.Byte) == 0; -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - return localaddr.sin6_port == peeraddr.sin6_port - && memcmp(&localaddr.sin6_addr.s6_addr, - &peeraddr.sin6_addr.s6_addr, - sizeof localaddr.sin6_addr.s6_addr) == 0; -#endif - } - else - { - return false; - } + const struct sockaddr_in* laddr4 = reinterpret_cast(&localaddr); + const struct sockaddr_in* raddr4 = reinterpret_cast(&peeraddr); + return laddr4->sin_port == raddr4->sin_port && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr; } + else if (localaddr.sin6_family == AF_INET6) + { +#ifdef BRYNET_PLATFORM_WINDOWS + return localaddr.sin6_port == peeraddr.sin6_port && memcmp(&localaddr.sin6_addr.u.Byte, + &peeraddr.sin6_addr.u.Byte, + sizeof localaddr.sin6_addr.u.Byte) == 0; +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + return localaddr.sin6_port == peeraddr.sin6_port && memcmp(&localaddr.sin6_addr.s6_addr, + &peeraddr.sin6_addr.s6_addr, + sizeof localaddr.sin6_addr.s6_addr) == 0; +#endif + } + else + { + return false; + } +} -} } } +}}}// namespace brynet::net::base diff --git a/libs/brynet/net/SocketLibTypes.hpp b/libs/brynet/net/SocketLibTypes.hpp index 0a881de..59ae25f 100644 --- a/libs/brynet/net/SocketLibTypes.hpp +++ b/libs/brynet/net/SocketLibTypes.hpp @@ -3,47 +3,48 @@ #include #ifdef BRYNET_PLATFORM_WINDOWS -#include +#define WIN32_LEAN_AND_MEAN #include -#include #include #include +#include +#include #elif defined BRYNET_PLATFORM_LINUX +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include #include +#include #elif defined BRYNET_PLATFORM_DARWIN -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include +#include #include +#include +#include +#include #include +#include #else #error "Unsupported OS, please commit an issuse." diff --git a/libs/brynet/net/TcpConnection.hpp b/libs/brynet/net/TcpConnection.hpp index af9654a..0d0155d 100644 --- a/libs/brynet/net/TcpConnection.hpp +++ b/libs/brynet/net/TcpConnection.hpp @@ -1,34 +1,34 @@ 锘#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include #include +#include #include +#include #include -#include +#include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef BRYNET_USE_OPENSSL -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif -#include #include -#ifdef __cplusplus +#include +#ifdef __cplusplus } #endif @@ -36,1230 +36,1199 @@ extern "C" { namespace brynet { namespace net { - class SendableMsg +class TcpConnection : public Channel, + public brynet::base::NonCopyable, + public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + + using EnterCallback = std::function; + using DataCallback = std::function; + using DisconnectedCallback = std::function; + using PacketSendedCallback = std::function; + using HighWaterCallback = std::function; + +public: + Ptr static Create(TcpSocket::Ptr socket, + size_t maxRecvBufferSize, + EnterCallback&& enterCallback, + const EventLoop::Ptr& eventLoop, + const SSLHelper::Ptr& sslHelper = nullptr) { - public: - using Ptr = std::shared_ptr; - - 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(std::string buffer) - : - mMsg(std::move(buffer)) - {} - - const void* data() override + class make_shared_enabler : public TcpConnection { - return static_cast(mMsg.data()); - } - size_t size() override - { - return mMsg.size(); - } + public: + make_shared_enabler(TcpSocket::Ptr socket, + size_t maxRecvBufferSize, + EnterCallback&& enterCallback, + EventLoop::Ptr eventLoop) + : TcpConnection(std::move(socket), + maxRecvBufferSize, + std::move(enterCallback), + std::move(eventLoop)) + {} + }; - private: - std::string mMsg; - }; - - static SendableMsg::Ptr MakeStringMsg(const char* buffer, size_t len) - { - return std::make_shared(buffer, len); - } - - static SendableMsg::Ptr MakeStringMsg(std::string buffer) - { - return std::make_shared(std::move(buffer)); - } - - class TcpConnection : public Channel, - public brynet::base::NonCopyable, - public std::enable_shared_from_this - { - public: - using Ptr = std::shared_ptr; - - using EnterCallback = std::function; - using DataCallback = std::function; - using DisconnectedCallback = std::function; - using PacketSendedCallback = std::function; - using HighWaterCallback = std::function; - - public: - Ptr static Create(TcpSocket::Ptr socket, - size_t maxRecvBufferSize, - EnterCallback&& enterCallback, - const EventLoop::Ptr& eventLoop, - const SSLHelper::Ptr& sslHelper = nullptr) - { - class make_shared_enabler : public TcpConnection - { - public: - make_shared_enabler(TcpSocket::Ptr socket, - size_t maxRecvBufferSize, - EnterCallback&& enterCallback, - EventLoop::Ptr eventLoop) - : - TcpConnection(std::move(socket), - maxRecvBufferSize, - std::move(enterCallback), - std::move(eventLoop)) - {} - }; - - const auto isServerSide = socket->isServerSide(); - auto session = std::make_shared( - std::move(socket), - maxRecvBufferSize, - std::move(enterCallback), - eventLoop); - (void)isServerSide; + const auto isServerSide = socket->isServerSide(); + auto session = std::make_shared( + std::move(socket), + maxRecvBufferSize, + std::move(enterCallback), + eventLoop); + (void) isServerSide; #ifdef BRYNET_USE_OPENSSL - if(sslHelper != nullptr) + if (sslHelper != nullptr) + { + if (isServerSide) { - if (isServerSide) + if (sslHelper->getOpenSSLCTX() == nullptr || + !session->initAcceptSSL(sslHelper->getOpenSSLCTX())) { - if (sslHelper->getOpenSSLCTX() == nullptr || - !session->initAcceptSSL(sslHelper->getOpenSSLCTX())) - { - throw std::runtime_error("init ssl failed"); - } + throw std::runtime_error("init ssl failed"); } - else - { - if (!session->initConnectSSL()) - { - throw std::runtime_error("init ssl failed"); - } - } - } -#else - if (sslHelper != nullptr) - { - throw std::runtime_error("not enable ssl"); - } -#endif - - eventLoop->runAsyncFunctor([session]() - { - session->onEnterEventLoop(); - }); - return session; - } - - const EventLoop::Ptr& getEventLoop() const - { - return mEventLoop; - } - - //TODO::濡傛灉鎵灞濫ventLoop宸茬粡娌℃湁宸ヤ綔锛屽垯鍙兘瀵艰嚧鍐呭瓨鏃犻檺澶э紝鍥犱负鎵鎶曢掔殑璇锋眰閮芥病鏈夊緱鍒板鐞 - void send( - const SendableMsg::Ptr& msg, - PacketSendedCallback&& callback = nullptr - ) - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([sharedThis, msg, callback]() mutable - { - if(sharedThis->mAlreadyClose) - { - return; - } - - const auto len = msg->size(); - sharedThis->mSendingMsgSize += len; - sharedThis->mSendList.emplace_back(PendingPacket{ - std::move(msg), - len, - std::move(callback) }); - sharedThis->runAfterFlush(); - - if(sharedThis->mSendingMsgSize > sharedThis->mHighWaterSize && - sharedThis->mHighWaterCallback != nullptr) - { - sharedThis->mHighWaterCallback(); - } - }); - } - - void send( - const char* buffer, - size_t len, - PacketSendedCallback&& callback = nullptr) - { - send(MakeStringMsg(buffer, len), std::move(callback)); - } - - void send( - std::string buffer, - PacketSendedCallback&& callback = nullptr) - { - send(MakeStringMsg(std::move(buffer)), std::move(callback)); - } - - // setDataCallback(std::function锛 - template - void setDataCallback(Callback&& cb) - { - verifyArgType(cb, &Callback::operator()); - - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([sharedThis, cb]() mutable - { - sharedThis->mDataCallback = cb; - sharedThis->processRecvMessage(); - }); - } - - void setDisConnectCallback(DisconnectedCallback&& cb) - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([sharedThis, cb]() mutable - { - sharedThis->mDisConnectCallback = std::move(cb); - }); - } - - /* if checkTime is zero, will cancel check heartbeat */ - void setHeartBeat(std::chrono::nanoseconds checkTime) - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([sharedThis, checkTime]() - { - if (sharedThis->mTimer.lock() != nullptr) - { - sharedThis->mTimer.lock()->cancel(); - sharedThis->mTimer.reset(); - } - - sharedThis->mCheckTime = checkTime; - sharedThis->startPingCheckTimer(); - }); - } - - void setHighWaterCallback(HighWaterCallback cb, size_t size) - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([=]() mutable - { - sharedThis->mHighWaterCallback = std::move(cb); - sharedThis->mHighWaterSize = size; - }); - } - - void postShrinkReceiveBuffer() - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([=]() - { - mEventLoop->runFunctorAfterLoop([=]() - { - sharedThis->shrinkReceiveBuffer(); - }); - }); - } - - void postDisConnect() - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([sharedThis]() - { - sharedThis->procCloseInLoop(); - }); - } - - void postShutdown() - { - auto sharedThis = shared_from_this(); - mEventLoop->runAsyncFunctor([sharedThis]() - { - sharedThis->mEventLoop->runFunctorAfterLoop([sharedThis]() - { - sharedThis->procShutdownInLoop(); - }); - }); - } - - const std::string& getIP() const - { - return mIP; - } - - protected: - TcpConnection(TcpSocket::Ptr socket, - size_t maxRecvBufferSize, - EnterCallback&& enterCallback, - EventLoop::Ptr eventLoop) BRYNET_NOEXCEPT - : -#ifdef BRYNET_PLATFORM_WINDOWS - mOvlRecv(port::Win::OverlappedType::OverlappedRecv), - mOvlSend(port::Win::OverlappedType::OverlappedSend), - mPostClose(false), -#endif - mIP(socket->getRemoteIP()), - mSocket(std::move(socket)), - mEventLoop(std::move(eventLoop)), - mAlreadyClose(false), - mMaxRecvBufferSize(maxRecvBufferSize), - mSendingMsgSize(0), - mEnterCallback(std::move(enterCallback)), - mHighWaterSize(0) - { - mRecvData = false; - mCheckTime = std::chrono::steady_clock::duration::zero(); - mIsPostFlush = false; - - mCanWrite = true; - -#ifdef BRYNET_PLATFORM_WINDOWS - mPostRecvCheck = false; - mPostWriteCheck = false; -#endif - growRecvBuffer(); - -#ifdef BRYNET_USE_OPENSSL - mSSLCtx = nullptr; - mSSL = nullptr; - mIsHandsharked = false; -#endif - } - - ~TcpConnection() BRYNET_NOEXCEPT override - { -#ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr) - { - SSL_free(mSSL); - mSSL = nullptr; - } - if (mSSLCtx != nullptr) - { - SSL_CTX_free(mSSLCtx); - mSSLCtx = nullptr; - } -#endif - - if (mTimer.lock()) - { - mTimer.lock()->cancel(); - } - } - - private: - void growRecvBuffer() - { - if (mRecvBuffer == nullptr) - { - mRecvBuffer.reset(brynet::base::buffer_new(std::min(16 * 1024, mMaxRecvBufferSize))); - mRecvBuffOriginSize = buffer_getsize(mRecvBuffer.get()); } else { - if (buffer_getsize(mRecvBuffer.get()) >= mMaxRecvBufferSize) + if (!session->initConnectSSL()) { - return; + throw std::runtime_error("init ssl failed"); } - - mCurrentTanhXDiff += 0.2; - const auto newTanh = std::tanh(mCurrentTanhXDiff); - const auto maxSizeDiff = mMaxRecvBufferSize - mRecvBuffOriginSize; - const auto NewSize = mRecvBuffOriginSize + (maxSizeDiff * newTanh); - - assert(NewSize <= mMaxRecvBufferSize); - std::unique_ptr newBuffer(brynet::base::buffer_new(NewSize)); - buffer_write(newBuffer.get(), - buffer_getreadptr(mRecvBuffer.get()), - buffer_getreadvalidcount(mRecvBuffer.get())); - mRecvBuffer = std::move(newBuffer); } } - - void shrinkReceiveBuffer() +#else + if (sslHelper != nullptr) { - auto newSize = buffer_getreadvalidcount(mRecvBuffer.get()); - if (newSize == 0) + throw std::runtime_error("not enable ssl"); + } +#endif + + eventLoop->runAsyncFunctor([session]() { + session->onEnterEventLoop(); + }); + return session; + } + + const EventLoop::Ptr& getEventLoop() const + { + return mEventLoop; + } + + //TODO::濡傛灉鎵灞濫ventLoop宸茬粡娌℃湁宸ヤ綔锛屽垯鍙兘瀵艰嚧鍐呭瓨鏃犻檺澶э紝鍥犱负鎵鎶曢掔殑璇锋眰閮芥病鏈夊緱鍒板鐞 + void send(const SendableMsg::Ptr& msg, + PacketSendedCallback&& callback = nullptr) + { + if (mEventLoop->isInLoopThread()) + { + sendInLoop(msg, std::move(callback)); + } + else + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, msg, callback, this]() mutable { + sendInLoop(msg, std::move(callback)); + }); + } + } + + void send(const char* buffer, + size_t len, + PacketSendedCallback&& callback = nullptr) + { + send(MakeStringMsg(buffer, len), std::move(callback)); + } + + void send(const std::string& buffer, + PacketSendedCallback&& callback = nullptr) + { + send(MakeStringMsg(buffer), std::move(callback)); + } + + void send(std::string&& buffer, + PacketSendedCallback&& callback = nullptr) + { + send(MakeStringMsg(std::move(buffer)), std::move(callback)); + } + + // setDataCallback(std::function锛 + template + void setDataCallback(Callback&& cb) + { + verifyArgType(cb, &Callback::operator()); + + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, cb, this]() mutable { + mDataCallback = cb; + processRecvMessage(); + }); + } + + void setDisConnectCallback(DisconnectedCallback&& cb) + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, cb, this]() mutable { + mDisConnectCallback = std::move(cb); + }); + } + + /* if checkTime is zero, will cancel check heartbeat */ + void setHeartBeat(std::chrono::nanoseconds checkTime) + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, checkTime, this]() { + if (mTimer.lock() != nullptr) { - newSize = std::min(16 * 1024, mMaxRecvBufferSize); + mTimer.lock()->cancel(); + mTimer.reset(); } - if(newSize == buffer_getsize(mRecvBuffer.get())) + + mCheckTime = checkTime; + startPingCheckTimer(); + }); + } + + void setHighWaterCallback(HighWaterCallback cb, size_t size) + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([=]() mutable { + mHighWaterCallback = std::move(cb); + mHighWaterSize = size; + }); + } + + void postShrinkReceiveBuffer() + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, this]() { + mEventLoop->runFunctorAfterLoop([sharedThis, this]() { + shrinkReceiveBuffer(); + }); + }); + } + + void postDisConnect() + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, this]() { + procCloseInLoop(); + }); + } + + void postShutdown() + { + auto sharedThis = shared_from_this(); + mEventLoop->runAsyncFunctor([sharedThis, this]() { + mEventLoop->runFunctorAfterLoop([sharedThis, this]() { + procShutdownInLoop(); + }); + }); + } + + const std::string& getIP() const + { + return mIP; + } + +protected: + TcpConnection(TcpSocket::Ptr socket, + size_t maxRecvBufferSize, + EnterCallback&& enterCallback, + EventLoop::Ptr eventLoop) BRYNET_NOEXCEPT + : +#ifdef BRYNET_PLATFORM_WINDOWS + mOvlRecv(port::Win::OverlappedType::OverlappedRecv), + mOvlSend(port::Win::OverlappedType::OverlappedSend), + mPostClose(false), +#endif + mIP(socket->getRemoteIP()), + mSocket(std::move(socket)), + mEventLoop(std::move(eventLoop)), + mAlreadyClose(false), + mMaxRecvBufferSize(maxRecvBufferSize), + mSendingMsgSize(0), + mEnterCallback(std::move(enterCallback)), + mHighWaterSize(0) + { + mRecvData = false; + mCheckTime = std::chrono::steady_clock::duration::zero(); + mIsPostFlush = false; + + mCanWrite = true; + +#ifdef BRYNET_PLATFORM_WINDOWS + mPostRecvCheck = false; + mPostWriteCheck = false; +#endif + growRecvBuffer(); + +#ifdef BRYNET_USE_OPENSSL + mSSLCtx = nullptr; + mSSL = nullptr; + mIsHandsharked = false; +#endif + } + + ~TcpConnection() BRYNET_NOEXCEPT override + { +#ifdef BRYNET_USE_OPENSSL + if (mSSL != nullptr) + { + SSL_free(mSSL); + mSSL = nullptr; + } + if (mSSLCtx != nullptr) + { + SSL_CTX_free(mSSLCtx); + mSSLCtx = nullptr; + } +#endif + + if (mTimer.lock()) + { + mTimer.lock()->cancel(); + } + } + +private: + void sendInLoop(const SendableMsg::Ptr& msg, + PacketSendedCallback&& callback = nullptr) + { + if (mAlreadyClose) + { + return; + } + + const auto len = msg->size(); + mSendingMsgSize += len; + mSendList.emplace_back(PendingPacket{ + msg, + len, + std::move(callback)}); + runAfterFlush(); + + if (mSendingMsgSize > mHighWaterSize && + mHighWaterCallback != nullptr) + { + mHighWaterCallback(); + } + } + + void growRecvBuffer() + { + if (mRecvBuffer == nullptr) + { + mRecvBuffer.reset(brynet::base::buffer_new(std::min(16 * 1024, mMaxRecvBufferSize))); + mRecvBuffOriginSize = buffer_getsize(mRecvBuffer.get()); + } + else + { + if (buffer_getsize(mRecvBuffer.get()) >= mMaxRecvBufferSize) { return; } - std::unique_ptr - newBuffer(brynet::base::buffer_new(newSize)); + mCurrentTanhXDiff += 0.2; + const auto newTanh = std::tanh(mCurrentTanhXDiff); + const auto maxSizeDiff = mMaxRecvBufferSize - mRecvBuffOriginSize; + const auto NewSize = mRecvBuffOriginSize + (maxSizeDiff * newTanh); + + assert(NewSize <= mMaxRecvBufferSize); + std::unique_ptr newBuffer(brynet::base::buffer_new(NewSize)); buffer_write(newBuffer.get(), buffer_getreadptr(mRecvBuffer.get()), buffer_getreadvalidcount(mRecvBuffer.get())); - mRecvBuffer = std::move(newBuffer); - mCurrentTanhXDiff = 0; - mRecvBuffOriginSize = newSize; + } + } + + void shrinkReceiveBuffer() + { + auto newSize = buffer_getreadvalidcount(mRecvBuffer.get()); + if (newSize == 0) + { + newSize = std::min(16 * 1024, mMaxRecvBufferSize); + } + if (newSize == buffer_getsize(mRecvBuffer.get())) + { + return; } - /* must called in network thread */ - bool onEnterEventLoop() + std::unique_ptr + newBuffer(brynet::base::buffer_new(newSize)); + buffer_write(newBuffer.get(), + buffer_getreadptr(mRecvBuffer.get()), + buffer_getreadvalidcount(mRecvBuffer.get())); + + mRecvBuffer = std::move(newBuffer); + mCurrentTanhXDiff = 0; + mRecvBuffOriginSize = newSize; + } + + /* must called in network thread */ + bool onEnterEventLoop() + { + assert(mEventLoop->isInLoopThread()); + if (!mEventLoop->isInLoopThread()) { - assert(mEventLoop->isInLoopThread()); - if (!mEventLoop->isInLoopThread()) - { - return false; - } + return false; + } - if (!brynet::net::base::SocketNonblock(mSocket->getFD()) || - !mEventLoop->linkChannel(mSocket->getFD(), this)) - { - return false; - } + if (!brynet::net::base::SocketNonblock(mSocket->getFD()) || + !mEventLoop->linkChannel(mSocket->getFD(), this)) + { + return false; + } - const auto findRet = mEventLoop->getTcpConnection(mSocket->getFD()); - (void)findRet; - assert(findRet == nullptr); + const auto findRet = mEventLoop->getTcpConnection(mSocket->getFD()); + (void) findRet; + assert(findRet == nullptr); #ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr) - { - mEventLoop->addTcpConnection(mSocket->getFD(), shared_from_this()); - processSSLHandshake(); - return true; - } -#endif - - if (!checkRead()) - { - return false; - } - + if (mSSL != nullptr) + { mEventLoop->addTcpConnection(mSocket->getFD(), shared_from_this()); - causeEnterCallback(); - - return true; - } - -#ifdef BRYNET_USE_OPENSSL - bool initAcceptSSL(SSL_CTX* ctx) - { - if (mSSL != nullptr) - { - return false; - } - - mSSL = SSL_new(ctx); - if (SSL_set_fd(mSSL, mSocket->getFD()) != 1) - { - ERR_print_errors_fp(stdout); - ::fflush(stdout); - return false; - } - - return true; - } - bool initConnectSSL() - { - if (mSSLCtx != nullptr) - { - return false; - } - - mSSLCtx = SSL_CTX_new(SSLv23_client_method()); - mSSL = SSL_new(mSSLCtx); - - if (SSL_set_fd(mSSL, mSocket->getFD()) != 1) - { - ERR_print_errors_fp(stdout); - ::fflush(stdout); - return false; - } - + processSSLHandshake(); return true; } #endif - void pingCheck() + if (!checkRead()) { - mTimer.reset(); - if (mRecvData) - { - mRecvData = false; - startPingCheckTimer(); - } - else - { - procCloseInLoop(); - } + return false; } - void startPingCheckTimer() + mEventLoop->addTcpConnection(mSocket->getFD(), shared_from_this()); + causeEnterCallback(); + + return true; + } + +#ifdef BRYNET_USE_OPENSSL + bool initAcceptSSL(SSL_CTX* ctx) + { + if (mSSL != nullptr) { - if (!mTimer.lock() && - mCheckTime != std::chrono::steady_clock::duration::zero()) - { - std::weak_ptr weakedThis = shared_from_this(); - mTimer = mEventLoop->runAfter(mCheckTime, [weakedThis]() { - auto sharedThis = weakedThis.lock(); - if (sharedThis != nullptr) - { - sharedThis->pingCheck(); - } - }); - } + return false; } - void canRecv() override + mSSL = SSL_new(ctx); + if (SSL_set_fd(mSSL, mSocket->getFD()) != 1) { + ERR_print_errors_fp(stdout); + ::fflush(stdout); + return false; + } + + return true; + } + bool initConnectSSL() + { + if (mSSLCtx != nullptr) + { + return false; + } + + mSSLCtx = SSL_CTX_new(SSLv23_client_method()); + mSSL = SSL_new(mSSLCtx); + + if (SSL_set_fd(mSSL, mSocket->getFD()) != 1) + { + ERR_print_errors_fp(stdout); + ::fflush(stdout); + return false; + } + + return true; + } +#endif + + void pingCheck() + { + mTimer.reset(); + if (mRecvData) + { + mRecvData = false; + startPingCheckTimer(); + } + else + { + procCloseInLoop(); + } + } + + void startPingCheckTimer() + { + if (!mTimer.lock() && + mCheckTime != std::chrono::steady_clock::duration::zero()) + { + std::weak_ptr weakThis = shared_from_this(); + mTimer = mEventLoop->runAfter(mCheckTime, [weakThis]() { + auto sharedThis = weakThis.lock(); + if (sharedThis != nullptr) + { + sharedThis->pingCheck(); + } + }); + } + } + + void canRecv(const bool willClose) override + { #ifdef BRYNET_PLATFORM_WINDOWS - mPostRecvCheck = false; - if (mPostClose) - { - if (!mPostWriteCheck) - { - onClose(); - } - return; - } -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - if (mAlreadyClose) - { - return; - } -#endif - -#ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr - && !mIsHandsharked - && (!processSSLHandshake() || !mIsHandsharked)) - { - return; - } -#endif - - recv(); - } - - void canSend() override + mPostRecvCheck = false; + if (mPostClose) { -#ifdef BRYNET_PLATFORM_WINDOWS - mPostWriteCheck = false; - if (mPostClose) - { - if (!mPostRecvCheck) - { - onClose(); - } - return; - } -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - if (mAlreadyClose) - { - return; - } -#endif - mCanWrite = true; - -#ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr - && !mIsHandsharked - && (!processSSLHandshake() || !mIsHandsharked)) - { - return; - } -#endif - - runAfterFlush(); - } - - bool checkRead() - { - bool check_ret = true; -#ifdef BRYNET_PLATFORM_WINDOWS - static CHAR temp[] = { 0 }; - static WSABUF in_buf = { 0, temp }; - - if (mPostRecvCheck) - { - return check_ret; - } - - DWORD dwBytes = 0; - DWORD flag = 0; - const int ret = WSARecv(mSocket->getFD(), - &in_buf, - 1, - &dwBytes, - &flag, - &(mOvlRecv.base), - 0); - if (ret == BRYNET_SOCKET_ERROR) - { - check_ret = (BRYNET_ERRNO == WSA_IO_PENDING); - } - - if (check_ret) - { - mPostRecvCheck = true; - } -#endif - - return check_ret; - } - - bool checkWrite() - { - bool check_ret = true; -#ifdef BRYNET_PLATFORM_WINDOWS - static WSABUF wsendbuf[1] = { {NULL, 0} }; - - if (mPostWriteCheck) - { - return check_ret; - } - - DWORD send_len = 0; - const int ret = WSASend(mSocket->getFD(), - wsendbuf, - 1, - &send_len, - 0, - &(mOvlSend.base), - 0); - if (ret == BRYNET_SOCKET_ERROR) - { - check_ret = (BRYNET_ERRNO == WSA_IO_PENDING); - } - - if (check_ret) - { - mPostWriteCheck = true; - } -#endif - return check_ret; - } - - - void recv() - { - bool must_close = false; -#ifdef BRYNET_USE_OPENSSL - const bool notInSSL = (mSSL == nullptr); -#else - const bool notInSSL = false; -#endif - - while (true) - { - if (buffer_getwritevalidcount(mRecvBuffer.get()) == 0 - || buffer_getreadvalidcount(mRecvBuffer.get()) == 0) - { - buffer_adjustto_head(mRecvBuffer.get()); - } - - if (buffer_getreadvalidcount(mRecvBuffer.get()) - == buffer_getsize(mRecvBuffer.get())) - { - growRecvBuffer(); - } - - const auto tryRecvLen = buffer_getwritevalidcount(mRecvBuffer.get()); - if (tryRecvLen == 0) - { -#ifdef BRYNET_PLATFORM_WINDOWS - checkRead(); -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - //force recheck IN-OUT Event - recheckEvent(); -#endif - break; - } - - int retlen = 0; -#ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr) - { - retlen = SSL_read(mSSL, - buffer_getwriteptr(mRecvBuffer.get()), tryRecvLen); - } - else - { - retlen = ::recv(mSocket->getFD(), - buffer_getwriteptr(mRecvBuffer.get()), tryRecvLen, 0); - } -#else - retlen = ::recv(mSocket->getFD(), - buffer_getwriteptr(mRecvBuffer.get()), - static_cast(tryRecvLen), - 0); -#endif - - if (retlen == 0) - { - must_close = true; - break; - } - else if (retlen < 0) - { -#ifdef BRYNET_USE_OPENSSL - if ((mSSL != nullptr && - SSL_get_error(mSSL, retlen) == SSL_ERROR_WANT_READ) || - (BRYNET_ERRNO == BRYNET_EWOULDBLOCK)) - { - must_close = !checkRead(); - } - else - { - must_close = true; - } -#else - if (BRYNET_ERRNO != BRYNET_EWOULDBLOCK) - { - must_close = true; - } - else - { - must_close = !checkRead(); - } -#endif - break; - } - - mRecvData = true; - buffer_addwritepos(mRecvBuffer.get(), static_cast(retlen)); - - if (notInSSL && retlen < static_cast(tryRecvLen)) - { - must_close = !checkRead(); - break; - } - } - - processRecvMessage(); - - if (must_close) - { - procCloseInLoop(); - } - } - - void flush() - { -#ifdef BRYNET_PLATFORM_WINDOWS - normalFlush(); -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN -#ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr) - { - normalFlush(); - } - else - { - quickFlush(); - } -#else - quickFlush(); -#endif -#endif - } - void normalFlush() - { -#ifdef BRYNET_PLATFORM_WINDOWS - static __declspec(thread) char* threadLocalSendBuf = nullptr; -#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - static __thread char* threadLocalSendBuf = nullptr; -#endif - static const int SENDBUF_SIZE = 1024 * 32; - if (threadLocalSendBuf == nullptr) - { - threadLocalSendBuf = static_cast(malloc(SENDBUF_SIZE)); - } - -#ifdef BRYNET_USE_OPENSSL - const bool notInSSL = (mSSL == nullptr); -#else - const bool notInSSL = false; -#endif - - bool must_close = false; - - while (!mSendList.empty() && mCanWrite) - { - auto sendptr = threadLocalSendBuf; - size_t wait_send_size = 0; - - for (auto it = mSendList.begin(); it != mSendList.end(); ++it) - { - auto& packet = *it; - auto packetLeftBuf = (char*)(packet.data->data()) + packet.data->size() - packet.left; - const auto packetLeftLen = packet.left; - - if ((wait_send_size + packetLeftLen) > SENDBUF_SIZE) - { - if (it == mSendList.begin()) - { - sendptr = packetLeftBuf; - wait_send_size = packetLeftLen; - } - break; - } - - memcpy(static_cast(sendptr + wait_send_size), static_cast(packetLeftBuf), packetLeftLen); - wait_send_size += packetLeftLen; - } - - if (wait_send_size == 0) - { - break; - } - - int send_retlen = 0; -#ifdef BRYNET_USE_OPENSSL - if (mSSL != nullptr) - { - send_retlen = SSL_write(mSSL, sendptr, wait_send_size); - } - else - { - send_retlen = ::send(mSocket->getFD(), sendptr, wait_send_size, 0); - } -#else - send_retlen = ::send(mSocket->getFD(), sendptr, static_cast(wait_send_size), 0); -#endif - if (send_retlen <= 0) - { - -#ifdef BRYNET_USE_OPENSSL - if ((mSSL != nullptr && SSL_get_error(mSSL, send_retlen) == SSL_ERROR_WANT_WRITE) || - (BRYNET_ERRNO == BRYNET_EWOULDBLOCK)) - { - mCanWrite = false; - must_close = !checkWrite(); - } - else - { - must_close = true; - } -#else - if (BRYNET_ERRNO == BRYNET_EWOULDBLOCK) - { - mCanWrite = false; - must_close = !checkWrite(); - } - else - { - must_close = true; - } -#endif - break; - } - - auto tmp_len = static_cast(send_retlen); - for (auto it = mSendList.begin(); it != mSendList.end();) - { - auto& packet = *it; - if (packet.left > tmp_len) - { - packet.left -= tmp_len; - break; - } - - tmp_len -= packet.left; - if (packet.mCompleteCallback != nullptr) - { - (packet.mCompleteCallback)(); - } - mSendingMsgSize -= packet.data->size(); - it = mSendList.erase(it); - } - - if (notInSSL && static_cast(send_retlen) != wait_send_size) - { - mCanWrite = false; - must_close = !checkWrite(); - break; - } - } - - if (must_close) - { - procCloseInLoop(); - } - } -#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - void quickFlush() - { -#ifndef MAX_IOVEC - constexpr size_t MAX_IOVEC = 1024; -#endif - - struct iovec iov[MAX_IOVEC]; - bool must_close = false; - - while (!mSendList.empty() && mCanWrite) - { - size_t num = 0; - size_t ready_send_len = 0; - for (const auto& p : mSendList) - { - iov[num].iov_base = (void*)(static_cast(p.data->data()) + p.data->size() - p.left); - iov[num].iov_len = p.left; - ready_send_len += p.left; - - num++; - if (num >= MAX_IOVEC) - { - break; - } - } - - if (num == 0) - { - break; - } - - const int send_len = writev(mSocket->getFD(), iov, static_cast(num)); - if (send_len <= 0) - { - if (BRYNET_ERRNO == BRYNET_EWOULDBLOCK) - { - mCanWrite = false; - must_close = !checkWrite(); - } - else - { - must_close = true; - } - break; - } - - auto tmp_len = static_cast(send_len); - for (auto it = mSendList.begin(); it != mSendList.end();) - { - PendingPacket& b = *it; - if (b.left > tmp_len) - { - b.left -= tmp_len; - break; - } - - tmp_len -= b.left; - if (b.mCompleteCallback != nullptr) - { - b.mCompleteCallback(); - } - mSendingMsgSize -= b.data->size(); - it = mSendList.erase(it); - } - - if (static_cast(send_len) != ready_send_len) - { - mCanWrite = false; - must_close = !checkWrite(); - break; - } - } - - if (must_close) - { - procCloseInLoop(); - } - } -#endif - - void onClose() override - { - if (mAlreadyClose) - { - return; - } - mAlreadyClose = true; - -#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - unregisterPollerEvent(); -#endif - - assert(mEnterCallback == nullptr); - auto callBack = mDisConnectCallback; - auto sharedThis = shared_from_this(); - auto eventLoop = mEventLoop; - std::shared_ptr socket = std::move(const_cast(mSocket)); - mEventLoop->runFunctorAfterLoop([callBack, - sharedThis, - eventLoop, - socket]() { - if (callBack != nullptr) - { - callBack(sharedThis); - } - auto tmp = eventLoop->getTcpConnection(socket->getFD()); - assert(tmp == sharedThis); - if (tmp == sharedThis) - { - eventLoop->removeTcpConnection(socket->getFD()); - } - }); - - mCanWrite = false; - mDataCallback = nullptr; - mDisConnectCallback = nullptr; - mHighWaterCallback = nullptr; - mRecvBuffer = nullptr; - mSendList.clear(); - } - - void procCloseInLoop() - { - mCanWrite = false; -#ifdef BRYNET_PLATFORM_WINDOWS - if (mPostWriteCheck || mPostRecvCheck) - { - if (mPostClose) - { - return; - } - mPostClose = true; - //windows涓嬬珛鍗冲叧闂璼ocket鍙兘瀵艰嚧fd琚彟澶栫殑TcpConnection閲嶇敤,鑰屽鑷存瀵硅薄鍦↖OCP杩斿洖鐩稿叧瀹屾垚缁撴灉鏃跺唴瀛樺凡缁忛噴鏀 - if (mPostRecvCheck) - { - CancelIoEx(HANDLE(mSocket->getFD()), &mOvlRecv.base); - } - if (mPostWriteCheck) - { - CancelIoEx(HANDLE(mSocket->getFD()), &mOvlSend.base); - } - } - else + if (!mPostWriteCheck) { onClose(); } -#elif defined BRYNET_PLATFORM_LINUX - onClose(); -#elif defined BRYNET_PLATFORM_DARWIN - onClose(); + return; + } +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + if (mAlreadyClose) + { + return; + } #endif + +#ifdef BRYNET_USE_OPENSSL + if (mSSL != nullptr && !mIsHandsharked && (!processSSLHandshake() || !mIsHandsharked)) + { + return; + } +#endif + + do + { + recv(); + adjustReceiveBuffer(); + } while (willClose && !mAlreadyClose && mRecvBuffer != nullptr && buffer_getwritevalidcount(mRecvBuffer.get()) > 0); + } + + void canSend() override + { +#ifdef BRYNET_PLATFORM_WINDOWS + mPostWriteCheck = false; + if (mPostClose) + { + if (!mPostRecvCheck) + { + onClose(); + } + return; + } +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + if (mAlreadyClose) + { + return; + } +#endif + mCanWrite = true; + +#ifdef BRYNET_USE_OPENSSL + if (mSSL != nullptr && !mIsHandsharked && (!processSSLHandshake() || !mIsHandsharked)) + { + return; + } +#endif + + runAfterFlush(); + } + + bool checkRead() + { + bool check_ret = true; +#ifdef BRYNET_PLATFORM_WINDOWS + static CHAR temp[] = {0}; + static WSABUF in_buf = {0, temp}; + + if (mPostRecvCheck) + { + return check_ret; } - void procShutdownInLoop() + DWORD dwBytes = 0; + DWORD flag = 0; + const int ret = WSARecv(mSocket->getFD(), + &in_buf, + 1, + &dwBytes, + &flag, + &(mOvlRecv.base), + 0); + if (ret == BRYNET_SOCKET_ERROR) { - mCanWrite = false; - if (mSocket != nullptr) + check_ret = (BRYNET_ERRNO == WSA_IO_PENDING); + } + + if (check_ret) + { + mPostRecvCheck = true; + } +#endif + + return check_ret; + } + + bool checkWrite() + { + bool check_ret = true; +#ifdef BRYNET_PLATFORM_WINDOWS + static WSABUF wsendbuf[1] = {{ NULL, + 0 }}; + + if (mPostWriteCheck) + { + return check_ret; + } + + DWORD send_len = 0; + const int ret = WSASend(mSocket->getFD(), + wsendbuf, + 1, + &send_len, + 0, + &(mOvlSend.base), + 0); + if (ret == BRYNET_SOCKET_ERROR) + { + check_ret = (BRYNET_ERRNO == WSA_IO_PENDING); + } + + if (check_ret) + { + mPostWriteCheck = true; + } +#endif + return check_ret; + } + + void adjustReceiveBuffer() + { + if (!mRecvBuffer) + { + return; + } + + if (buffer_getwritevalidcount(mRecvBuffer.get()) == 0 || buffer_getreadvalidcount(mRecvBuffer.get()) == 0) + { + buffer_adjustto_head(mRecvBuffer.get()); + } + + if (buffer_getreadvalidcount(mRecvBuffer.get()) == buffer_getsize(mRecvBuffer.get())) + { + growRecvBuffer(); + } + } + + void recv() + { + bool must_close = false; +#ifdef BRYNET_USE_OPENSSL + const bool notInSSL = (mSSL == nullptr); +#else + const bool notInSSL = false; +#endif + + while (true) + { + adjustReceiveBuffer(); + + const auto tryRecvLen = buffer_getwritevalidcount(mRecvBuffer.get()); + if (tryRecvLen == 0) { #ifdef BRYNET_PLATFORM_WINDOWS - shutdown(mSocket->getFD(), SD_SEND); + checkRead(); #elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - shutdown(mSocket->getFD(), SHUT_WR); + //force recheck IN-OUT Event + recheckEvent(); #endif + break; } - } - void runAfterFlush() - { - if (!mIsPostFlush && !mSendList.empty() && mCanWrite) - { - auto sharedThis = shared_from_this(); - mEventLoop->runFunctorAfterLoop([sharedThis]() { - sharedThis->mIsPostFlush = false; - sharedThis->flush(); - }); - - mIsPostFlush = true; - } - } -#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN - void recheckEvent() - { -#ifdef BRYNET_PLATFORM_LINUX - struct epoll_event ev = { 0, { nullptr } }; - ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP; - ev.data.ptr = (Channel*)(this); - epoll_ctl(mEventLoop->getEpollHandle(), EPOLL_CTL_MOD, mSocket->getFD(), &ev); -#elif defined BRYNET_PLATFORM_DARWIN - struct kevent ev[2]; - memset(&ev, 0, sizeof(ev)); - int n = 0; - EV_SET(&ev[n++], mSocket->getFD(), EVFILT_READ, EV_ENABLE, 0, 0, (Channel*)(this)); - EV_SET(&ev[n++], mSocket->getFD(), EVFILT_WRITE, EV_ENABLE, 0, 0, (Channel*)(this)); - - struct timespec now = { 0, 0 }; - kevent(mEventLoop->getKqueueHandle(), ev, n, NULL, 0, &now); -#endif - } - void unregisterPollerEvent() - { -#ifdef BRYNET_PLATFORM_LINUX - struct epoll_event ev = { 0, { nullptr } }; - epoll_ctl(mEventLoop->getEpollHandle(), EPOLL_CTL_DEL, mSocket->getFD(), &ev); -#elif defined BRYNET_PLATFORM_DARWIN - struct kevent ev[2]; - memset(&ev, 0, sizeof(ev)); - int n = 0; - EV_SET(&ev[n++], mSocket->getFD(), EVFILT_READ, EV_DELETE, 0, 0, NULL); - EV_SET(&ev[n++], mSocket->getFD(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - - struct timespec now = { 0, 0 }; - kevent(mEventLoop->getKqueueHandle(), ev, n, NULL, 0, &now); -#endif - } -#endif + int retlen = 0; #ifdef BRYNET_USE_OPENSSL - bool processSSLHandshake() - { - if (mIsHandsharked) + if (mSSL != nullptr) { - return true; - } - - bool mustClose = false; - int ret = 0; - - if (mSSLCtx != nullptr) - { - ret = SSL_connect(mSSL); + retlen = SSL_read(mSSL, + buffer_getwriteptr(mRecvBuffer.get()), tryRecvLen); } else { - ret = SSL_accept(mSSL); + retlen = ::recv(mSocket->getFD(), + buffer_getwriteptr(mRecvBuffer.get()), tryRecvLen, 0); } +#else + retlen = ::recv(mSocket->getFD(), + buffer_getwriteptr(mRecvBuffer.get()), + static_cast(tryRecvLen), + 0); +#endif - if (ret == 1) + if (retlen == 0) { - mIsHandsharked = true; - if (checkRead()) + must_close = true; + break; + } + else if (retlen < 0) + { +#ifdef BRYNET_USE_OPENSSL + if ((mSSL != nullptr && + SSL_get_error(mSSL, retlen) == SSL_ERROR_WANT_READ) || + (BRYNET_ERRNO == BRYNET_EWOULDBLOCK)) { - causeEnterCallback(); + must_close = !checkRead(); } else { - mustClose = true; + must_close = true; + } +#else + if (BRYNET_ERRNO != BRYNET_EWOULDBLOCK) + { + must_close = true; + } + else + { + must_close = !checkRead(); + } +#endif + break; + } + + mRecvData = true; + buffer_addwritepos(mRecvBuffer.get(), static_cast(retlen)); + + if (notInSSL && retlen < static_cast(tryRecvLen)) + { + must_close = !checkRead(); + break; + } + } + + processRecvMessage(); + + if (must_close) + { + procCloseInLoop(); + } + } + + void flush() + { +#ifdef BRYNET_PLATFORM_WINDOWS + normalFlush(); +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN +#ifdef BRYNET_USE_OPENSSL + if (mSSL != nullptr) + { + normalFlush(); + } + else + { + quickFlush(); + } +#else + quickFlush(); +#endif +#endif + } + void normalFlush() + { +#ifdef BRYNET_PLATFORM_WINDOWS + static __declspec(thread) char* threadLocalSendBuf = nullptr; +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + static __thread char* threadLocalSendBuf = nullptr; +#endif + static const int SENDBUF_SIZE = 1024 * 32; + if (threadLocalSendBuf == nullptr) + { + threadLocalSendBuf = static_cast(malloc(SENDBUF_SIZE)); + } + +#ifdef BRYNET_USE_OPENSSL + const bool notInSSL = (mSSL == nullptr); +#else + const bool notInSSL = false; +#endif + + bool must_close = false; + + while (!mSendList.empty() && mCanWrite) + { + auto sendptr = threadLocalSendBuf; + size_t wait_send_size = 0; + + for (auto it = mSendList.begin(); it != mSendList.end(); ++it) + { + auto& packet = *it; + auto packetLeftBuf = (char*) (packet.data->data()) + packet.data->size() - packet.left; + const auto packetLeftLen = packet.left; + + if ((wait_send_size + packetLeftLen) > SENDBUF_SIZE) + { + if (it == mSendList.begin()) + { + sendptr = packetLeftBuf; + wait_send_size = packetLeftLen; + } + break; + } + + memcpy(static_cast(sendptr + wait_send_size), static_cast(packetLeftBuf), packetLeftLen); + wait_send_size += packetLeftLen; + } + + if (wait_send_size == 0) + { + break; + } + + int send_retlen = 0; +#ifdef BRYNET_USE_OPENSSL + if (mSSL != nullptr) + { + send_retlen = SSL_write(mSSL, sendptr, wait_send_size); + } + else + { + send_retlen = ::send(mSocket->getFD(), sendptr, wait_send_size, 0); + } +#else + send_retlen = ::send(mSocket->getFD(), sendptr, static_cast(wait_send_size), 0); +#endif + if (send_retlen <= 0) + { + +#ifdef BRYNET_USE_OPENSSL + if ((mSSL != nullptr && SSL_get_error(mSSL, send_retlen) == SSL_ERROR_WANT_WRITE) || + (BRYNET_ERRNO == BRYNET_EWOULDBLOCK)) + { + mCanWrite = false; + must_close = !checkWrite(); + } + else + { + must_close = true; + } +#else + if (BRYNET_ERRNO == BRYNET_EWOULDBLOCK) + { + mCanWrite = false; + must_close = !checkWrite(); + } + else + { + must_close = true; + } +#endif + break; + } + + auto tmp_len = static_cast(send_retlen); + for (auto it = mSendList.begin(); it != mSendList.end();) + { + auto& packet = *it; + if (packet.left > tmp_len) + { + packet.left -= tmp_len; + break; + } + + tmp_len -= packet.left; + if (packet.mCompleteCallback != nullptr) + { + (packet.mCompleteCallback)(); + } + mSendingMsgSize -= packet.data->size(); + it = mSendList.erase(it); + } + + if (notInSSL && static_cast(send_retlen) != wait_send_size) + { + mCanWrite = false; + must_close = !checkWrite(); + break; + } + } + + if (must_close) + { + procCloseInLoop(); + } + } +#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + void quickFlush() + { +#ifndef MAX_IOVEC + constexpr size_t MAX_IOVEC = 1024; +#endif + + struct iovec iov[MAX_IOVEC]; + bool must_close = false; + + while (!mSendList.empty() && mCanWrite) + { + size_t num = 0; + size_t ready_send_len = 0; + for (const auto& p : mSendList) + { + iov[num].iov_base = (void*) (static_cast(p.data->data()) + p.data->size() - p.left); + iov[num].iov_len = p.left; + ready_send_len += p.left; + + num++; + if (num >= MAX_IOVEC) + { + break; } } - else if (ret == 0) + + if (num == 0) + { + break; + } + + const int send_len = writev(mSocket->getFD(), iov, static_cast(num)); + if (send_len <= 0) + { + if (BRYNET_ERRNO == BRYNET_EWOULDBLOCK) + { + mCanWrite = false; + must_close = !checkWrite(); + } + else + { + must_close = true; + } + break; + } + + auto tmp_len = static_cast(send_len); + for (auto it = mSendList.begin(); it != mSendList.end();) + { + PendingPacket& b = *it; + if (b.left > tmp_len) + { + b.left -= tmp_len; + break; + } + + tmp_len -= b.left; + if (b.mCompleteCallback != nullptr) + { + b.mCompleteCallback(); + } + mSendingMsgSize -= b.data->size(); + it = mSendList.erase(it); + } + + if (static_cast(send_len) != ready_send_len) + { + mCanWrite = false; + must_close = !checkWrite(); + break; + } + } + + if (must_close) + { + procCloseInLoop(); + } + } +#endif + + void onClose() override + { + if (mAlreadyClose) + { + return; + } + mAlreadyClose = true; + +#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + unregisterPollerEvent(); +#endif + + assert(mEnterCallback == nullptr); + auto callBack = mDisConnectCallback; + auto sharedThis = shared_from_this(); + auto eventLoop = mEventLoop; + std::shared_ptr socket = std::move(const_cast(mSocket)); + mEventLoop->runFunctorAfterLoop([callBack, + sharedThis, + eventLoop, + socket]() { + if (callBack != nullptr) + { + callBack(sharedThis); + } + auto tmp = eventLoop->getTcpConnection(socket->getFD()); + assert(tmp == sharedThis); + if (tmp == sharedThis) + { + eventLoop->removeTcpConnection(socket->getFD()); + } + }); + + mCanWrite = false; + mDataCallback = nullptr; + mDisConnectCallback = nullptr; + mHighWaterCallback = nullptr; + mRecvBuffer = nullptr; + mSendList.clear(); + } + + void procCloseInLoop() + { + mCanWrite = false; +#ifdef BRYNET_PLATFORM_WINDOWS + if (mPostWriteCheck || mPostRecvCheck) + { + if (mPostClose) + { + return; + } + mPostClose = true; + //windows涓嬬珛鍗冲叧闂璼ocket鍙兘瀵艰嚧fd琚彟澶栫殑TcpConnection閲嶇敤,鑰屽鑷存瀵硅薄鍦↖OCP杩斿洖鐩稿叧瀹屾垚缁撴灉鏃跺唴瀛樺凡缁忛噴鏀 + if (mPostRecvCheck) + { + CancelIoEx(HANDLE(mSocket->getFD()), &mOvlRecv.base); + } + if (mPostWriteCheck) + { + CancelIoEx(HANDLE(mSocket->getFD()), &mOvlSend.base); + } + } + else + { + onClose(); + } +#elif defined BRYNET_PLATFORM_LINUX + onClose(); +#elif defined BRYNET_PLATFORM_DARWIN + onClose(); +#endif + } + + void procShutdownInLoop() + { + mCanWrite = false; + if (mSocket != nullptr) + { +#ifdef BRYNET_PLATFORM_WINDOWS + shutdown(mSocket->getFD(), SD_SEND); +#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + shutdown(mSocket->getFD(), SHUT_WR); +#endif + } + } + + void runAfterFlush() + { + if (!mIsPostFlush && !mSendList.empty() && mCanWrite) + { + auto sharedThis = shared_from_this(); + mEventLoop->runFunctorAfterLoop([sharedThis, this]() { + mIsPostFlush = false; + flush(); + }); + + mIsPostFlush = true; + } + } +#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN + void recheckEvent() + { +#ifdef BRYNET_PLATFORM_LINUX + struct epoll_event ev = {0, + { + nullptr + }}; + ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP; + ev.data.ptr = (Channel*) (this); + epoll_ctl(mEventLoop->getEpollHandle(), EPOLL_CTL_MOD, mSocket->getFD(), &ev); +#elif defined BRYNET_PLATFORM_DARWIN + struct kevent ev[2]; + memset(&ev, 0, sizeof(ev)); + int n = 0; + EV_SET(&ev[n++], mSocket->getFD(), EVFILT_READ, EV_ENABLE, 0, 0, (Channel*) (this)); + EV_SET(&ev[n++], mSocket->getFD(), EVFILT_WRITE, EV_ENABLE, 0, 0, (Channel*) (this)); + + struct timespec now = {0, 0}; + kevent(mEventLoop->getKqueueHandle(), ev, n, NULL, 0, &now); +#endif + } + void unregisterPollerEvent() + { +#ifdef BRYNET_PLATFORM_LINUX + struct epoll_event ev = {0, + { + nullptr + }}; + epoll_ctl(mEventLoop->getEpollHandle(), EPOLL_CTL_DEL, mSocket->getFD(), &ev); +#elif defined BRYNET_PLATFORM_DARWIN + struct kevent ev[2]; + memset(&ev, 0, sizeof(ev)); + int n = 0; + EV_SET(&ev[n++], mSocket->getFD(), EVFILT_READ, EV_DELETE, 0, 0, NULL); + EV_SET(&ev[n++], mSocket->getFD(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + + struct timespec now = {0, 0}; + kevent(mEventLoop->getKqueueHandle(), ev, n, NULL, 0, &now); +#endif + } +#endif +#ifdef BRYNET_USE_OPENSSL + bool processSSLHandshake() + { + if (mIsHandsharked) + { + return true; + } + + bool mustClose = false; + int ret = 0; + + if (mSSLCtx != nullptr) + { + ret = SSL_connect(mSSL); + } + else + { + ret = SSL_accept(mSSL); + } + + if (ret == 1) + { + mIsHandsharked = true; + if (checkRead()) + { + causeEnterCallback(); + } + else { mustClose = true; } - else if (ret < 0) + } + else if (ret == 0) + { + mustClose = true; + } + else if (ret < 0) + { + int err = SSL_get_error(mSSL, ret); + if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { - int err = SSL_get_error(mSSL, ret); - if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) - { - if (!checkRead()) - { - mustClose = true; - } - } - else + if (!checkRead()) { mustClose = true; } } - - if (mustClose) + else { - causeEnterCallback(); - procCloseInLoop(); - return false; + mustClose = true; } - return true; } + + if (mustClose) + { + causeEnterCallback(); + procCloseInLoop(); + return false; + } + return true; + } #endif - void causeEnterCallback() + void causeEnterCallback() + { + assert(mEventLoop->isInLoopThread()); + if (mEventLoop->isInLoopThread() && mEnterCallback != nullptr) { - assert(mEventLoop->isInLoopThread()); - if (mEventLoop->isInLoopThread() && mEnterCallback != nullptr) + auto tmp = mEnterCallback; + mEnterCallback = nullptr; + tmp(shared_from_this()); + } + } + + void processRecvMessage() + { + if (mDataCallback != nullptr && buffer_getreadvalidcount(mRecvBuffer.get()) > 0) + { + auto reader = brynet::base::BasePacketReader(buffer_getreadptr(mRecvBuffer.get()), + buffer_getreadvalidcount(mRecvBuffer.get()), false); + mDataCallback(reader); + const auto consumedLen = reader.savedPos(); + assert(consumedLen <= reader.size()); + if (consumedLen <= reader.size()) { - auto tmp = mEnterCallback; - mEnterCallback = nullptr; - tmp(shared_from_this()); + buffer_addreadpos(mRecvBuffer.get(), consumedLen); } } + } - void processRecvMessage() - { - if (mDataCallback != nullptr && buffer_getreadvalidcount(mRecvBuffer.get()) > 0) - { - auto reader = brynet::base::BasePacketReader(buffer_getreadptr(mRecvBuffer.get()), - buffer_getreadvalidcount(mRecvBuffer.get()), false); - mDataCallback(reader); - const auto consumedLen = reader.savedPos(); - assert(consumedLen <= reader.size()); - if (consumedLen <= reader.size()) - { - buffer_addreadpos(mRecvBuffer.get(), consumedLen); - } - } - } - - template - static void verifyArgType(const CallbackType&, void(CallbackType::*)(Arg&) const) - { - static_assert(std::is_reference::value, "arg must be reference type"); - static_assert(!std::is_const::type>::value, "arg can't be const type"); - } - - private: + template + static void verifyArgType(const CallbackType&, void (CallbackType::*)(Arg&) const) + { + static_assert(std::is_reference::value, "arg must be reference type"); + static_assert(!std::is_const::type>::value, "arg can't be const type"); + } +private: #ifdef BRYNET_PLATFORM_WINDOWS - struct port::Win::OverlappedExt mOvlRecv; - struct port::Win::OverlappedExt mOvlSend; + struct port::Win::OverlappedExt mOvlRecv; + struct port::Win::OverlappedExt mOvlSend; - bool mPostRecvCheck; - bool mPostWriteCheck; - bool mPostClose; + bool mPostRecvCheck; + bool mPostWriteCheck; + bool mPostClose; #endif - const std::string mIP; - const TcpSocket::Ptr mSocket; - const EventLoop::Ptr mEventLoop; - bool mCanWrite; - bool mAlreadyClose; + const std::string mIP; + const TcpSocket::Ptr mSocket; + const EventLoop::Ptr mEventLoop; + bool mCanWrite; + bool mAlreadyClose; - class BufferDeleter + class BufferDeleter + { + public: + void operator()(struct brynet::base::buffer_s* ptr) const { - public: - void operator()(struct brynet::base::buffer_s* ptr) const - { - brynet::base::buffer_delete(ptr); - } - }; - std::unique_ptr mRecvBuffer; - double mCurrentTanhXDiff = 0; - size_t mRecvBuffOriginSize = 0; - const size_t mMaxRecvBufferSize; + brynet::base::buffer_delete(ptr); + } + }; + std::unique_ptr mRecvBuffer; + double mCurrentTanhXDiff = 0; + size_t mRecvBuffOriginSize = 0; + const size_t mMaxRecvBufferSize; - struct PendingPacket - { - SendableMsg::Ptr data; - size_t left; - PacketSendedCallback mCompleteCallback; - }; - - using PacketListType = std::deque; - PacketListType mSendList; - size_t mSendingMsgSize; - - EnterCallback mEnterCallback; - DataCallback mDataCallback; - DisconnectedCallback mDisConnectCallback; - HighWaterCallback mHighWaterCallback; - size_t mHighWaterSize; - - bool mIsPostFlush; - -#ifdef BRYNET_USE_OPENSSL - SSL_CTX* mSSLCtx; - SSL* mSSL; - bool mIsHandsharked; -#endif - bool mRecvData; - std::chrono::nanoseconds mCheckTime{}; - brynet::base::Timer::WeakPtr mTimer; + struct PendingPacket + { + SendableMsg::Ptr data; + size_t left; + PacketSendedCallback mCompleteCallback; }; -} } + using PacketListType = std::deque; + PacketListType mSendList; + size_t mSendingMsgSize; + + EnterCallback mEnterCallback; + DataCallback mDataCallback; + DisconnectedCallback mDisConnectCallback; + HighWaterCallback mHighWaterCallback; + size_t mHighWaterSize; + + bool mIsPostFlush; + +#ifdef BRYNET_USE_OPENSSL + SSL_CTX* mSSLCtx; + SSL* mSSL; + bool mIsHandsharked; +#endif + bool mRecvData; + std::chrono::nanoseconds mCheckTime{}; + brynet::base::Timer::WeakPtr mTimer; +}; + +}}// namespace brynet::net diff --git a/libs/brynet/net/TcpService.hpp b/libs/brynet/net/TcpService.hpp index 6da5d00..fbe011f 100644 --- a/libs/brynet/net/TcpService.hpp +++ b/libs/brynet/net/TcpService.hpp @@ -4,88 +4,46 @@ namespace brynet { namespace net { - class AddSocketOption +using ConnectionOption = detail::ConnectionOption; +class TcpService : public detail::TcpServiceDetail, + public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + using FrameCallback = detail::TcpServiceDetail::FrameCallback; + +public: + static Ptr Create() { - private: - using AddSocketOptionFunc = detail::AddSocketOptionFunc; - using AddSocketOptionInfo = detail::AddSocketOptionInfo; + struct make_shared_enabler : public TcpService + { + }; + return std::make_shared(); + } - public: - static AddSocketOptionFunc AddEnterCallback( - TcpConnection::EnterCallback callback) - { - return [callback](AddSocketOptionInfo& option) { - option.enterCallback.push_back(callback); - }; - } -#ifdef BRYNET_USE_OPENSSL - static AddSocketOptionFunc WithClientSideSSL() - { - return [](AddSocketOptionInfo& option) { - option.useSSL = true; - }; - } - static AddSocketOptionFunc WithServerSideSSL(SSLHelper::Ptr sslHelper) - { - return [sslHelper](AddSocketOptionInfo& option) { - option.sslHelper = sslHelper; - option.useSSL = true; - }; - } -#endif - static AddSocketOptionFunc WithMaxRecvBufferSize(size_t size) - { - return [size](AddSocketOptionInfo& option) { - option.maxRecvBufferSize = size; - }; - } - static AddSocketOptionFunc WithForceSameThreadLoop(bool same) - { - return [same](AddSocketOptionInfo& option) { - option.forceSameThreadLoop = same; - }; - } - }; - - class TcpService : public detail::TcpServiceDetail, - public std::enable_shared_from_this + void startWorkerThread(size_t threadNum, + FrameCallback callback = nullptr) { - public: - using Ptr = std::shared_ptr; - using FrameCallback = detail::TcpServiceDetail::FrameCallback; + detail::TcpServiceDetail::startWorkerThread(threadNum, callback); + } - public: - static Ptr Create() - { - struct make_shared_enabler : public TcpService {}; - return std::make_shared(); - } + void stopWorkerThread() + { + detail::TcpServiceDetail::stopWorkerThread(); + } - void startWorkerThread(size_t threadNum, - FrameCallback callback = nullptr) - { - detail::TcpServiceDetail::startWorkerThread(threadNum, callback); - } + bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption options) + { + return detail::TcpServiceDetail::addTcpConnection(std::move(socket), options); + } - void stopWorkerThread() - { - detail::TcpServiceDetail::stopWorkerThread(); - } + EventLoop::Ptr getRandomEventLoop() + { + return detail::TcpServiceDetail::getRandomEventLoop(); + } - template - bool addTcpConnection(TcpSocket::Ptr socket, - const Options& ... options) - { - return detail::TcpServiceDetail::addTcpConnection(std::move(socket), options...); - } +private: + TcpService() = default; +}; - EventLoop::Ptr getRandomEventLoop() - { - return detail::TcpServiceDetail::getRandomEventLoop(); - } - - private: - TcpService() = default; - }; - -} } \ No newline at end of file +}}// namespace brynet::net diff --git a/libs/brynet/net/detail/AddSocketOptionInfo.hpp b/libs/brynet/net/detail/AddSocketOptionInfo.hpp deleted file mode 100644 index 5a5aa32..0000000 --- a/libs/brynet/net/detail/AddSocketOptionInfo.hpp +++ /dev/null @@ -1,27 +0,0 @@ -锘#pragma once - -#include -#include - -namespace brynet { namespace net { namespace detail { - - class AddSocketOptionInfo final - { - public: - AddSocketOptionInfo() - { - useSSL = false; - forceSameThreadLoop = false; - maxRecvBufferSize = 128; - } - - std::vector enterCallback; - SSLHelper::Ptr sslHelper; - bool useSSL; - bool forceSameThreadLoop; - size_t maxRecvBufferSize; - }; - - using AddSocketOptionFunc = std::function; - -} } } \ No newline at end of file diff --git a/libs/brynet/net/detail/ConnectionOption.hpp b/libs/brynet/net/detail/ConnectionOption.hpp new file mode 100644 index 0000000..15bb7f3 --- /dev/null +++ b/libs/brynet/net/detail/ConnectionOption.hpp @@ -0,0 +1,18 @@ +锘#pragma once + +#include +#include + +namespace brynet { namespace net { namespace detail { + +class ConnectionOption final +{ +public: + std::vector enterCallback; + SSLHelper::Ptr sslHelper; + bool useSSL = false; + bool forceSameThreadLoop = false; + size_t maxRecvBufferSize = 128; +}; + +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/detail/ConnectorDetail.hpp b/libs/brynet/net/detail/ConnectorDetail.hpp index 93e0f81..0a48d06 100644 --- a/libs/brynet/net/detail/ConnectorDetail.hpp +++ b/libs/brynet/net/detail/ConnectorDetail.hpp @@ -1,23 +1,14 @@ #pragma once +#include +#include +#include +#include +#include #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #ifdef BRYNET_HAVE_LANG_CXX17 #include #else @@ -26,136 +17,131 @@ namespace brynet { namespace net { namespace detail { - class AsyncConnectorDetail : public brynet::base::NonCopyable +class AsyncConnectorDetail : public brynet::base::NonCopyable +{ +protected: + void startWorkerThread() { - protected: - void startWorkerThread() - { #ifdef BRYNET_HAVE_LANG_CXX17 - std::lock_guard lck(mThreadGuard); + std::lock_guard lck(mThreadGuard); #else - std::lock_guard lck(mThreadGuard); + std::lock_guard lck(mThreadGuard); #endif - if (mThread != nullptr) - { - return; - } - - mIsRun = std::make_shared(true); - mWorkInfo = std::make_shared(); - mEventLoop = std::make_shared(); - - auto eventLoop = mEventLoop; - auto workerInfo = mWorkInfo; - auto isRun = mIsRun; - - mThread = std::make_shared([eventLoop, workerInfo, isRun]() { - while (*isRun) - { - detail::RunOnceCheckConnect(eventLoop, workerInfo); - } - - workerInfo->causeAllFailed(); - }); + if (mThread != nullptr) + { + return; } - void stopWorkerThread() - { + mIsRun = std::make_shared(true); + mWorkInfo = std::make_shared(); + mEventLoop = std::make_shared(); + + auto eventLoop = mEventLoop; + auto workerInfo = mWorkInfo; + auto isRun = mIsRun; + + mThread = std::make_shared([eventLoop, workerInfo, isRun]() { + while (*isRun) + { + detail::RunOnceCheckConnect(eventLoop, workerInfo); + } + + workerInfo->causeAllFailed(); + }); + } + + void stopWorkerThread() + { #ifdef BRYNET_HAVE_LANG_CXX17 - std::lock_guard lck(mThreadGuard); + std::lock_guard lck(mThreadGuard); #else - std::lock_guard lck(mThreadGuard); + std::lock_guard lck(mThreadGuard); #endif - if (mThread == nullptr) - { - return; - } - - mEventLoop->runAsyncFunctor([this]() { - *mIsRun = false; - }); - - try - { - if (mThread->joinable()) - { - mThread->join(); - } - } - catch (std::system_error & e) - { - (void)e; - } - - mEventLoop = nullptr; - mWorkInfo = nullptr; - mIsRun = nullptr; - mThread = nullptr; + if (mThread == nullptr) + { + return; } - void asyncConnect(const std::vector& options) + mEventLoop->runAsyncFunctor([this]() { + *mIsRun = false; + }); + + try { + if (mThread->joinable()) + { + mThread->join(); + } + } + catch (std::system_error& e) + { + (void) e; + } + + mEventLoop = nullptr; + mWorkInfo = nullptr; + mIsRun = nullptr; + mThread = nullptr; + } + + void asyncConnect(detail::ConnectOption option) + { #ifdef BRYNET_HAVE_LANG_CXX17 - std::shared_lock lck(mThreadGuard); + std::shared_lock lck(mThreadGuard); #else - std::lock_guard lck(mThreadGuard); + std::lock_guard lck(mThreadGuard); #endif - detail::ConnectOptionsInfo option; - for (const auto& func : options) - { - func(option); - } - if (option.completedCallback == nullptr && option.faledCallback == nullptr) - { - throw ConnectException("all callback is nullptr"); - } - if (option.ip.empty()) - { - throw ConnectException("addr is empty"); - } - - if (!(*mIsRun)) - { - throw ConnectException("work thread already stop"); - } - - auto workInfo = mWorkInfo; - auto address = detail::AsyncConnectAddr(std::move(option.ip), - option.port, - option.timeout, - std::move(option.completedCallback), - std::move(option.faledCallback), - std::move(option.processCallbacks)); - mEventLoop->runAsyncFunctor([workInfo, address]() { - workInfo->processConnect(address); - }); - } - - protected: - AsyncConnectorDetail() + if (option.completedCallback == nullptr && option.failedCallback == nullptr) { - mIsRun = std::make_shared(false); + throw ConnectException("all callback is nullptr"); } - - virtual ~AsyncConnectorDetail() + if (option.ip.empty()) { - stopWorkerThread(); + throw ConnectException("addr is empty"); } - private: - std::shared_ptr mEventLoop; + if (!(*mIsRun)) + { + throw ConnectException("work thread already stop"); + } - std::shared_ptr mWorkInfo; - std::shared_ptr mThread; + auto workInfo = mWorkInfo; + auto address = detail::AsyncConnectAddr(std::move(option.ip), + option.port, + option.timeout, + std::move(option.completedCallback), + std::move(option.failedCallback), + std::move(option.processCallbacks)); + mEventLoop->runAsyncFunctor([workInfo, address]() { + workInfo->processConnect(address); + }); + } + +protected: + AsyncConnectorDetail() + { + mIsRun = std::make_shared(false); + } + + virtual ~AsyncConnectorDetail() + { + stopWorkerThread(); + } + +private: + std::shared_ptr mEventLoop; + + std::shared_ptr mWorkInfo; + std::shared_ptr mThread; #ifdef BRYNET_HAVE_LANG_CXX17 - std::shared_mutex mThreadGuard; + std::shared_mutex mThreadGuard; #else - std::mutex mThreadGuard; + std::mutex mThreadGuard; #endif - std::shared_ptr mIsRun; - }; + std::shared_ptr mIsRun; +}; -} } } \ No newline at end of file +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/detail/ConnectorWorkInfo.hpp b/libs/brynet/net/detail/ConnectorWorkInfo.hpp index c0a8538..89da322 100644 --- a/libs/brynet/net/detail/ConnectorWorkInfo.hpp +++ b/libs/brynet/net/detail/ConnectorWorkInfo.hpp @@ -1,13 +1,14 @@ #pragma once -#include -#include - -#include #include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include #ifdef BRYNET_HAVE_LANG_CXX17 #include @@ -17,352 +18,341 @@ namespace brynet { namespace net { namespace detail { - class ConnectOptionsInfo; - using ConnectOptionFunc = std::function; +class AsyncConnectAddr final +{ +public: + using CompletedCallback = std::function; + using ProcessTcpSocketCallback = std::function; + using FailedCallback = std::function; - class AsyncConnectAddr final +public: + AsyncConnectAddr(std::string&& ip, + int port, + std::chrono::nanoseconds timeout, + CompletedCallback&& successCB, + FailedCallback&& failedCB, + std::vector&& processCallbacks) + : mIP(std::move(ip)), + mPort(port), + mTimeout(timeout), + mSuccessCB(std::move(successCB)), + mFailedCB(std::move(failedCB)), + mProcessCallbacks(std::move(processCallbacks)) { - public: - using CompletedCallback = std::function; - using ProcessTcpSocketCallback = std::function; - using FailedCallback = std::function; + } - public: - AsyncConnectAddr(std::string&& ip, - int port, - std::chrono::nanoseconds timeout, - CompletedCallback&& successCB, - FailedCallback&& failedCB, - std::vector&& 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& 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 mProcessCallbacks; - }; - - class ConnectorWorkInfo final : public brynet::base::NonCopyable + const std::string& getIP() const { - public: - using Ptr = std::shared_ptr; + return mIP; + } - ConnectorWorkInfo() BRYNET_NOEXCEPT + int getPort() const + { + return mPort; + } + + const CompletedCallback& getSuccessCB() const + { + return mSuccessCB; + } + + const FailedCallback& getFailedCB() const + { + return mFailedCB; + } + + const std::vector& 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 mProcessCallbacks; +}; + +class ConnectorWorkInfo final : public brynet::base::NonCopyable +{ +public: + using Ptr = std::shared_ptr; + + ConnectorWorkInfo() BRYNET_NOEXCEPT + { + mPoller.reset(brynet::base::poller_new()); + mPollResult.reset(brynet::base::stack_new(1024, sizeof(BrynetSocketFD))); + } + + void checkConnectStatus(int millSecond) + { + if (poller_poll(mPoller.get(), millSecond) <= 0) { - mPoller.reset(brynet::base::poller_new()); - mPollResult.reset(brynet::base::stack_new(1024, sizeof(BrynetSocketFD))); + return; } - void checkConnectStatus(int millsecond) + std::set totalFds; + std::set successFds; + + poller_visitor(mPoller.get(), brynet::base::WriteCheck, mPollResult.get()); + while (true) { - if (poller_poll(mPoller.get(), millsecond) <= 0) + auto p = stack_popfront(mPollResult.get()); + if (p == nullptr) { - return; + break; } - std::set totalFds; - std::set successFds; - - poller_visitor(mPoller.get(), brynet::base::WriteCheck, mPollResult.get()); - while (true) + const auto fd = *(BrynetSocketFD*) p; + totalFds.insert(fd); + if (isConnectSuccess(fd, false) && + !brynet::net::base::IsSelfConnect(fd)) { - auto p = stack_popfront(mPollResult.get()); - if (p == nullptr) - { - break; - } - - const auto fd = *(BrynetSocketFD*)p; - totalFds.insert(fd); - if (isConnectSuccess(fd, false) && - !brynet::net::base::IsSelfConnect(fd)) - { - successFds.insert(fd); - } - } - - for (auto fd : totalFds) - { - poller_remove(mPoller.get(), fd); - - const auto it = mConnectingInfos.find(fd); - if (it == mConnectingInfos.end()) - { - continue; - } - - auto socket = TcpSocket::Create(fd, false); - const auto& connectingInfo = it->second; - if (successFds.find(fd) != successFds.end()) - { - for (const auto& process : connectingInfo.processCallbacks) - { - process(*socket); - } - if (connectingInfo.successCB != nullptr) - { - connectingInfo.successCB(std::move(socket)); - } - } - else - { - if (connectingInfo.failedCB != nullptr) - { - connectingInfo.failedCB(); - } - } - - mConnectingInfos.erase(it); + successFds.insert(fd); } } - bool isConnectSuccess(BrynetSocketFD clientfd, bool willCheckWrite) const + for (auto fd : totalFds) { - if (willCheckWrite && !poller_check(mPoller.get(), clientfd, brynet::base::WriteCheck)) + poller_remove(mPoller.get(), fd); + + const auto it = mConnectingInfos.find(fd); + if (it == mConnectingInfos.end()) { - return false; + continue; } - int error = BRYNET_SOCKET_ERROR; - int len = sizeof(error); - if (getsockopt(clientfd, - SOL_SOCKET, - SO_ERROR, - (char*)&error, - (socklen_t*)&len) == BRYNET_SOCKET_ERROR) + auto socket = TcpSocket::Create(fd, false); + const auto& connectingInfo = it->second; + if (successFds.find(fd) != successFds.end()) { - return false; - } - - return error == 0; - } - - void checkTimeout() - { - for (auto it = mConnectingInfos.begin(); it != mConnectingInfos.end();) - { - const auto now = std::chrono::steady_clock::now(); - if ((now - it->second.startConnectTime) < it->second.timeout) + for (const auto& process : connectingInfo.processCallbacks) { - ++it; - continue; + process(*socket); } - - auto fd = it->first; - auto cb = it->second.failedCB; - - poller_remove(mPoller.get(), fd); - mConnectingInfos.erase(it++); - - brynet::net::base::SocketClose(fd); - if (cb != nullptr) + if (connectingInfo.successCB != nullptr) { - //TODO::don't modify mConnectingInfos in cb - cb(); + connectingInfo.successCB(std::move(socket)); } } - } - - void processConnect(const AsyncConnectAddr& addr) - { - struct sockaddr_in server_addr = sockaddr_in(); - BrynetSocketFD clientfd = BRYNET_INVALID_SOCKET; - -#ifdef BRYNET_PLATFORM_WINDOWS - const int ExpectedError = WSAEWOULDBLOCK; -#else - const int ExpectedError = EINPROGRESS; -#endif - int n = 0; - - brynet::net::base::InitSocket(); - - clientfd = brynet::net::base::SocketCreate(AF_INET, SOCK_STREAM, 0); - if (clientfd == BRYNET_INVALID_SOCKET) - { - goto FAILED; - } - - brynet::net::base::SocketNonblock(clientfd); - server_addr.sin_family = AF_INET; - inet_pton(AF_INET, addr.getIP().c_str(), &server_addr.sin_addr.s_addr); - server_addr.sin_port = static_cast(htons(addr.getPort())); - - n = connect(clientfd, (struct sockaddr*) & server_addr, sizeof(struct sockaddr)); - if (n == 0) - { - if (brynet::net::base::IsSelfConnect(clientfd)) - { - goto FAILED; - } - } - else if (BRYNET_ERRNO != ExpectedError) - { - goto FAILED; - } else { - ConnectingInfo ci; - ci.startConnectTime = std::chrono::steady_clock::now(); - ci.successCB = addr.getSuccessCB(); - ci.failedCB = addr.getFailedCB(); - ci.timeout = addr.getTimeout(); - ci.processCallbacks = addr.getProcessCallbacks(); - - mConnectingInfos[clientfd] = ci; - poller_add(mPoller.get(), clientfd, brynet::base::WriteCheck); - - return; - } - - if (addr.getSuccessCB() != nullptr) - { - auto tcpSocket = TcpSocket::Create(clientfd, false); - for (const auto& process : addr.getProcessCallbacks()) + if (connectingInfo.failedCB != nullptr) { - process(*tcpSocket); - } - addr.getSuccessCB()(std::move(tcpSocket)); - } - return; - - FAILED: - if (clientfd != BRYNET_INVALID_SOCKET) - { - brynet::net::base::SocketClose(clientfd); - clientfd = BRYNET_INVALID_SOCKET; - (void)clientfd; - } - if (addr.getFailedCB() != nullptr) - { - addr.getFailedCB()(); - } - } - - void causeAllFailed() - { - auto copyMap = mConnectingInfos; - mConnectingInfos.clear(); - - for (const auto& v : copyMap) - { - auto fd = v.first; - auto cb = v.second.failedCB; - - poller_remove(mPoller.get(), fd); - brynet::net::base::SocketClose(fd); - if (cb != nullptr) - { - cb(); + connectingInfo.failedCB(); } } + + mConnectingInfos.erase(it); } - - private: - class ConnectingInfo - { - public: - ConnectingInfo() - { - timeout = std::chrono::nanoseconds::zero(); - } - - std::chrono::steady_clock::time_point startConnectTime; - std::chrono::nanoseconds timeout; - AsyncConnectAddr::CompletedCallback successCB; - AsyncConnectAddr::FailedCallback failedCB; - std::vector processCallbacks; - }; - - std::map mConnectingInfos; - - class PollerDeleter - { - public: - void operator()(struct brynet::base::poller_s* ptr) const - { - brynet::base::poller_delete(ptr); - } - }; - class StackDeleter - { - public: - void operator()(struct brynet::base::stack_s* ptr) const - { - brynet::base::stack_delete(ptr); - } - }; - - std::unique_ptr mPoller; - std::unique_ptr mPollResult; - }; - - static void RunOnceCheckConnect( - const std::shared_ptr& eventLoop, - const std::shared_ptr& workerInfo) - { - eventLoop->loop(std::chrono::milliseconds(10).count()); - workerInfo->checkConnectStatus(0); - workerInfo->checkTimeout(); } - class ConnectOptionsInfo final + bool isConnectSuccess(BrynetSocketFD clientfd, bool willCheckWrite) const { - public: - ConnectOptionsInfo() - : - port(0), - timeout(std::chrono::seconds(10)) + if (willCheckWrite && !poller_check(mPoller.get(), clientfd, brynet::base::WriteCheck)) { + return false; } - std::string ip; - int port; + int error = BRYNET_SOCKET_ERROR; + int len = sizeof(error); + if (getsockopt(clientfd, + SOL_SOCKET, + SO_ERROR, + (char*) &error, + (socklen_t*) &len) == BRYNET_SOCKET_ERROR) + { + return false; + } + + return error == 0; + } + + void checkTimeout() + { + for (auto it = mConnectingInfos.begin(); it != mConnectingInfos.end();) + { + const auto now = std::chrono::steady_clock::now(); + if ((now - it->second.startConnectTime) < it->second.timeout) + { + ++it; + continue; + } + + auto fd = it->first; + auto cb = it->second.failedCB; + + poller_remove(mPoller.get(), fd); + mConnectingInfos.erase(it++); + + brynet::net::base::SocketClose(fd); + if (cb != nullptr) + { + //TODO::don't modify mConnectingInfos in cb + cb(); + } + } + } + + void processConnect(const AsyncConnectAddr& addr) + { + struct sockaddr_in server_addr = sockaddr_in(); + BrynetSocketFD clientfd = BRYNET_INVALID_SOCKET; + +#ifdef BRYNET_PLATFORM_WINDOWS + const int ExpectedError = WSAEWOULDBLOCK; +#else + const int ExpectedError = EINPROGRESS; +#endif + int n = 0; + + brynet::net::base::InitSocket(); + + clientfd = brynet::net::base::SocketCreate(AF_INET, SOCK_STREAM, 0); + if (clientfd == BRYNET_INVALID_SOCKET) + { + goto FAILED; + } + + brynet::net::base::SocketNonblock(clientfd); + server_addr.sin_family = AF_INET; + inet_pton(AF_INET, addr.getIP().c_str(), &server_addr.sin_addr.s_addr); + server_addr.sin_port = static_cast(htons(addr.getPort())); + + n = connect(clientfd, (struct sockaddr*) &server_addr, sizeof(struct sockaddr)); + if (n == 0) + { + if (brynet::net::base::IsSelfConnect(clientfd)) + { + goto FAILED; + } + } + else if (BRYNET_ERRNO != ExpectedError) + { + goto FAILED; + } + else + { + ConnectingInfo ci; + ci.startConnectTime = std::chrono::steady_clock::now(); + ci.successCB = addr.getSuccessCB(); + ci.failedCB = addr.getFailedCB(); + ci.timeout = addr.getTimeout(); + ci.processCallbacks = addr.getProcessCallbacks(); + + mConnectingInfos[clientfd] = ci; + poller_add(mPoller.get(), clientfd, brynet::base::WriteCheck); + + return; + } + + if (addr.getSuccessCB() != nullptr) + { + auto tcpSocket = TcpSocket::Create(clientfd, false); + for (const auto& process : addr.getProcessCallbacks()) + { + process(*tcpSocket); + } + addr.getSuccessCB()(std::move(tcpSocket)); + } + return; + + FAILED: + if (clientfd != BRYNET_INVALID_SOCKET) + { + brynet::net::base::SocketClose(clientfd); + clientfd = BRYNET_INVALID_SOCKET; + (void) clientfd; + } + if (addr.getFailedCB() != nullptr) + { + addr.getFailedCB()(); + } + } + + void causeAllFailed() + { + auto copyMap = mConnectingInfos; + mConnectingInfos.clear(); + + for (const auto& v : copyMap) + { + auto fd = v.first; + auto cb = v.second.failedCB; + + poller_remove(mPoller.get(), fd); + brynet::net::base::SocketClose(fd); + if (cb != nullptr) + { + cb(); + } + } + } + +private: + class ConnectingInfo + { + public: + ConnectingInfo() + { + timeout = std::chrono::nanoseconds::zero(); + } + + std::chrono::steady_clock::time_point startConnectTime; std::chrono::nanoseconds timeout; + AsyncConnectAddr::CompletedCallback successCB; + AsyncConnectAddr::FailedCallback failedCB; std::vector processCallbacks; - AsyncConnectAddr::CompletedCallback completedCallback; - AsyncConnectAddr::FailedCallback faledCallback; }; -} } } \ No newline at end of file + std::map mConnectingInfos; + + class PollerDeleter + { + public: + void operator()(struct brynet::base::poller_s* ptr) const + { + brynet::base::poller_delete(ptr); + } + }; + class StackDeleter + { + public: + void operator()(struct brynet::base::stack_s* ptr) const + { + brynet::base::stack_delete(ptr); + } + }; + + std::unique_ptr mPoller; + std::unique_ptr mPollResult; +}; + +static void RunOnceCheckConnect( + const std::shared_ptr& eventLoop, + const std::shared_ptr& 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 processCallbacks; + AsyncConnectAddr::CompletedCallback completedCallback; + AsyncConnectAddr::FailedCallback failedCallback; +}; + +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/detail/IOLoopData.hpp b/libs/brynet/net/detail/IOLoopData.hpp index 888f312..437d8b2 100644 --- a/libs/brynet/net/detail/IOLoopData.hpp +++ b/libs/brynet/net/detail/IOLoopData.hpp @@ -1,67 +1,62 @@ 锘#pragma once -#include -#include -#include -#include - #include #include +#include +#include namespace brynet { namespace net { namespace detail { - class TcpServiceDetail; +class TcpServiceDetail; - class IOLoopData : public brynet::base::NonCopyable, - public std::enable_shared_from_this +class IOLoopData : public brynet::base::NonCopyable, + public std::enable_shared_from_this +{ +public: + using Ptr = std::shared_ptr; + + static Ptr Create(EventLoop::Ptr eventLoop, + std::shared_ptr ioThread) { - public: - using Ptr = std::shared_ptr; - - static Ptr Create(EventLoop::Ptr eventLoop, - std::shared_ptr ioThread) + class make_shared_enabler : public IOLoopData { - class make_shared_enabler : public IOLoopData - { - public: - make_shared_enabler(EventLoop::Ptr eventLoop, - std::shared_ptr ioThread) - : - IOLoopData(std::move(eventLoop), std::move(ioThread)) - {} - }; + public: + make_shared_enabler(EventLoop::Ptr eventLoop, + std::shared_ptr ioThread) + : IOLoopData(std::move(eventLoop), std::move(ioThread)) + {} + }; - return std::make_shared(std::move(eventLoop), - std::move(ioThread)); - } + return std::make_shared(std::move(eventLoop), + std::move(ioThread)); + } - const EventLoop::Ptr& getEventLoop() const - { - return mEventLoop; - } + const EventLoop::Ptr& getEventLoop() const + { + return mEventLoop; + } - protected: - const std::shared_ptr& getIOThread() const - { - return mIOThread; - } +protected: + const std::shared_ptr& getIOThread() const + { + return mIOThread; + } - IOLoopData(EventLoop::Ptr eventLoop, - std::shared_ptr ioThread) - : - mEventLoop(std::move(eventLoop)), - mIOThread(std::move(ioThread)) - {} - virtual ~IOLoopData() = default; + IOLoopData(EventLoop::Ptr eventLoop, + std::shared_ptr ioThread) + : mEventLoop(std::move(eventLoop)), + mIOThread(std::move(ioThread)) + {} + virtual ~IOLoopData() = default; - const EventLoop::Ptr mEventLoop; + const EventLoop::Ptr mEventLoop; - private: - std::shared_ptr mIOThread; +private: + std::shared_ptr mIOThread; - friend class TcpServiceDetail; - }; + friend class TcpServiceDetail; +}; - using IOLoopDataPtr = std::shared_ptr; +using IOLoopDataPtr = std::shared_ptr; -} } } \ No newline at end of file +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/detail/ListenThreadDetail.hpp b/libs/brynet/net/detail/ListenThreadDetail.hpp index 634fc80..792a1d5 100644 --- a/libs/brynet/net/detail/ListenThreadDetail.hpp +++ b/libs/brynet/net/detail/ListenThreadDetail.hpp @@ -1,169 +1,168 @@ #pragma once -#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include #include +#include +#include #include -#include -#include - -#include -#include -#include -#include -#include -#include namespace brynet { namespace net { namespace detail { - class ListenThreadDetail : public brynet::base::NonCopyable +class ListenThreadDetail : public brynet::base::NonCopyable +{ +protected: + using AccepCallback = std::function; + using TcpSocketProcessCallback = std::function; + + void startListen() { - protected: - using AccepCallback = std::function; - using TcpSocketProcessCallback = std::function; + std::lock_guard lck(mListenThreadGuard); - void startListen() + if (mListenThread != nullptr) { - std::lock_guard lck(mListenThreadGuard); - - if (mListenThread != nullptr) - { - return; - } - - const auto fd = brynet::net::base::Listen(mIsIPV6, mIP.c_str(), mPort, 512); - if (fd == BRYNET_INVALID_SOCKET) - { - throw BrynetCommonException( - std::string("listen error of:") + std::to_string(BRYNET_ERRNO)); - } - - mRunListen = std::make_shared(true); - - auto listenSocket = std::shared_ptr(ListenSocket::Create(fd)); - auto isRunListen = mRunListen; - auto callback = mCallback; - auto processCallbacks = mProcessCallbacks; - mListenThread = std::make_shared( - [isRunListen, listenSocket, callback, processCallbacks]() mutable { - while (*isRunListen) - { - auto clientSocket = runOnceListen(listenSocket); - if (clientSocket == nullptr) - { - continue; - } - - if (*isRunListen) - { - for (const auto& process : processCallbacks) - { - process(*clientSocket); - } - callback(std::move(clientSocket)); - } - } - }); + return; } - void stopListen() + const auto fd = brynet::net::base::Listen(mIsIPV6, mIP.c_str(), mPort, 512, mEnabledReusePort); + if (fd == BRYNET_INVALID_SOCKET) { - std::lock_guard lck(mListenThreadGuard); + throw BrynetCommonException( + std::string("listen error of:") + std::to_string(BRYNET_ERRNO)); + } - if (mListenThread == nullptr) - { - return; - } + mRunListen = std::make_shared(true); - *mRunListen = false; - auto selfIP = mIP; - if (selfIP == "0.0.0.0") - { - selfIP = "127.0.0.1"; - } + auto listenSocket = std::shared_ptr(ListenSocket::Create(fd)); + auto isRunListen = mRunListen; + auto callback = mCallback; + auto processCallbacks = mProcessCallbacks; + mListenThread = std::make_shared( + [isRunListen, listenSocket, callback, processCallbacks]() mutable { + while (*isRunListen) + { + auto clientSocket = runOnceListen(listenSocket); + if (clientSocket == nullptr) + { + continue; + } - auto connector = AsyncConnector::Create(); - connector->startWorkerThread(); + if (*isRunListen) + { + for (const auto& process : processCallbacks) + { + process(*clientSocket); + } + callback(std::move(clientSocket)); + } + } + }); + } - wrapper::SocketConnectBuilder connectBuilder; - connectBuilder - .configureConnector(connector) - .configureConnectOptions({ - ConnectOption::WithTimeout(std::chrono::seconds(2)), - ConnectOption::WithAddr(selfIP, mPort) - }) + void stopListen() + { + std::lock_guard lck(mListenThreadGuard); + + if (mListenThread == nullptr) + { + return; + } + + *mRunListen = false; + auto selfIP = mIP; + if (selfIP == "0.0.0.0") + { + selfIP = "127.0.0.1"; + } + + auto connector = AsyncConnector::Create(); + connector->startWorkerThread(); + + //TODO:: if the listen enable reuse_port, one time connect may be can't wakeup listen. + wrapper::SocketConnectBuilder connectBuilder; + (void) connectBuilder + .WithConnector(connector) + .WithTimeout(std::chrono::seconds(2)) + .WithAddr(selfIP, mPort) .syncConnect(); - try - { - if (mListenThread->joinable()) - { - mListenThread->join(); - } - } - catch (std::system_error & e) - { - (void)e; - } - mListenThread = nullptr; - } - - protected: - ListenThreadDetail(bool isIPV6, - const std::string& ip, - int port, - const AccepCallback& callback, - const std::vector& processCallbacks) - : - mIsIPV6(isIPV6), - mIP(ip), - mPort(port), - mCallback(callback), - mProcessCallbacks(processCallbacks) + try { - if (mCallback == nullptr) + if (mListenThread->joinable()) { - throw BrynetCommonException("accept callback is nullptr"); + mListenThread->join(); } - mRunListen = std::make_shared(false); } - - virtual ~ListenThreadDetail() BRYNET_NOEXCEPT + catch (std::system_error& e) { - stopListen(); + (void) e; } + mListenThread = nullptr; + } - private: - static brynet::net::TcpSocket::Ptr runOnceListen(const std::shared_ptr& listenSocket) +protected: + ListenThreadDetail(bool isIPV6, + const std::string& ip, + int port, + const AccepCallback& callback, + const std::vector& processCallbacks, + bool enabledReusePort) + : mIsIPV6(isIPV6), + mIP(ip), + mPort(port), + mCallback(callback), + mProcessCallbacks(processCallbacks), + mEnabledReusePort(enabledReusePort) + { + if (mCallback == nullptr) { - try - { - return listenSocket->accept(); - } - catch (const EintrError & e) - { - std::cerr << "accept eintr execption:" << e.what() << std::endl; - } - catch (const AcceptError & e) - { - std::cerr << "accept execption:" << e.what() << std::endl; - } + throw BrynetCommonException("accept callback is nullptr"); + } + mRunListen = std::make_shared(false); + } - return nullptr; + virtual ~ListenThreadDetail() BRYNET_NOEXCEPT + { + stopListen(); + } + +private: + static brynet::net::TcpSocket::Ptr runOnceListen(const std::shared_ptr& listenSocket) + { + try + { + return listenSocket->accept(); + } + catch (const EintrError& e) + { + std::cerr << "accept eintr execption:" << e.what() << std::endl; + } + catch (const AcceptError& e) + { + std::cerr << "accept execption:" << e.what() << std::endl; } - private: - const bool mIsIPV6; - const std::string mIP; - const int mPort; - const AccepCallback mCallback; - const std::vector mProcessCallbacks; + return nullptr; + } - std::shared_ptr mRunListen; - std::shared_ptr mListenThread; - std::mutex mListenThreadGuard; - }; +private: + const bool mIsIPV6; + const std::string mIP; + const int mPort; + const AccepCallback mCallback; + const std::vector mProcessCallbacks; + const bool mEnabledReusePort; -} } } + std::shared_ptr mRunListen; + std::shared_ptr mListenThread; + std::mutex mListenThreadGuard; +}; + +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/detail/TCPServiceDetail.hpp b/libs/brynet/net/detail/TCPServiceDetail.hpp index d64c422..7d251fe 100644 --- a/libs/brynet/net/detail/TCPServiceDetail.hpp +++ b/libs/brynet/net/detail/TCPServiceDetail.hpp @@ -1,198 +1,177 @@ 锘#pragma once -#include -#include -#include -#include -#include -#include -#include - -#include #include -#include +#include #include #include +#include +#include #include -#include +#include +#include +#include +#include +#include namespace brynet { namespace net { namespace detail { - class TcpServiceDetail : public brynet::base::NonCopyable +class TcpServiceDetail : public brynet::base::NonCopyable +{ +protected: + using FrameCallback = std::function; + const static unsigned int sDefaultLoopTimeOutMS = 100; + + void startWorkerThread(size_t threadNum, + FrameCallback callback = nullptr) { - protected: - using FrameCallback = std::function; - const static unsigned int sDefaultLoopTimeOutMS = 100; + std::lock_guard lck(mServiceGuard); + std::lock_guard lock(mIOLoopGuard); - void startWorkerThread(size_t threadNum, - FrameCallback callback = nullptr) + if (!mIOLoopDatas.empty()) { - std::lock_guard lck(mServiceGuard); - std::lock_guard lock(mIOLoopGuard); - - if (!mIOLoopDatas.empty()) - { - return; - } - - mRunIOLoop = std::make_shared(true); - - mIOLoopDatas.resize(threadNum); - for (auto& v : mIOLoopDatas) - { - auto eventLoop = std::make_shared(); - auto runIoLoop = mRunIOLoop; - v = IOLoopData::Create(eventLoop, - std::make_shared( - [callback, runIoLoop, eventLoop]() { - while (*runIoLoop) - { - eventLoop->loopCompareNearTimer(sDefaultLoopTimeOutMS); - if (callback != nullptr) - { - callback(eventLoop); - } - } - })); - } + return; } - void stopWorkerThread() + mRunIOLoop = std::make_shared(true); + + mIOLoopDatas.resize(threadNum); + for (auto& v : mIOLoopDatas) { - std::lock_guard lck(mServiceGuard); - std::lock_guard lock(mIOLoopGuard); + auto eventLoop = std::make_shared(); + auto runIoLoop = mRunIOLoop; + v = IOLoopData::Create(eventLoop, + std::make_shared( + [callback, runIoLoop, eventLoop]() { + while (*runIoLoop) + { + eventLoop->loopCompareNearTimer(sDefaultLoopTimeOutMS); + if (callback != nullptr) + { + callback(eventLoop); + } + } + })); + } + } - *mRunIOLoop = false; + void stopWorkerThread() + { + std::lock_guard lck(mServiceGuard); + std::lock_guard lock(mIOLoopGuard); - for (const auto& v : mIOLoopDatas) + *mRunIOLoop = false; + + for (const auto& v : mIOLoopDatas) + { + v->getEventLoop()->wakeup(); + try { - v->getEventLoop()->wakeup(); - try + if (v->getIOThread()->joinable()) { - if (v->getIOThread()->joinable()) - { - v->getIOThread()->join(); - } - } - catch (std::system_error & e) - { - (void)e; + v->getIOThread()->join(); } } - mIOLoopDatas.clear(); - } - - template - bool addTcpConnection(TcpSocket::Ptr socket, - const Options& ... options) - { - return _addTcpConnection(std::move(socket), { options... }); - } - - EventLoop::Ptr getRandomEventLoop() - { - std::lock_guard lock(mIOLoopGuard); - - const auto ioLoopSize = mIOLoopDatas.size(); - if (ioLoopSize == 0) + catch (std::system_error& e) { - return nullptr; - } - else if (ioLoopSize == 1) - { - return mIOLoopDatas.front()->getEventLoop(); - } - else - { - return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop(); + (void) e; } } + mIOLoopDatas.clear(); + } - TcpServiceDetail() BRYNET_NOEXCEPT - : - mRandom(static_cast( - std::chrono::system_clock::now().time_since_epoch().count())) + bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption option) + { + if (option.maxRecvBufferSize <= 0) { - mRunIOLoop = std::make_shared(false); + throw BrynetCommonException("buffer size is zero"); } - virtual ~TcpServiceDetail() BRYNET_NOEXCEPT + EventLoop::Ptr eventLoop; + if (option.forceSameThreadLoop) { - stopWorkerThread(); + eventLoop = getSameThreadEventLoop(); + } + else + { + eventLoop = getRandomEventLoop(); + } + if (eventLoop == nullptr) + { + return false; } - bool _addTcpConnection(TcpSocket::Ptr socket, - const std::vector& optionFuncs) + auto wrapperEnterCallback = [option](const TcpConnection::Ptr& tcpConnection) { + for (const auto& callback : option.enterCallback) + { + callback(tcpConnection); + } + }; + + if (option.useSSL && option.sslHelper == nullptr) { - AddSocketOptionInfo options; - for (const auto& v : optionFuncs) - { - if (v != nullptr) - { - v(options); - } - } - - if (options.maxRecvBufferSize <= 0) - { - throw BrynetCommonException("buffer size is zero"); - } - - EventLoop::Ptr eventLoop; - if (options.forceSameThreadLoop) - { - eventLoop = getSameThreadEventLoop(); - } - else - { - eventLoop = getRandomEventLoop(); - } - if (eventLoop == nullptr) - { - return false; - } - - auto wrapperEnterCallback = [options](const TcpConnection::Ptr& tcpConnection) { - for (const auto& callback : options.enterCallback) - { - callback(tcpConnection); - } - }; - - if (options.useSSL && options.sslHelper == nullptr) - { - options.sslHelper = SSLHelper::Create(); - } - - TcpConnection::Create(std::move(socket), - options.maxRecvBufferSize, - wrapperEnterCallback, - eventLoop, - options.sslHelper); - - return true; + option.sslHelper = SSLHelper::Create(); } - EventLoop::Ptr getSameThreadEventLoop() + TcpConnection::Create(std::move(socket), + option.maxRecvBufferSize, + wrapperEnterCallback, + eventLoop, + option.sslHelper); + + return true; + } + + EventLoop::Ptr getRandomEventLoop() + { + std::lock_guard lock(mIOLoopGuard); + + const auto ioLoopSize = mIOLoopDatas.size(); + if (ioLoopSize == 0) { - std::lock_guard lock(mIOLoopGuard); - for (const auto& v : mIOLoopDatas) - { - if (v->getEventLoop()->isInLoopThread()) - { - return v->getEventLoop(); - } - } return nullptr; } + else if (ioLoopSize == 1) + { + return mIOLoopDatas.front()->getEventLoop(); + } + else + { + return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop(); + } + } - private: - std::vector mIOLoopDatas; - mutable std::mutex mIOLoopGuard; - std::shared_ptr mRunIOLoop; + TcpServiceDetail() BRYNET_NOEXCEPT + : mRandom(static_cast( + std::chrono::system_clock::now().time_since_epoch().count())) + { + mRunIOLoop = std::make_shared(false); + } - std::mutex mServiceGuard; - std::mt19937 mRandom; - }; + virtual ~TcpServiceDetail() BRYNET_NOEXCEPT + { + stopWorkerThread(); + } -} } } + EventLoop::Ptr getSameThreadEventLoop() + { + std::lock_guard lock(mIOLoopGuard); + for (const auto& v : mIOLoopDatas) + { + if (v->getEventLoop()->isInLoopThread()) + { + return v->getEventLoop(); + } + } + return nullptr; + } + +private: + std::vector mIOLoopDatas; + mutable std::mutex mIOLoopGuard; + std::shared_ptr mRunIOLoop; + + std::mutex mServiceGuard; + std::mt19937 mRandom; +}; + +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/detail/WakeupChannel.hpp b/libs/brynet/net/detail/WakeupChannel.hpp index 83e3c16..924d471 100644 --- a/libs/brynet/net/detail/WakeupChannel.hpp +++ b/libs/brynet/net/detail/WakeupChannel.hpp @@ -1,15 +1,6 @@ 锘#pragma once -#include -#include -#include -#include -#include -#include -#include - #include -#include #ifdef BRYNET_PLATFORM_WINDOWS #include #endif @@ -20,120 +11,119 @@ namespace brynet { namespace net { namespace detail { #ifdef BRYNET_PLATFORM_WINDOWS - class WakeupChannel final : public Channel, public brynet::base::NonCopyable +class WakeupChannel final : public Channel, public brynet::base::NonCopyable +{ +public: + explicit WakeupChannel(HANDLE iocp) + : mIOCP(iocp), + mWakeupOvl(port::Win::OverlappedType::OverlappedRecv) { - public: - explicit WakeupChannel(HANDLE iocp) - : - mIOCP(iocp), - mWakeupOvl(port::Win::OverlappedType::OverlappedRecv) - { - } + } - bool wakeup() BRYNET_NOEXCEPT - { - return PostQueuedCompletionStatus(mIOCP, - 0, - reinterpret_cast(this), - &mWakeupOvl.base); - } + bool wakeup() BRYNET_NOEXCEPT + { + return PostQueuedCompletionStatus(mIOCP, + 0, + reinterpret_cast(this), + &mWakeupOvl.base); + } - private: - void canRecv() BRYNET_NOEXCEPT override - { - ; - } +private: + void canRecv(bool) BRYNET_NOEXCEPT override + { + ; + } - void canSend() BRYNET_NOEXCEPT override - { - ; - } + void canSend() BRYNET_NOEXCEPT override + { + ; + } - void onClose() BRYNET_NOEXCEPT override - { - ; - } + void onClose() BRYNET_NOEXCEPT override + { + ; + } - HANDLE mIOCP; - port::Win::OverlappedExt mWakeupOvl; - }; + HANDLE mIOCP; + port::Win::OverlappedExt mWakeupOvl; +}; #elif defined BRYNET_PLATFORM_LINUX - class WakeupChannel final : public Channel, public brynet::base::NonCopyable +class WakeupChannel final : public Channel, public brynet::base::NonCopyable +{ +public: + explicit WakeupChannel(BrynetSocketFD fd) + : mUniqueFd(fd) { - public: - explicit WakeupChannel(BrynetSocketFD fd) : mUniqueFd(fd) - { - } + } - bool wakeup() - { - uint64_t one = 1; - return write(mUniqueFd.getFD(), &one, sizeof one) > 0; - } + bool wakeup() + { + uint64_t one = 1; + return write(mUniqueFd.getFD(), &one, sizeof one) > 0; + } - private: - void canRecv() override +private: + void canRecv(bool) override + { + char temp[1024 * 10]; + while (true) { - char temp[1024 * 10]; - while (true) + auto n = read(mUniqueFd.getFD(), temp, sizeof(temp)); + if (n == -1 || static_cast(n) < sizeof(temp)) { - auto n = read(mUniqueFd.getFD(), temp, sizeof(temp)); - if (n == -1 || static_cast(n) < sizeof(temp)) - { - break; - } + break; } } + } - void canSend() override - { - } + void canSend() override + { + } - void onClose() override - { - } + void onClose() override + { + } - private: - UniqueFd mUniqueFd; - }; +private: + UniqueFd mUniqueFd; +}; #elif defined BRYNET_PLATFORM_DARWIN - class WakeupChannel final : public Channel, public brynet::base::NonCopyable +class WakeupChannel final : public Channel, public brynet::base::NonCopyable +{ +public: + explicit WakeupChannel(int kqueuefd, int ident) + : mKqueueFd(kqueuefd), + mUserEvent(ident) { - public: - explicit WakeupChannel(int kqueuefd, int ident) - : - mKqueueFd(kqueuefd), - mUserEvent(ident) - { - } + } - bool wakeup() - { - struct kevent ev; - EV_SET(&ev, mUserEvent, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); + bool wakeup() + { + struct kevent ev; + EV_SET(&ev, mUserEvent, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); - struct timespec timeout = { 0, 0 }; - return kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout) == 0; - } + struct timespec timeout = {0, 0}; + return kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout) == 0; + } - private: - void canRecv() override - { - } +private: + void canRecv(bool) override + { + } - void canSend() override - { - } + void canSend() override + { + } - void onClose() override - { - } + void onClose() override + { + } - private: - int mKqueueFd; - int mUserEvent; - }; +private: + int mKqueueFd; + int mUserEvent; +}; #endif -} } } \ No newline at end of file +}}}// namespace brynet::net::detail diff --git a/libs/brynet/net/http/HttpFormat.hpp b/libs/brynet/net/http/HttpFormat.hpp index e6f4dcd..d386269 100644 --- a/libs/brynet/net/http/HttpFormat.hpp +++ b/libs/brynet/net/http/HttpFormat.hpp @@ -1,222 +1,234 @@ #pragma once -#include #include -#include #include +#include +#include namespace brynet { namespace net { namespace http { - class HttpQueryParameter final +class HttpQueryParameter final +{ +public: + void add(const std::string& k, const std::string& v) { - public: - void add(const std::string& k, const std::string& v) + if (!mParameter.empty()) { - if (!mParameter.empty()) - { - mParameter += "&"; - } - - mParameter += k; - mParameter += "="; - mParameter += v; + mParameter += "&"; } - const std::string& getResult() const - { - return mParameter; - } + mParameter += k; + mParameter += "="; + mParameter += v; + } - private: - std::string mParameter; + const std::string& getResult() const + { + return mParameter; + } + +private: + std::string mParameter; +}; + +class HttpRequest final +{ +public: + enum class HTTP_METHOD + { + HTTP_METHOD_HEAD, + HTTP_METHOD_GET, + HTTP_METHOD_POST, + HTTP_METHOD_PUT, + HTTP_METHOD_DELETE, + HTTP_METHOD_MAX }; - class HttpRequest final + HttpRequest() { - public: + setMethod(HTTP_METHOD::HTTP_METHOD_GET); + } - enum class HTTP_METHOD - { - HTTP_METHOD_HEAD, - HTTP_METHOD_GET, - HTTP_METHOD_POST, - HTTP_METHOD_PUT, - HTTP_METHOD_DELETE, - HTTP_METHOD_MAX - }; + void setMethod(HTTP_METHOD protocol) + { + mMethod = protocol; + assert(mMethod > HTTP_METHOD::HTTP_METHOD_HEAD && + mMethod < HTTP_METHOD::HTTP_METHOD_MAX); + } - HttpRequest() + void setHost(const std::string& host) + { + addHeadValue("Host", host); + } + + void setUrl(const std::string& url) + { + mUrl = url; + } + + void setCookie(const std::string& v) + { + addHeadValue("Cookie", v); + } + + void setContentType(const std::string& v) + { + addHeadValue("Content-Type", v); + } + + void setQuery(const std::string& query) + { + mQuery = query; + } + + void setBody(const std::string& body) + { + addHeadValue("Content-Length", std::to_string(body.size())); + mBody = body; + } + + void setBody(std::string&& body) + { + addHeadValue("Content-Length", std::to_string(body.size())); + mBody = std::move(body); + } + + void addHeadValue(const std::string& field, + const std::string& value) + { + mHeadField[field] = value; + } + + std::string getResult() const + { + const auto MethodMax = static_cast(HTTP_METHOD::HTTP_METHOD_MAX); + const static std::array HttpMethodString = + {"HEAD", "GET", "POST", "PUT", "DELETE"}; + + std::string ret; + if (mMethod >= HTTP_METHOD::HTTP_METHOD_HEAD && + mMethod < HTTP_METHOD::HTTP_METHOD_MAX) { - setMethod(HTTP_METHOD::HTTP_METHOD_GET); + ret += HttpMethodString[static_cast(mMethod)]; } - void setMethod(HTTP_METHOD protocol) + ret += " "; + ret += mUrl; + if (!mQuery.empty()) { - mMethod = protocol; - assert(mMethod > HTTP_METHOD::HTTP_METHOD_HEAD && - mMethod < HTTP_METHOD::HTTP_METHOD_MAX); + ret += "?"; + ret += mQuery; } - void setHost(const std::string& host) + ret += " HTTP/1.1\r\n"; + + for (auto& v : mHeadField) { - addHeadValue("Host", host); - } - - void setUrl(const std::string& url) - { - mUrl = url; - } - - void setCookie(const std::string& v) - { - addHeadValue("Cookie", v); - } - - void setContentType(const std::string& v) - { - addHeadValue("Content-Type", v); - } - - void setQuery(const std::string& query) - { - mQuery = query; - } - - void setBody(const std::string& body) - { - mBody = body; - addHeadValue("Content-Length", std::to_string(body.size())); - } - - void addHeadValue(const std::string& field, - const std::string& value) - { - mHeadField[field] = value; - } - - std::string getResult() const - { - const auto MethodMax = static_cast(HTTP_METHOD::HTTP_METHOD_MAX); - const static std::array 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(mMethod)]; - } - - ret += " "; - ret += mUrl; - if (!mQuery.empty()) - { - ret += "?"; - ret += mQuery; - } - - ret += " HTTP/1.1\r\n"; - - for (auto& v : mHeadField) - { - ret += v.first; - ret += ": "; - ret += v.second; - ret += "\r\n"; - } - + ret += v.first; + ret += ": "; + ret += v.second; ret += "\r\n"; - - if (!mBody.empty()) - { - ret += mBody; - } - - return ret; } - private: - std::string mUrl; - std::string mQuery; - std::string mBody; - HTTP_METHOD mMethod; - std::map mHeadField; + ret += "\r\n"; + + if (!mBody.empty()) + { + ret += mBody; + } + + return ret; + } + +private: + std::string mUrl; + std::string mQuery; + std::string mBody; + HTTP_METHOD mMethod; + std::map mHeadField; +}; + +class HttpResponse final +{ +public: + enum class HTTP_RESPONSE_STATUS + { + NONE, + OK = 200, }; - class HttpResponse final + HttpResponse() + : mStatus(HTTP_RESPONSE_STATUS::OK) { - public: - enum class HTTP_RESPONSE_STATUS - { - NONE, - OK = 200, - }; + } - HttpResponse() : mStatus(HTTP_RESPONSE_STATUS::OK) - { - } + void setStatus(HTTP_RESPONSE_STATUS status) + { + mStatus = status; + } - void setStatus(HTTP_RESPONSE_STATUS status) - { - mStatus = status; - } + void setContentType(const std::string& v) + { + addHeadValue("Content-Type", v); + } - void setContentType(const std::string& v) - { - addHeadValue("Content-Type", v); - } + void addHeadValue(const std::string& field, + const std::string& value) + { + mHeadField[field] = value; + } - void addHeadValue(const std::string& field, - const std::string& value) - { - mHeadField[field] = value; - } + void setBody(const std::string& body) + { + addHeadValue("Content-Length", std::to_string(body.size())); + mBody = body; + } - void setBody(const std::string& body) - { - mBody = body; - addHeadValue("Content-Length", std::to_string(body.size())); - } + void setBody(std::string&& body) + { + addHeadValue("Content-Length", std::to_string(body.size())); + mBody = std::move(body); + } - std::string getResult() const - { - std::string ret = "HTTP/1.1 "; + std::string getResult() const + { + std::string ret = "HTTP/1.1 "; - ret += std::to_string(static_cast(mStatus)); - switch (mStatus) - { + ret += std::to_string(static_cast(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 mHeadField; - std::string mBody; - }; + ret += "\r\n"; -} } } \ No newline at end of file + 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 mHeadField; + std::string mBody; +}; + +}}}// namespace brynet::net::http diff --git a/libs/brynet/net/http/HttpParser.hpp b/libs/brynet/net/http/HttpParser.hpp index 9b79680..c706c11 100644 --- a/libs/brynet/net/http/HttpParser.hpp +++ b/libs/brynet/net/http/HttpParser.hpp @@ -1,318 +1,327 @@ #pragma once -#include +#include +#include #include #include -#include -#include +#include #include "http_parser.h" -#include namespace brynet { namespace net { namespace http { - class HttpService; +class HttpService; - class HTTPParser +class HTTPParser +{ +public: + using Ptr = std::shared_ptr; + + explicit HTTPParser(http_parser_type parserType) + : mParserType(parserType) { - public: - using Ptr = std::shared_ptr; + mLastWasValue = true; - explicit HTTPParser(http_parser_type parserType) - : - mParserType(parserType) + mIsUpgrade = false; + mIsWebSocket = false; + mIsKeepAlive = false; + mISCompleted = false; + mStatusCode = 0; + mWSFrameType = WebSocketFormat::WebSocketFrameType::ERROR_FRAME; + mSettings.on_status = sStatusHandle; + mSettings.on_body = sBodyHandle; + mSettings.on_url = sUrlHandle; + mSettings.on_header_field = sHeadField; + mSettings.on_header_value = sHeadValue; + mSettings.on_headers_complete = sHeadComplete; + mSettings.on_message_begin = sMessageBegin; + mSettings.on_message_complete = sMessageEnd; + mSettings.on_chunk_header = sChunkHeader; + mSettings.on_chunk_complete = sChunkComplete; + mParser.data = this; + + http_parser_init(&mParser, mParserType); + } + + virtual ~HTTPParser() = default; + + bool isUpgrade() const + { + return mIsUpgrade; + } + + bool isWebSocket() const + { + return mIsWebSocket; + } + + bool isKeepAlive() const + { + return mIsKeepAlive; + } + + + bool isCompleted() const + { + return mISCompleted; + } + + int method() const + { + // mMethod's value defined in http_method, such as HTTP_GET銆丠TTP_POST. + // if mMethod is -1, it's invalid. + return mMethod; + } + + const std::string& getPath() const + { + return mPath; + } + + const std::string& getQuery() const + { + return mQuery; + } + + const std::string& getStatus() const + { + return mStatus; + } + + int getStatusCode() const + { + return mStatusCode; + } + + bool hasEntry(const std::string& key, + const std::string& value) const + { + const auto it = mHeadValues.find(key); + return it != mHeadValues.end() && value == it->second; + } + + bool hasKey(const std::string& key) const + { + return mHeadValues.find(key) != mHeadValues.end(); + } + + const std::string& getValue(const std::string& key) const + { + const static std::string emptystr(""); + + auto it = mHeadValues.find(key); + if (it != mHeadValues.end()) { - mLastWasValue = true; + return (*it).second; + } + else + { + return emptystr; + } + } - mIsWebSocket = false; - mIsKeepAlive = false; - mISCompleted = false; - mStatusCode = 0; - mWSFrameType = WebSocketFormat::WebSocketFrameType::ERROR_FRAME; - mSettings.on_status = sStatusHandle; - mSettings.on_body = sBodyHandle; - mSettings.on_url = sUrlHandle; - mSettings.on_header_field = sHeadField; - mSettings.on_header_value = sHeadValue; - mSettings.on_headers_complete = sHeadComplete; - mSettings.on_message_begin = sMessageBegin; - mSettings.on_message_complete = sMessageEnd; - mSettings.on_chunk_header = sChunkHeader; - mSettings.on_chunk_complete = sChunkComplete; - mParser.data = this; + const std::string& getBody() const + { + return mBody; + } + std::string& getWSCacheFrame() + { + return mWSCacheFrame; + } + + std::string& getWSParseString() + { + return mWSParsePayload; + } + + WebSocketFormat::WebSocketFrameType getWSFrameType() const + { + return mWSFrameType; + } + + void cacheWSFrameType(WebSocketFormat::WebSocketFrameType frameType) + { + mWSFrameType = frameType; + } + +private: + void clearParse() + { + mMethod = -1; + mIsUpgrade = false; + mIsWebSocket = false; + mISCompleted = false; + mLastWasValue = true; + mUrl.clear(); + mQuery.clear(); + mBody.clear(); + mStatus.clear(); + mCurrentField.clear(); + mCurrentValue.clear(); + mHeadValues.clear(); + mPath.clear(); + } + + size_t tryParse(const char* buffer, size_t len) + { + const size_t nparsed = http_parser_execute(&mParser, &mSettings, buffer, len); + if (mISCompleted) + { + mIsUpgrade = mParser.upgrade; + mIsWebSocket = mIsUpgrade && hasEntry("Upgrade", "websocket"); + mIsKeepAlive = hasEntry("Connection", "Keep-Alive"); + mMethod = mParser.method; http_parser_init(&mParser, mParserType); } - virtual ~HTTPParser() = default; + return nparsed; + } - bool isWebSocket() const +private: + static int sChunkHeader(http_parser* hp) + { + (void) hp; + return 0; + } + + static int sChunkComplete(http_parser* hp) + { + (void) hp; + return 0; + } + + static int sMessageBegin(http_parser* hp) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + httpParser->clearParse(); + + return 0; + } + + static int sMessageEnd(http_parser* hp) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + httpParser->mISCompleted = true; + return 0; + } + + static int sHeadComplete(http_parser* hp) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + + if (httpParser->mUrl.empty()) { - return mIsWebSocket; - } - - bool isKeepAlive() const - { - return mIsKeepAlive; - } - - int method() const - { - // mMethod's value defined in http_method, such as HTTP_GET銆丠TTP_POST. - // if mMethod is -1, it's invalid. - return mMethod; - } - - const std::string& getPath() const - { - return mPath; - } - - const std::string& getQuery() const - { - return mQuery; - } - - const std::string& getStatus() const - { - return mStatus; - } - - int getStatusCode() const - { - return mStatusCode; - } - - bool hasEntry(const std::string& key, - const std::string& value) const - { - const auto it = mHeadValues.find(key); - return it != mHeadValues.end() && value == it->second; - } - - bool hasKey(const std::string& key) const - { - return mHeadValues.find(key) != mHeadValues.end(); - } - - const std::string& getValue(const std::string& key) const - { - const static std::string emptystr(""); - - auto it = mHeadValues.find(key); - if (it != mHeadValues.end()) - { - return (*it).second; - } - else - { - return emptystr; - } - } - - const std::string& getBody() const - { - return mBody; - } - - std::string& getWSCacheFrame() - { - return mWSCacheFrame; - } - - std::string& getWSParseString() - { - return mWSParsePayload; - } - - WebSocketFormat::WebSocketFrameType getWSFrameType() const - { - return mWSFrameType; - } - - void cacheWSFrameType(WebSocketFormat::WebSocketFrameType frameType) - { - mWSFrameType = frameType; - } - - private: - void clearParse() - { - mMethod = -1; - mISCompleted = false; - mLastWasValue = true; - mUrl.clear(); - mQuery.clear(); - mBody.clear(); - mStatus.clear(); - mCurrentField.clear(); - mCurrentValue.clear(); - mHeadValues.clear(); - mPath.clear(); - } - - size_t tryParse(const char* buffer, size_t len) - { - const size_t nparsed = http_parser_execute(&mParser, &mSettings, buffer, len); - if (mISCompleted) - { - mIsWebSocket = mParser.upgrade; - mIsKeepAlive = hasEntry("Connection", "Keep-Alive"); - mMethod = mParser.method; - http_parser_init(&mParser, mParserType); - } - - return nparsed; - } - - bool isCompleted() const - { - return mISCompleted; - } - - private: - static int sChunkHeader(http_parser* hp) - { - (void)hp; return 0; } - static int sChunkComplete(http_parser* hp) + struct http_parser_url u; + + const int result = http_parser_parse_url(httpParser->mUrl.data(), + httpParser->mUrl.size(), + 0, + &u); + if (result != 0) { - (void)hp; - return 0; + return -1; } - static int sMessageBegin(http_parser* hp) + if (!(u.field_set & (1 << UF_PATH))) { - HTTPParser* httpParser = (HTTPParser*)hp->data; - httpParser->clearParse(); - - return 0; - } - - static int sMessageEnd(http_parser* hp) - { - HTTPParser* httpParser = (HTTPParser*)hp->data; - httpParser->mISCompleted = true; - return 0; - } - - static int sHeadComplete(http_parser* hp) - { - HTTPParser* httpParser = (HTTPParser*)hp->data; - - if (httpParser->mUrl.empty()) - { - return 0; - } - - struct http_parser_url u; - - const int result = http_parser_parse_url(httpParser->mUrl.data(), - httpParser->mUrl.size(), - 0, - &u); - if (result != 0) - { - return -1; - } - - if (!(u.field_set & (1 << UF_PATH))) - { - fprintf(stderr, - "\n\n*** failed to parse PATH in URL %s ***\n\n", + fprintf(stderr, + "\n\n*** failed to parse PATH in URL %s ***\n\n", httpParser->mUrl.c_str()); - return -1; - } + return -1; + } - httpParser->mPath = std::string( - httpParser->mUrl.data() + u.field_data[UF_PATH].off, + httpParser->mPath = std::string( + httpParser->mUrl.data() + u.field_data[UF_PATH].off, u.field_data[UF_PATH].len); - if (u.field_set & (1 << UF_QUERY)) - { - httpParser->mQuery = std::string( - httpParser->mUrl.data() + u.field_data[UF_QUERY].off, + if (u.field_set & (1 << UF_QUERY)) + { + httpParser->mQuery = std::string( + httpParser->mUrl.data() + u.field_data[UF_QUERY].off, u.field_data[UF_QUERY].len); - } - - return 0; } - static int sUrlHandle(http_parser* hp, const char* url, size_t length) + return 0; + } + + static int sUrlHandle(http_parser* hp, const char* url, size_t length) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + httpParser->mUrl.append(url, length); + + return 0; + } + + static int sHeadValue(http_parser* hp, const char* at, size_t length) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + auto& value = httpParser->mHeadValues[httpParser->mCurrentField]; + value.append(at, length); + httpParser->mLastWasValue = true; + return 0; + } + + static int sHeadField(http_parser* hp, const char* at, size_t length) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + if (httpParser->mLastWasValue) { - HTTPParser* httpParser = (HTTPParser*)hp->data; - httpParser->mUrl.append(url, length); - - return 0; + httpParser->mCurrentField.clear(); } + httpParser->mCurrentField.append(at, length); + httpParser->mLastWasValue = false; - static int sHeadValue(http_parser* hp, const char* at, size_t length) - { - HTTPParser* httpParser = (HTTPParser*)hp->data; - auto& value = httpParser->mHeadValues[httpParser->mCurrentField]; - value.append(at, length); - httpParser->mLastWasValue = true; - return 0; - } + return 0; + } - static int sHeadField(http_parser* hp, const char* at, size_t length) - { - HTTPParser* httpParser = (HTTPParser*)hp->data; - if (httpParser->mLastWasValue) - { - httpParser->mCurrentField.clear(); - } - httpParser->mCurrentField.append(at, length); - httpParser->mLastWasValue = false; + static int sStatusHandle(http_parser* hp, const char* at, size_t length) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + httpParser->mStatus.append(at, length); + httpParser->mStatusCode = hp->status_code; + return 0; + } - return 0; - } + static int sBodyHandle(http_parser* hp, const char* at, size_t length) + { + HTTPParser* httpParser = (HTTPParser*) hp->data; + httpParser->mBody.append(at, length); + return 0; + } - static int sStatusHandle(http_parser* hp, const char* at, size_t length) - { - HTTPParser* httpParser = (HTTPParser*)hp->data; - httpParser->mStatus.append(at, length); - httpParser->mStatusCode = hp->status_code; - return 0; - } +private: + const http_parser_type mParserType; + http_parser mParser; + http_parser_settings mSettings; - static int sBodyHandle(http_parser* hp, const char* at, size_t length) - { - HTTPParser* httpParser = (HTTPParser*)hp->data; - httpParser->mBody.append(at, length); - return 0; - } + int mMethod = -1; + bool mIsUpgrade = false; + bool mIsWebSocket = false; + bool mIsKeepAlive; + bool mISCompleted; - private: - const http_parser_type mParserType; - http_parser mParser; - http_parser_settings mSettings; + bool mLastWasValue; + std::string mCurrentField; + std::string mCurrentValue; - int mMethod = -1; - bool mIsWebSocket; - bool mIsKeepAlive; - bool mISCompleted; + std::string mPath; + std::string mQuery; + std::string mStatus; + std::map mHeadValues; + int mStatusCode; - bool mLastWasValue; - std::string mCurrentField; - std::string mCurrentValue; + std::string mUrl; + std::string mBody; - std::string mPath; - std::string mQuery; - std::string mStatus; - std::map mHeadValues; - int mStatusCode; + std::string mWSCacheFrame; + std::string mWSParsePayload; + WebSocketFormat::WebSocketFrameType mWSFrameType; - std::string mUrl; - std::string mBody; +private: + friend class HttpService; +}; - std::string mWSCacheFrame; - std::string mWSParsePayload; - WebSocketFormat::WebSocketFrameType mWSFrameType; - - private: - friend class HttpService; - }; - -} } } \ No newline at end of file +}}}// namespace brynet::net::http diff --git a/libs/brynet/net/http/HttpService.hpp b/libs/brynet/net/http/HttpService.hpp index 965f003..51b3c68 100644 --- a/libs/brynet/net/http/HttpService.hpp +++ b/libs/brynet/net/http/HttpService.hpp @@ -1,342 +1,355 @@ 锘#pragma once -#include - #include -#include #include #include #include +#include namespace brynet { namespace net { namespace http { - class HttpService; - class HttpSessionHandlers; +class HttpService; +class HttpSessionHandlers; - class HttpSession : public brynet::base::NonCopyable +class HttpSession : public brynet::base::NonCopyable +{ +public: + using Ptr = std::shared_ptr; + + using EnterCallback = std::function; + using HttpParserCallback = std::function; + using WsCallback = std::function; + + using ClosedCallback = std::function; + using WsConnectedCallback = std::function; + +public: + template + void send(PacketType&& packet, + TcpConnection::PacketSendedCallback&& callback = nullptr) { - public: - using Ptr = std::shared_ptr; - - using EnterCallback = std::function ; - using HttpParserCallback = std::function ; - using WsCallback = std::function < void( const HttpSession::Ptr&, - WebSocketFormat::WebSocketFrameType opcode, - const std::string& payload)>; - - using ClosedCallback = std::function ; - using WsConnectedCallback = std::function ; - - public: - template - void send(PacketType&& packet, - TcpConnection::PacketSendedCallback&& callback = nullptr) - { - mSession->send(std::forward(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(std::move(session)); - } - - const TcpConnection::Ptr& getSession() const - { - return mSession; - } - - const HttpParserCallback& getHttpCallback() const - { - return mHttpRequestCallback; - } - - const ClosedCallback& getCloseCallback() const - { - return mCloseCallback; - } - - const WsCallback& getWSCallback() const - { - return mWSCallback; - } - - const WsConnectedCallback& getWSConnectedCallback() const - { - return mWSConnectedCallback; - } - - private: - void setHttpCallback(HttpParserCallback&& callback) - { - mHttpRequestCallback = std::move(callback); - } - - void setClosedCallback(ClosedCallback&& callback) - { - mCloseCallback = std::move(callback); - } - - void setWSCallback(WsCallback&& callback) - { - mWSCallback = std::move(callback); - } - - void setWSConnected(WsConnectedCallback&& callback) - { - mWSConnectedCallback = std::move(callback); - } - - private: - TcpConnection::Ptr mSession; - HttpParserCallback mHttpRequestCallback; - WsCallback mWSCallback; - ClosedCallback mCloseCallback; - WsConnectedCallback mWSConnectedCallback; - - friend class HttpService; - }; - - class HttpSessionHandlers + mSession->send(std::forward(packet), + std::move(callback)); + } + void send(const char* packet, + size_t len, + TcpConnection::PacketSendedCallback&& callback = nullptr) { - public: - void setHttpCallback(HttpSession::HttpParserCallback&& callback) - { - mHttpRequestCallback = std::move(callback); - } + mSession->send(packet, len, std::move(callback)); + } - void setClosedCallback(HttpSession::ClosedCallback&& callback) - { - mCloseCallback = std::move(callback); - } - - void setWSCallback(HttpSession::WsCallback&& callback) - { - mWSCallback = std::move(callback); - } - - void setWSConnected(HttpSession::WsConnectedCallback&& callback) - { - mWSConnectedCallback = std::move(callback); - } - - private: - HttpSession::HttpParserCallback mHttpRequestCallback; - HttpSession::WsCallback mWSCallback; - HttpSession::ClosedCallback mCloseCallback; - HttpSession::WsConnectedCallback mWSConnectedCallback; - - friend class HttpService; - }; - - class HttpService + void postShutdown() const { - public: - static void setup(const TcpConnection::Ptr& session, - const HttpSession::EnterCallback& enterCallback) + mSession->postShutdown(); + } + + void postClose() const + { + mSession->postDisConnect(); + } + +protected: + explicit HttpSession(TcpConnection::Ptr session) + { + mSession = std::move(session); + } + + virtual ~HttpSession() = default; + + static Ptr Create(TcpConnection::Ptr session) + { + class make_shared_enabler : public HttpSession { - auto httpSession = HttpSession::Create(session); - if (enterCallback != nullptr) - { - HttpSessionHandlers handlers; - enterCallback(httpSession, handlers); - httpSession->setHttpCallback(std::move(handlers.mHttpRequestCallback)); - httpSession->setClosedCallback(std::move(handlers.mCloseCallback)); - httpSession->setWSCallback(std::move(handlers.mWSCallback)); - httpSession->setWSConnected(std::move(handlers.mWSConnectedCallback)); - } - HttpService::handle(httpSession); + public: + explicit make_shared_enabler(TcpConnection::Ptr session) + : HttpSession(std::move(session)) + {} + }; + return std::make_shared(std::move(session)); + } + + const TcpConnection::Ptr& getSession() const + { + return mSession; + } + + const HttpParserCallback& getHttpCallback() const + { + return mHttpRequestCallback; + } + + const ClosedCallback& getCloseCallback() const + { + return mCloseCallback; + } + + const WsCallback& getWSCallback() const + { + return mWSCallback; + } + + const WsConnectedCallback& getWSConnectedCallback() const + { + return mWSConnectedCallback; + } + +private: + void setHttpCallback(HttpParserCallback&& callback) + { + mHttpRequestCallback = std::move(callback); + } + + void setClosedCallback(ClosedCallback&& callback) + { + mCloseCallback = std::move(callback); + } + + void setWSCallback(WsCallback&& callback) + { + mWSCallback = std::move(callback); + } + + void setWSConnected(WsConnectedCallback&& callback) + { + mWSConnectedCallback = std::move(callback); + } + +private: + TcpConnection::Ptr mSession; + HttpParserCallback mHttpRequestCallback; + WsCallback mWSCallback; + ClosedCallback mCloseCallback; + WsConnectedCallback mWSConnectedCallback; + + friend class HttpService; +}; + +class HttpSessionHandlers +{ +public: + void setHttpCallback(HttpSession::HttpParserCallback&& callback) + { + mHttpRequestCallback = std::move(callback); + } + + void setClosedCallback(HttpSession::ClosedCallback&& callback) + { + mCloseCallback = std::move(callback); + } + + void setWSCallback(HttpSession::WsCallback&& callback) + { + mWSCallback = std::move(callback); + } + + void setWSConnected(HttpSession::WsConnectedCallback&& callback) + { + mWSConnectedCallback = std::move(callback); + } + +private: + HttpSession::HttpParserCallback mHttpRequestCallback; + HttpSession::WsCallback mWSCallback; + HttpSession::ClosedCallback mCloseCallback; + HttpSession::WsConnectedCallback mWSConnectedCallback; + + friend class HttpService; +}; + +class HttpService +{ +public: + static void setup(const TcpConnection::Ptr& session, + const HttpSession::EnterCallback& enterCallback) + { + auto httpSession = HttpSession::Create(session); + if (enterCallback != nullptr) + { + HttpSessionHandlers handlers; + enterCallback(httpSession, handlers); + httpSession->setHttpCallback(std::move(handlers.mHttpRequestCallback)); + httpSession->setClosedCallback(std::move(handlers.mCloseCallback)); + httpSession->setWSCallback(std::move(handlers.mWSCallback)); + httpSession->setWSConnected(std::move(handlers.mWSConnectedCallback)); } + HttpService::handle(httpSession); + } - private: - static void handle(const HttpSession::Ptr& httpSession) - { - /*TODO::keep alive and timeout close */ - auto& session = httpSession->getSession(); +private: + static void handle(const HttpSession::Ptr& httpSession) + { + /*TODO::keep alive and timeout close */ + auto& session = httpSession->getSession(); + auto httpParser = std::make_shared(HTTP_BOTH); - session->setDisConnectCallback([httpSession](const TcpConnection::Ptr&) { - const auto& tmp = httpSession->getCloseCallback(); - if (tmp != nullptr) - { - tmp(httpSession); - } - }); - - auto httpParser = std::make_shared(HTTP_BOTH); - session->setDataCallback([httpSession, httpParser]( - brynet::base::BasePacketReader& reader) { - size_t retLen = 0; - - if (httpParser->isWebSocket()) - { - retLen = HttpService::ProcessWebSocket( reader.begin(), - reader.size(), - httpParser, - httpSession); - } - else - { - retLen = HttpService::ProcessHttp( reader.begin(), - reader.size(), - httpParser, - httpSession); - } - - reader.addPos(retLen); - reader.savePos(); - }); - } - - static size_t ProcessWebSocket(const char* buffer, - size_t len, - const HTTPParser::Ptr& httpParser, - const HttpSession::Ptr& httpSession) - { - size_t leftLen = len; - - const auto& wsCallback = httpSession->getWSCallback(); - auto& cacheFrame = httpParser->getWSCacheFrame(); - auto& parseString = httpParser->getWSParseString(); - - while (leftLen > 0) - { - parseString.clear(); - - auto opcode = WebSocketFormat::WebSocketFrameType::ERROR_FRAME; - size_t frameSize = 0; - bool isFin = false; - - if (!WebSocketFormat::wsFrameExtractBuffer(buffer, - leftLen, - parseString, - opcode, - frameSize, - isFin)) - { - // 濡傛灉娌℃湁瑙f瀽鍑哄畬鏁寸殑ws frame鍒欓鍑哄嚱鏁 - break; - } - - // 濡傛灉褰撳墠fram鐨刦in涓篺alse鎴栬卭pcode涓哄欢缁寘 - // 鍒欏皢褰撳墠frame鐨刾ayload娣诲姞鍒癱ache - if (!isFin || - opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME) - { - cacheFrame += parseString; - parseString.clear(); - } - // 濡傛灉褰撳墠fram鐨刦in涓篺alse锛屽苟涓攐pcode涓嶄负寤剁画鍖 - // 鍒欒〃绀烘敹鍒板垎娈祊ayload鐨勭涓涓(frame)锛岄渶瑕佺紦瀛樺綋鍓峟rame鐨刼pcode - if (!isFin && - opcode != WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME) - { - httpParser->cacheWSFrameType(opcode); - } - - leftLen -= frameSize; - buffer += frameSize; - - if (!isFin) - { - continue; - } - - // 濡傛灉fin涓簍rue锛屽苟涓攐pcode涓哄欢缁寘 - // 鍒欒〃绀哄垎娈祊ayload鍏ㄩ儴鎺ュ彈瀹屾瘯 - // 鍥犳闇瑕佽幏鍙栦箣鍓嶇涓娆℃敹鍒板垎娈礷rame鐨刼pcode浣滀负鏁翠釜payload鐨勭被鍨 - if (opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME) - { - if (!cacheFrame.empty()) - { - parseString = std::move(cacheFrame); - cacheFrame.clear(); - } - opcode = httpParser->getWSFrameType(); - } - - if (wsCallback != nullptr) - { - wsCallback(httpSession, opcode, parseString); - } - } - - return (len - leftLen); - } - - static size_t ProcessHttp(const char* buffer, - size_t len, - const HTTPParser::Ptr& httpParser, - const HttpSession::Ptr& httpSession) - { - size_t retlen = len; + session->setDisConnectCallback([httpSession, httpParser](const TcpConnection::Ptr&) { if (!httpParser->isCompleted()) { - retlen = httpParser->tryParse(buffer, len); - if (!httpParser->isCompleted()) - { - return retlen; - } + // try pass EOF to http parser + HttpService::ProcessHttp(nullptr, 0, httpParser, httpSession); } + const auto& tmp = httpSession->getCloseCallback(); + if (tmp != nullptr) + { + tmp(httpSession); + } + }); + + session->setDataCallback([httpSession, httpParser]( + brynet::base::BasePacketReader& reader) { + size_t retLen = 0; + if (httpParser->isWebSocket()) { - if (httpParser->hasKey("Sec-WebSocket-Key")) - { - auto response = WebSocketFormat::wsHandshake( - httpParser->getValue("Sec-WebSocket-Key")); - httpSession->send(response.c_str(), - response.size()); - } - - const auto& wsConnectedCallback = httpSession->getWSConnectedCallback(); - if (wsConnectedCallback != nullptr) - { - wsConnectedCallback(httpSession, *httpParser); - } + retLen = HttpService::ProcessWebSocket(reader.begin(), + reader.size(), + httpParser, + httpSession); + } + else if (httpParser->isUpgrade()) + { + // TODO::not support other upgrade protocol } else { - const auto& httpCallback = httpSession->getHttpCallback(); - if (httpCallback != nullptr) + retLen = HttpService::ProcessHttp(reader.begin(), + reader.size(), + httpParser, + httpSession); + // if http_parser_execute not consume all data that indicate cause error in parser. + // so we need close connection. + if (retLen != reader.size()) { - httpCallback(*httpParser, httpSession); + httpSession->postClose(); } } - return retlen; - } - }; + reader.addPos(retLen); + reader.savePos(); + }); + } -} } } \ No newline at end of file + 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)) + { + // 濡傛灉娌℃湁瑙f瀽鍑哄畬鏁寸殑ws frame鍒欓鍑哄嚱鏁 + break; + } + + // 濡傛灉褰撳墠fram鐨刦in涓篺alse鎴栬卭pcode涓哄欢缁寘 + // 鍒欏皢褰撳墠frame鐨刾ayload娣诲姞鍒癱ache + if (!isFin || + opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME) + { + cacheFrame += parseString; + parseString.clear(); + } + // 濡傛灉褰撳墠fram鐨刦in涓篺alse锛屽苟涓攐pcode涓嶄负寤剁画鍖 + // 鍒欒〃绀烘敹鍒板垎娈祊ayload鐨勭涓涓(frame)锛岄渶瑕佺紦瀛樺綋鍓峟rame鐨刼pcode + if (!isFin && + opcode != WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME) + { + httpParser->cacheWSFrameType(opcode); + } + + leftLen -= frameSize; + buffer += frameSize; + + if (!isFin) + { + continue; + } + + // 濡傛灉fin涓簍rue锛屽苟涓攐pcode涓哄欢缁寘 + // 鍒欒〃绀哄垎娈祊ayload鍏ㄩ儴鎺ュ彈瀹屾瘯 + // 鍥犳闇瑕佽幏鍙栦箣鍓嶇涓娆℃敹鍒板垎娈礷rame鐨刼pcode浣滀负鏁翠釜payload鐨勭被鍨 + if (opcode == WebSocketFormat::WebSocketFrameType::CONTINUATION_FRAME) + { + if (!cacheFrame.empty()) + { + parseString = std::move(cacheFrame); + cacheFrame.clear(); + } + opcode = httpParser->getWSFrameType(); + } + + if (wsCallback != nullptr) + { + wsCallback(httpSession, opcode, parseString); + } + } + + return (len - leftLen); + } + + static size_t ProcessHttp(const char* buffer, + size_t len, + const HTTPParser::Ptr& httpParser, + const HttpSession::Ptr& httpSession) + { + size_t retlen = len; + if (!httpParser->isCompleted()) + { + retlen = httpParser->tryParse(buffer, len); + if (!httpParser->isCompleted()) + { + return retlen; + } + } + + if (httpParser->isWebSocket()) + { + if (httpParser->hasKey("Sec-WebSocket-Key")) + { + auto response = WebSocketFormat::wsHandshake( + httpParser->getValue("Sec-WebSocket-Key")); + httpSession->send(response.c_str(), + response.size()); + } + + const auto& wsConnectedCallback = httpSession->getWSConnectedCallback(); + if (wsConnectedCallback != nullptr) + { + wsConnectedCallback(httpSession, *httpParser); + } + } + else + { + const auto& httpCallback = httpSession->getHttpCallback(); + if (httpCallback != nullptr) + { + httpCallback(*httpParser, httpSession); + } + } + + return retlen; + } +}; + +}}}// namespace brynet::net::http diff --git a/libs/brynet/net/http/WebSocketFormat.hpp b/libs/brynet/net/http/WebSocketFormat.hpp index 17a3015..bd4f464 100644 --- a/libs/brynet/net/http/WebSocketFormat.hpp +++ b/libs/brynet/net/http/WebSocketFormat.hpp @@ -1,239 +1,239 @@ #pragma once -#include #include -#include -#include #include #include +#include +#include +#include namespace brynet { namespace net { namespace http { - class WebSocketFormat +class WebSocketFormat +{ +public: + enum class WebSocketFrameType { - public: - enum class WebSocketFrameType { - ERROR_FRAME = 0xff, - CONTINUATION_FRAME = 0x00, - TEXT_FRAME = 0x01, - BINARY_FRAME = 0x02, - CLOSE_FRAME = 0x08, - PING_FRAME = 0x09, - PONG_FRAME = 0x0A - }; + ERROR_FRAME = 0xff, + CONTINUATION_FRAME = 0x00, + TEXT_FRAME = 0x01, + BINARY_FRAME = 0x02, + CLOSE_FRAME = 0x08, + PING_FRAME = 0x09, + PONG_FRAME = 0x0A + }; - static std::string wsHandshake(std::string secKey) - { - secKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + static std::string wsHandshake(std::string secKey) + { + secKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); - CSHA1 s1; - s1.Update((unsigned char*)secKey.c_str(), static_cast(secKey.size())); - s1.Final(); - unsigned char puDest[20]; - s1.GetHash(puDest); + CSHA1 s1; + s1.Update((unsigned char*) secKey.c_str(), static_cast(secKey.size())); + s1.Final(); + unsigned char puDest[20]; + s1.GetHash(puDest); - std::string base64Str = brynet::base::crypto::base64_encode((const unsigned char*)puDest, 20); + std::string base64Str = brynet::base::crypto::base64_encode((const unsigned char*) puDest, 20); - std::string response = "HTTP/1.1 101 Switching Protocols\r\n" + std::string response = + "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: "; - response += base64Str; - response += "\r\n\r\n"; + response += base64Str; + response += "\r\n\r\n"; - return response; + return response; + } + + static bool wsFrameBuild(const char* payload, + size_t payloadLen, + std::string& frame, + WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME, + bool isFin = true, + bool masking = false) + { + const auto unixTime = std::chrono::system_clock::now().time_since_epoch().count(); + static std::mt19937 random(static_cast(unixTime)); + + static_assert(std::is_same::value, ""); + + const uint8_t head = static_cast(frame_type) | (isFin ? 0x80 : 0x00); + + frame.clear(); + frame.push_back(static_cast(head)); + if (payloadLen <= 125) + { + // mask << 7 | payloadLen, mask = 0 + frame.push_back(static_cast(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((payloadLen & 0xFF000000) >> 24)); + frame.push_back(static_cast((payloadLen & 0x00FF0000) >> 16)); + frame.push_back(static_cast((payloadLen & 0x0000FF00) >> 8)); + frame.push_back(static_cast(payloadLen & 0x000000FF)); } - static bool wsFrameBuild(const char* payload, - size_t payloadLen, - std::string& frame, - WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME, - bool isFin = true, - bool masking = false) + if (masking) { - const auto unixTime = std::chrono::system_clock::now(). - time_since_epoch(). - count(); - static std::mt19937 random(static_cast(unixTime)); - - static_assert(std::is_same::value, ""); - - const uint8_t head = static_cast(frame_type) | (isFin ? 0x80 : 0x00); - - frame.clear(); - frame.push_back(static_cast(head)); - if (payloadLen <= 125) - { - // mask << 7 | payloadLen, mask = 0 - frame.push_back(static_cast(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((payloadLen & 0xFF000000) >> 24)); - frame.push_back(static_cast((payloadLen & 0x00FF0000) >> 16)); - frame.push_back(static_cast((payloadLen & 0x0000FF00) >> 8)); - frame.push_back(static_cast(payloadLen & 0x000000FF)); - } - - if (masking) - { - frame[1] = ((uint8_t)frame[1]) | 0x80; - uint8_t mask[4]; - for (auto& m : mask) - { - m = static_cast(random()); - frame.push_back(m); - } - - frame.reserve(frame.size() + payloadLen); - - for (size_t i = 0; i < payloadLen; i++) - { - frame.push_back(static_cast(payload[i]) ^ mask[i % 4]); - } - } - else - { - frame.append(payload, payloadLen); - } - - return true; - } - - static bool wsFrameBuild(const std::string& payload, - std::string& frame, - WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME, - bool isFin = true, - bool masking = false) - { - return wsFrameBuild(payload.c_str(), - payload.size(), - frame, - frame_type, - isFin, - masking); - } - - static bool wsFrameExtractBuffer(const char* inbuffer, - const size_t bufferSize, - std::string& payload, - WebSocketFrameType& outopcode, - size_t& frameSize, - bool& outfin) - { - const auto buffer = (const unsigned char*)inbuffer; - - if (bufferSize < 2) - { - return false; - } - - outfin = (buffer[0] & 0x80) != 0; - outopcode = (WebSocketFrameType)(buffer[0] & 0x0F); - const bool isMasking = (buffer[1] & 0x80) != 0; - uint32_t payloadlen = buffer[1] & 0x7F; - - uint32_t pos = 2; - if (payloadlen == 126) - { - if (bufferSize < 4) - { - return false; - } - - payloadlen = (buffer[2] << 8) + buffer[3]; - pos = 4; - } - else if (payloadlen == 127) - { - if (bufferSize < 10) - { - return false; - } - - if (buffer[2] != 0 || - buffer[3] != 0 || - buffer[4] != 0 || - buffer[5] != 0) - { - return false; - } - - if ((buffer[6] & 0x80) != 0) - { - return false; - } - - payloadlen = (buffer[6] << 24) + - (buffer[7] << 16) + - (buffer[8] << 8) + - buffer[9]; - pos = 10; - } - + frame[1] = ((uint8_t) frame[1]) | 0x80; uint8_t mask[4]; - if (isMasking) + for (auto& m : mask) { - if (bufferSize < (pos + 4)) - { - return false; - } - - mask[0] = buffer[pos++]; - mask[1] = buffer[pos++]; - mask[2] = buffer[pos++]; - mask[3] = buffer[pos++]; + m = static_cast(random()); + frame.push_back(m); } - if (bufferSize < (pos + payloadlen)) + frame.reserve(frame.size() + payloadLen); + + for (size_t i = 0; i < payloadLen; i++) + { + frame.push_back(static_cast(payload[i]) ^ mask[i % 4]); + } + } + else + { + frame.append(payload, payloadLen); + } + + return true; + } + + static bool wsFrameBuild(const std::string& payload, + std::string& frame, + WebSocketFrameType frame_type = WebSocketFrameType::TEXT_FRAME, + bool isFin = true, + bool masking = false) + { + return wsFrameBuild(payload.c_str(), + payload.size(), + frame, + frame_type, + isFin, + masking); + } + + static bool wsFrameExtractBuffer(const char* inbuffer, + const size_t bufferSize, + std::string& payload, + WebSocketFrameType& outopcode, + size_t& frameSize, + bool& outfin) + { + const auto buffer = (const unsigned char*) inbuffer; + + if (bufferSize < 2) + { + return false; + } + + outfin = (buffer[0] & 0x80) != 0; + outopcode = (WebSocketFrameType)(buffer[0] & 0x0F); + const bool isMasking = (buffer[1] & 0x80) != 0; + uint32_t payloadlen = buffer[1] & 0x7F; + + uint32_t pos = 2; + if (payloadlen == 126) + { + if (bufferSize < 4) { return false; } - if (isMasking) - { - payload.reserve(payloadlen); - for (size_t j = 0; j < payloadlen; j++) - payload.push_back(buffer[pos+j] ^ mask[j % 4]); - } - else - { - payload.append((const char*)(buffer + pos), payloadlen); - } - - frameSize = payloadlen + pos; - - return true; + payloadlen = (buffer[2] << 8) + buffer[3]; + pos = 4; } - - static bool wsFrameExtractString(const std::string& buffer, - std::string& payload, - WebSocketFrameType& opcode, - size_t& frameSize, bool& isFin) + else if (payloadlen == 127) { - return wsFrameExtractBuffer(buffer.c_str(), - buffer.size(), - payload, - opcode, - frameSize, - isFin); - } - }; + if (bufferSize < 10) + { + return false; + } -} } } \ No newline at end of file + if (buffer[2] != 0 || + buffer[3] != 0 || + buffer[4] != 0 || + buffer[5] != 0) + { + return false; + } + + if ((buffer[6] & 0x80) != 0) + { + return false; + } + + payloadlen = (buffer[6] << 24) + + (buffer[7] << 16) + + (buffer[8] << 8) + + buffer[9]; + pos = 10; + } + + uint8_t mask[4]; + if (isMasking) + { + if (bufferSize < (pos + 4)) + { + return false; + } + + mask[0] = buffer[pos++]; + mask[1] = buffer[pos++]; + mask[2] = buffer[pos++]; + mask[3] = buffer[pos++]; + } + + if (bufferSize < (pos + payloadlen)) + { + return false; + } + + if (isMasking) + { + payload.reserve(payloadlen); + for (size_t j = 0; j < payloadlen; j++) + payload.push_back(buffer[pos + j] ^ mask[j % 4]); + } + else + { + payload.append((const char*) (buffer + pos), payloadlen); + } + + frameSize = payloadlen + pos; + + return true; + } + + static bool wsFrameExtractString(const std::string& buffer, + std::string& payload, + WebSocketFrameType& opcode, + size_t& frameSize, bool& isFin) + { + return wsFrameExtractBuffer(buffer.c_str(), + buffer.size(), + payload, + opcode, + frameSize, + isFin); + } +}; + +}}}// namespace brynet::net::http diff --git a/libs/brynet/net/http/http_parser.h b/libs/brynet/net/http/http_parser.h index 1c03d36..62f7866 100644 --- a/libs/brynet/net/http/http_parser.h +++ b/libs/brynet/net/http/http_parser.h @@ -22,10 +22,10 @@ #define http_parser_h #include -#include #include -#include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -38,7 +38,7 @@ extern "C" { #include #if defined(_WIN32) && !defined(__MINGW32__) && \ - (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) + (!defined(_MSC_VER) || _MSC_VER < 1600) && !defined(__WINE__) #include typedef __int8 int8_t; typedef unsigned __int8 uint8_t; @@ -56,7 +56,7 @@ typedef unsigned __int64 uint64_t; * faster */ #ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 +#define HTTP_PARSER_STRICT 1 #endif /* Maximium header size allowed. If the macro is not defined @@ -67,7 +67,7 @@ typedef unsigned __int64 uint64_t; * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) */ #ifndef HTTP_MAX_HEADER_SIZE -# define HTTP_MAX_HEADER_SIZE (80*1024) +#define HTTP_MAX_HEADER_SIZE (80 * 1024) #endif typedef struct http_parser http_parser; @@ -92,269 +92,279 @@ typedef struct http_parser_settings http_parser_settings; * many times for each string. E.G. you might get 10 callbacks for "on_url" * each providing just a few characters more data. */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); +typedef int (*http_data_cb)(http_parser *, const char *at, size_t length); +typedef int (*http_cb)(http_parser *); /* Status Codes */ -#define HTTP_STATUS_MAP(XX) \ - XX(100, CONTINUE, Continue) \ - XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ - XX(102, PROCESSING, Processing) \ - XX(200, OK, OK) \ - XX(201, CREATED, Created) \ - XX(202, ACCEPTED, Accepted) \ - XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ - XX(204, NO_CONTENT, No Content) \ - XX(205, RESET_CONTENT, Reset Content) \ - XX(206, PARTIAL_CONTENT, Partial Content) \ - XX(207, MULTI_STATUS, Multi-Status) \ - XX(208, ALREADY_REPORTED, Already Reported) \ - XX(226, IM_USED, IM Used) \ - XX(300, MULTIPLE_CHOICES, Multiple Choices) \ - XX(301, MOVED_PERMANENTLY, Moved Permanently) \ - XX(302, FOUND, Found) \ - XX(303, SEE_OTHER, See Other) \ - XX(304, NOT_MODIFIED, Not Modified) \ - XX(305, USE_PROXY, Use Proxy) \ - XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ - XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ - XX(400, BAD_REQUEST, Bad Request) \ - XX(401, UNAUTHORIZED, Unauthorized) \ - XX(402, PAYMENT_REQUIRED, Payment Required) \ - XX(403, FORBIDDEN, Forbidden) \ - XX(404, NOT_FOUND, Not Found) \ - XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ - XX(406, NOT_ACCEPTABLE, Not Acceptable) \ - XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ - XX(408, REQUEST_TIMEOUT, Request Timeout) \ - XX(409, CONFLICT, Conflict) \ - XX(410, GONE, Gone) \ - XX(411, LENGTH_REQUIRED, Length Required) \ - XX(412, PRECONDITION_FAILED, Precondition Failed) \ - XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ - XX(414, URI_TOO_LONG, URI Too Long) \ - XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ - XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ - XX(417, EXPECTATION_FAILED, Expectation Failed) \ - XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ - XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ - XX(423, LOCKED, Locked) \ - XX(424, FAILED_DEPENDENCY, Failed Dependency) \ - XX(426, UPGRADE_REQUIRED, Upgrade Required) \ - XX(428, PRECONDITION_REQUIRED, Precondition Required) \ - XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ - XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ - XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ - XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ - XX(501, NOT_IMPLEMENTED, Not Implemented) \ - XX(502, BAD_GATEWAY, Bad Gateway) \ - XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ - XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ - XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ - XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ - XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ - XX(508, LOOP_DETECTED, Loop Detected) \ - XX(510, NOT_EXTENDED, Not Extended) \ - XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ +#define HTTP_STATUS_MAP(XX) \ + XX(100, CONTINUE, Continue) \ + XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ + XX(102, PROCESSING, Processing) \ + XX(200, OK, OK) \ + XX(201, CREATED, Created) \ + XX(202, ACCEPTED, Accepted) \ + XX(203, NON_AUTHORITATIVE_INFORMATION, Non - Authoritative Information) \ + XX(204, NO_CONTENT, No Content) \ + XX(205, RESET_CONTENT, Reset Content) \ + XX(206, PARTIAL_CONTENT, Partial Content) \ + XX(207, MULTI_STATUS, Multi - Status) \ + XX(208, ALREADY_REPORTED, Already Reported) \ + XX(226, IM_USED, IM Used) \ + XX(300, MULTIPLE_CHOICES, Multiple Choices) \ + XX(301, MOVED_PERMANENTLY, Moved Permanently) \ + XX(302, FOUND, Found) \ + XX(303, SEE_OTHER, See Other) \ + XX(304, NOT_MODIFIED, Not Modified) \ + XX(305, USE_PROXY, Use Proxy) \ + XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ + XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ + XX(400, BAD_REQUEST, Bad Request) \ + XX(401, UNAUTHORIZED, Unauthorized) \ + XX(402, PAYMENT_REQUIRED, Payment Required) \ + XX(403, FORBIDDEN, Forbidden) \ + XX(404, NOT_FOUND, Not Found) \ + XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ + XX(406, NOT_ACCEPTABLE, Not Acceptable) \ + XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ + XX(408, REQUEST_TIMEOUT, Request Timeout) \ + XX(409, CONFLICT, Conflict) \ + XX(410, GONE, Gone) \ + XX(411, LENGTH_REQUIRED, Length Required) \ + XX(412, PRECONDITION_FAILED, Precondition Failed) \ + XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ + XX(414, URI_TOO_LONG, URI Too Long) \ + XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ + XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ + XX(417, EXPECTATION_FAILED, Expectation Failed) \ + XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ + XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ + XX(423, LOCKED, Locked) \ + XX(424, FAILED_DEPENDENCY, Failed Dependency) \ + XX(426, UPGRADE_REQUIRED, Upgrade Required) \ + XX(428, PRECONDITION_REQUIRED, Precondition Required) \ + XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ + XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ + XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ + XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ + XX(501, NOT_IMPLEMENTED, Not Implemented) \ + XX(502, BAD_GATEWAY, Bad Gateway) \ + XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ + XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ + XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ + XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ + XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ + XX(508, LOOP_DETECTED, Loop Detected) \ + XX(510, NOT_EXTENDED, Not Extended) \ + XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) enum http_status - { +{ #define XX(num, name, string) HTTP_STATUS_##name = num, - HTTP_STATUS_MAP(XX) + HTTP_STATUS_MAP(XX) #undef XX - }; +}; /* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* WebDAV */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - XX(16, BIND, BIND) \ - XX(17, REBIND, REBIND) \ - XX(18, UNBIND, UNBIND) \ - XX(19, ACL, ACL) \ - /* subversion */ \ - XX(20, REPORT, REPORT) \ - XX(21, MKACTIVITY, MKACTIVITY) \ - XX(22, CHECKOUT, CHECKOUT) \ - XX(23, MERGE, MERGE) \ - /* upnp */ \ - XX(24, MSEARCH, M-SEARCH) \ - XX(25, NOTIFY, NOTIFY) \ - XX(26, SUBSCRIBE, SUBSCRIBE) \ - XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(28, PATCH, PATCH) \ - XX(29, PURGE, PURGE) \ - /* CalDAV */ \ - XX(30, MKCALENDAR, MKCALENDAR) \ - /* RFC-2068, section 19.6.1.2 */ \ - XX(31, LINK, LINK) \ - XX(32, UNLINK, UNLINK) \ - /* icecast */ \ - XX(33, SOURCE, SOURCE) \ +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + /* pathological */ \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + /* WebDAV */ \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + /* subversion */ \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + /* upnp */ \ + XX(24, MSEARCH, M - SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + /* RFC-5789 */ \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + /* CalDAV */ \ + XX(30, MKCALENDAR, MKCALENDAR) \ + /* RFC-2068, section 19.6.1.2 */ \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + /* icecast */ \ + XX(33, SOURCE, SOURCE) enum http_method - { +{ #define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) + HTTP_METHOD_MAP(XX) #undef XX - }; +}; -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; +enum http_parser_type +{ + HTTP_REQUEST, + HTTP_RESPONSE, + HTTP_BOTH +}; /* Flag values for http_parser.flags field */ enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_CONNECTION_UPGRADE = 1 << 3 - , F_TRAILING = 1 << 4 - , F_UPGRADE = 1 << 5 - , F_SKIPBODY = 1 << 6 - , F_CONTENTLENGTH = 1 << 7 - }; +{ + F_CHUNKED = 1 << 0, + F_CONNECTION_KEEP_ALIVE = 1 << 1, + F_CONNECTION_CLOSE = 1 << 2, + F_CONNECTION_UPGRADE = 1 << 3, + F_TRAILING = 1 << 4, + F_UPGRADE = 1 << 5, + F_SKIPBODY = 1 << 6, + F_CONTENTLENGTH = 1 << 7 +}; /* Map for errno-related constants * * The provided argument should be a macro that takes 2 arguments. */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - XX(CB_status, "the on_status callback failed") \ - XX(CB_chunk_header, "the on_chunk_header callback failed") \ - XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(UNEXPECTED_CONTENT_LENGTH, \ - "unexpected content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") +#define HTTP_ERRNO_MAP(XX) \ + /* No error */ \ + XX(OK, "success") \ + \ + /* Callback-related errors */ \ + XX(CB_message_begin, "the on_message_begin callback failed") \ + XX(CB_url, "the on_url callback failed") \ + XX(CB_header_field, "the on_header_field callback failed") \ + XX(CB_header_value, "the on_header_value callback failed") \ + XX(CB_headers_complete, "the on_headers_complete callback failed") \ + XX(CB_body, "the on_body callback failed") \ + XX(CB_message_complete, "the on_message_complete callback failed") \ + XX(CB_status, "the on_status callback failed") \ + XX(CB_chunk_header, "the on_chunk_header callback failed") \ + XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ + \ + /* Parsing-related errors */ \ + XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ + XX(HEADER_OVERFLOW, \ + "too many header bytes seen; overflow detected") \ + XX(CLOSED_CONNECTION, \ + "data received after completed connection: close message") \ + XX(INVALID_VERSION, "invalid HTTP version") \ + XX(INVALID_STATUS, "invalid HTTP status code") \ + XX(INVALID_METHOD, "invalid HTTP method") \ + XX(INVALID_URL, "invalid URL") \ + XX(INVALID_HOST, "invalid host") \ + XX(INVALID_PORT, "invalid port") \ + XX(INVALID_PATH, "invalid path") \ + XX(INVALID_QUERY_STRING, "invalid query string") \ + XX(INVALID_FRAGMENT, "invalid fragment") \ + XX(LF_EXPECTED, "LF character expected") \ + XX(INVALID_HEADER_TOKEN, "invalid character in header") \ + XX(INVALID_CONTENT_LENGTH, \ + "invalid character in content-length header") \ + XX(UNEXPECTED_CONTENT_LENGTH, \ + "unexpected content-length header") \ + XX(INVALID_CHUNK_SIZE, \ + "invalid character in chunk size header") \ + XX(INVALID_CONSTANT, "invalid constant string") \ + XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state") \ + XX(STRICT, "strict mode assertion failed") \ + XX(PAUSED, "parser is paused") \ + XX(UNKNOWN, "an unknown error occurred") /* Define HPE_* values for each errno value above */ #define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) +enum http_errno +{ + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) }; #undef HTTP_ERRNO_GEN /* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) +#define HTTP_PARSER_ERRNO(p) ((enum http_errno)(p)->http_errno) -struct http_parser { - /** PRIVATE **/ - unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 7; /* enum state from http_parser.c */ - unsigned int header_state : 7; /* enum header_state from http_parser.c */ - unsigned int index : 7; /* index into current matcher */ - unsigned int lenient_http_headers : 1; +struct http_parser +{ + /** PRIVATE **/ + unsigned int type : 2; /* enum http_parser_type */ + unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ + unsigned int state : 7; /* enum state from http_parser.c */ + unsigned int header_state : 7; /* enum header_state from http_parser.c */ + unsigned int index : 7; /* index into current matcher */ + unsigned int lenient_http_headers : 1; - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ + uint32_t nread; /* # bytes read in various scenarios */ + uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned int status_code : 16; /* responses only */ - unsigned int method : 8; /* requests only */ - unsigned int http_errno : 7; + /** READ-ONLY **/ + unsigned short http_major; + unsigned short http_minor; + unsigned int status_code : 16; /* responses only */ + unsigned int method : 8; /* requests only */ + unsigned int http_errno : 7; - /* 1 = Upgrade header was present and the parser has exited because of that. + /* 1 = Upgrade header was present and the parser has exited because of that. * 0 = No upgrade header present. * Should be checked when http_parser_execute() returns in addition to * error checking. */ - unsigned int upgrade : 1; + unsigned int upgrade : 1; - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ + /** PUBLIC **/ + void *data; /* A pointer to get hook to the "connection" or "socket" object */ }; -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_status; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; - /* When on_chunk_header is called, the current chunk length is stored +struct http_parser_settings +{ + http_cb on_message_begin; + http_data_cb on_url; + http_data_cb on_status; + http_data_cb on_header_field; + http_data_cb on_header_value; + http_cb on_headers_complete; + http_data_cb on_body; + http_cb on_message_complete; + /* When on_chunk_header is called, the current chunk length is stored * in parser->content_length. */ - http_cb on_chunk_header; - http_cb on_chunk_complete; + http_cb on_chunk_header; + http_cb on_chunk_complete; }; enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; +{ + UF_SCHEMA = 0, + UF_HOST = 1, + UF_PORT = 2, + UF_PATH = 3, + UF_QUERY = 4, + UF_FRAGMENT = 5, + UF_USERINFO = 6, + UF_MAX = 7 +}; /* Result structure for http_parser_parse_url(). @@ -364,14 +374,16 @@ enum http_parser_url_fields * because we probably have padding left over), we convert any port to * a uint16_t. */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ +struct http_parser_url +{ + uint16_t field_set; /* Bitmask of (1 << UF_*) values */ + uint16_t port; /* Converted UF_PORT string */ - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; + struct + { + uint16_t off; /* Offset into buffer in which field starts */ + uint16_t len; /* Length of run in buffer */ + } field_data[UF_MAX]; }; @@ -398,9 +410,9 @@ static void http_parser_settings_init(http_parser_settings *settings); /* Executes the parser. Returns number of parsed bytes. Sets * `parser->http_errno` on error. */ static size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); + const http_parser_settings *settings, + const char *data, + size_t len); /* If http_should_keep_alive() in the on_headers_complete or @@ -428,8 +440,8 @@ static void http_parser_url_init(struct http_parser_url *u); /* Parse a URL; return nonzero on failure */ static int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); + int is_connect, + struct http_parser_url *u); /* Pause or un-pause the parser; a nonzero value pauses */ static void http_parser_pause(http_parser *parser, int paused); @@ -443,7 +455,7 @@ static void http_parser_set_max_header_size(uint32_t size); static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #ifndef ULLONG_MAX -#define ULLONG_MAX ((uint64_t)-1) /* 2^64-1 */ +#define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ #endif #ifndef MIN @@ -455,33 +467,33 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #endif #ifndef BIT_AT -#define BIT_AT(a, i) \ - (!!((unsigned int)(a)[(unsigned int)(i) >> 3] & \ - (1 << ((unsigned int)(i)&7)))) +#define BIT_AT(a, i) \ + (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ + (1 << ((unsigned int) (i) &7)))) #endif #ifndef ELEM_AT -#define ELEM_AT(a, i, v) ((unsigned int)(i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) +#define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) #endif -#define SET_ERRNO(e) \ - do \ - { \ - parser->nread = nread; \ - parser->http_errno = (e); \ - } while (0) +#define SET_ERRNO(e) \ + do \ + { \ + parser->nread = nread; \ + parser->http_errno = (e); \ + } while (0) #define CURRENT_STATE() p_state #define UPDATE_STATE(V) p_state = (enum state)(V); -#define RETURN(V) \ - do \ - { \ - parser->nread = nread; \ - parser->state = CURRENT_STATE(); \ - return (V); \ - } while (0); +#define RETURN(V) \ + do \ + { \ + parser->nread = nread; \ + parser->state = CURRENT_STATE(); \ + return (V); \ + } while (0); #define REEXECUTE() \ - goto reexecute; + goto reexecute; #ifdef __GNUC__ #define LIKELY(X) __builtin_expect(!!(X), 1) @@ -492,27 +504,27 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #endif /* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ - do \ - { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (LIKELY(settings->on_##FOR)) \ - { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != settings->on_##FOR(parser))) \ - { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) \ - { \ - return (ER); \ - } \ - } \ - } while (0) +#define CALLBACK_NOTIFY_(FOR, ER) \ + do \ + { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (LIKELY(settings->on_##FOR)) \ + { \ + parser->state = CURRENT_STATE(); \ + if (UNLIKELY(0 != settings->on_##FOR(parser))) \ + { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + UPDATE_STATE(parser->state); \ + \ + /* We either errored above or got paused; get out */ \ + if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) \ + { \ + return (ER); \ + } \ + } \ + } while (0) /* Run the notify callback FOR and consume the current byte */ #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) @@ -521,50 +533,50 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) /* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ - do \ - { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) \ - { \ - if (LIKELY(settings->on_##FOR)) \ - { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != \ - settings->on_##FOR(parser, FOR##_mark, (LEN)))) \ - { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) \ - { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ - } while (0) +#define CALLBACK_DATA_(FOR, LEN, ER) \ + do \ + { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (FOR##_mark) \ + { \ + if (LIKELY(settings->on_##FOR)) \ + { \ + parser->state = CURRENT_STATE(); \ + if (UNLIKELY(0 != \ + settings->on_##FOR(parser, FOR##_mark, (LEN)))) \ + { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + UPDATE_STATE(parser->state); \ + \ + /* We either errored above or got paused; get out */ \ + if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) \ + { \ + return (ER); \ + } \ + } \ + FOR##_mark = NULL; \ + } \ + } while (0) /* Run the data callback FOR and consume the current byte */ #define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) /* Run the data callback FOR and don't consume the current byte */ #define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) /* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ - do \ - { \ - if (!FOR##_mark) \ - { \ - FOR##_mark = p; \ - } \ - } while (0) +#define MARK(FOR) \ + do \ + { \ + if (!FOR##_mark) \ + { \ + FOR##_mark = p; \ + } \ + } while (0) /* Don't allow the total size of the HTTP headers (including the status * line) to exceed max_header_size. This check is here to protect @@ -577,16 +589,16 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; * than any reasonable request or response so this should never affect * day-to-day operation. */ -#define COUNT_HEADER_SIZE(V) \ - do \ - { \ - nread += (uint32_t)(V); \ - if (UNLIKELY(nread > max_header_size)) \ - { \ - SET_ERRNO(HPE_HEADER_OVERFLOW); \ - goto error; \ - } \ - } while (0) +#define COUNT_HEADER_SIZE(V) \ + do \ + { \ + nread += (uint32_t)(V); \ + if (UNLIKELY(nread > max_header_size)) \ + { \ + SET_ERRNO(HPE_HEADER_OVERFLOW); \ + goto error; \ + } \ + } while (0) #define PROXY_CONNECTION "proxy-connection" #define CONNECTION "connection" @@ -597,56 +609,56 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #define KEEP_ALIVE "keep-alive" #define CLOSE "close" - static const char *method_strings[] = - { +static const char *method_strings[] = + { #define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) + HTTP_METHOD_MAP(XX) #undef XX - }; +}; - /* Tokens as defined by rfc 2616. Also lowercases them. +/* Tokens as defined by rfc 2616. Also lowercases them. * token = 1* * separators = "(" | ")" | "<" | ">" | "@" * | "," | ";" | ":" | "\" | <"> * | "/" | "[" | "]" | "?" | "=" * | "{" | "}" | SP | HT */ - static const char tokens[256] = { - /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - ' ', '!', 0, '#', '$', '%', '&', '\'', - /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, - /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', - /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, - /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', - /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0}; +static const char tokens[256] = { + /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + ' ', '!', 0, '#', '$', '%', '&', '\'', + /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 0, 0, '*', '+', 0, '-', '.', 0, + /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + '0', '1', '2', '3', '4', '5', '6', '7', + /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + '8', '9', 0, 0, 0, 0, 0, 0, + /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 'x', 'y', 'z', 0, 0, 0, '^', '_', + /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 'x', 'y', 'z', 0, '|', 0, '~', 0}; - static const int8_t unhex[256] = - {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const int8_t unhex[256] = + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; #if HTTP_PARSER_STRICT #define T(v) 0 @@ -654,45 +666,45 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; #define T(v) v #endif - static const uint8_t normal_url_char[32] = { - /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, - /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, - /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, - /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, - /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, - /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, - /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, - }; +static const uint8_t normal_url_char[32] = { + /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, + /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, + /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, + /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, + /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, + /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, + /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, + /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, +}; #undef T - enum state - { +enum state +{ s_dead = 1 /* important that this is > 0 */ , @@ -782,12 +794,12 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; , s_message_done - }; +}; #define PARSING_HEADER(state) (state <= s_headers_done) - enum header_states - { +enum header_states +{ h_general = 0, h_C, h_CO, @@ -821,10 +833,10 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; h_connection_keep_alive, h_connection_close, h_connection_upgrade - }; +}; - enum http_host_state - { +enum http_host_state +{ s_http_host_dead = 1, s_http_userinfo_start, s_http_userinfo, @@ -837,12 +849,12 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; s_http_host_v6_zone, s_http_host_port_start, s_http_host_port - }; +}; /* Macros for character classes; depends on strict-mode */ #define CR '\r' #define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) +#define LOWER(c) (unsigned char) (c | 0x20) #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') #define IS_NUM(c) ((c) >= '0' && (c) <= '9') #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) @@ -854,18 +866,18 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ (c) == '$' || (c) == ',') -#define STRICT_TOKEN(c) ((c == ' ') ? 0 : tokens[(unsigned char)c]) +#define STRICT_TOKEN(c) ((c == ' ') ? 0 : tokens[(unsigned char) c]) #if HTTP_PARSER_STRICT #define TOKEN(c) STRICT_TOKEN(c) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) +#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char) c)) #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') #else -#define TOKEN(c) tokens[(unsigned char)c] +#define TOKEN(c) tokens[(unsigned char) c] #define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c)&0x80)) + (BIT_AT(normal_url_char, (unsigned char) c) || ((c) &0x80)) #define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') + (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') #endif /** @@ -873,20 +885,20 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; * character or %x80-FF **/ #define IS_HEADER_CHAR(ch) \ - (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127)) + (ch == CR || ch == LF || ch == 9 || ((unsigned char) ch > 31 && ch != 127)) #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) #if HTTP_PARSER_STRICT -#define STRICT_CHECK(cond) \ - do \ - { \ - if (cond) \ - { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ - } while (0) +#define STRICT_CHECK(cond) \ + do \ + { \ + if (cond) \ + { \ + SET_ERRNO(HPE_STRICT); \ + goto error; \ + } \ + } while (0) #define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) #else #define STRICT_CHECK(cond) @@ -895,17 +907,17 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; /* Map errno values to strings for human-readable output */ #define HTTP_STRERROR_GEN(n, s) {"HPE_" #n, s}, - static struct - { +static struct +{ const char *name; const char *description; - } http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)}; +} http_strerror_tab[] = { + HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)}; #undef HTTP_STRERROR_GEN - static int http_message_needs_eof(const http_parser *parser); +static int http_message_needs_eof(const http_parser *parser); - /* Our URL parser. +/* Our URL parser. * * This is designed to be shared by http_parser_execute() for URL validation, * hence it has a state transition + byte-for-byte interface. In addition, it @@ -916,181 +928,181 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; * assumed that the caller cares about (and can detect) the transition between * URL and non-URL states by looking for these. */ - static enum state - parse_url_char(enum state s, const char ch) - { +static enum state +parse_url_char(enum state s, const char ch) +{ if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; + return s_dead; } #if HTTP_PARSER_STRICT if (ch == '\t' || ch == '\f') { - return s_dead; + return s_dead; } #endif switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). + case s_req_spaces_before_url: + /* Proxied requests are followed by scheme of an absolute URI (alpha). * All methods except CONNECT are followed by '/' or '*'. */ - if (ch == '/' || ch == '*') - { - return s_req_path; - } + if (ch == '/' || ch == '*') + { + return s_req_path; + } - if (IS_ALPHA(ch)) - { - return s_req_schema; - } + if (IS_ALPHA(ch)) + { + return s_req_schema; + } - break; + break; - case s_req_schema: - if (IS_ALPHA(ch)) - { - return s; - } + case s_req_schema: + if (IS_ALPHA(ch)) + { + return s; + } - if (ch == ':') - { - return s_req_schema_slash; - } + if (ch == ':') + { + return s_req_schema_slash; + } - break; + break; - case s_req_schema_slash: - if (ch == '/') - { - return s_req_schema_slash_slash; - } + case s_req_schema_slash: + if (ch == '/') + { + return s_req_schema_slash_slash; + } - break; + break; - case s_req_schema_slash_slash: - if (ch == '/') - { - return s_req_server_start; - } + case s_req_schema_slash_slash: + if (ch == '/') + { + return s_req_server_start; + } - break; + break; - case s_req_server_with_at: - if (ch == '@') - { - return s_dead; - } + case s_req_server_with_at: + if (ch == '@') + { + return s_dead; + } - /* fall through */ - case s_req_server_start: - case s_req_server: - if (ch == '/') - { - return s_req_path; - } + /* fall through */ + case s_req_server_start: + case s_req_server: + if (ch == '/') + { + return s_req_path; + } - if (ch == '?') - { - return s_req_query_string_start; - } + if (ch == '?') + { + return s_req_query_string_start; + } - if (ch == '@') - { - return s_req_server_with_at; - } + if (ch == '@') + { + return s_req_server_with_at; + } - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') - { - return s_req_server; - } + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') + { + return s_req_server; + } - break; + break; - case s_req_path: - if (IS_URL_CHAR(ch)) - { - return s; - } + case s_req_path: + if (IS_URL_CHAR(ch)) + { + return s; + } - switch (ch) - { - case '?': - return s_req_query_string_start; + switch (ch) + { + case '?': + return s_req_query_string_start; - case '#': - return s_req_fragment_start; - } + case '#': + return s_req_fragment_start; + } - break; + break; - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) - { - return s_req_query_string; - } + case s_req_query_string_start: + case s_req_query_string: + if (IS_URL_CHAR(ch)) + { + return s_req_query_string; + } - switch (ch) - { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; + switch (ch) + { + case '?': + /* allow extra '?' in query string */ + return s_req_query_string; - case '#': - return s_req_fragment_start; - } + case '#': + return s_req_fragment_start; + } - break; + break; - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) - { - return s_req_fragment; - } + case s_req_fragment_start: + if (IS_URL_CHAR(ch)) + { + return s_req_fragment; + } - switch (ch) - { - case '?': - return s_req_fragment; + switch (ch) + { + case '?': + return s_req_fragment; - case '#': - return s; - } + case '#': + return s; + } - break; + break; - case s_req_fragment: - if (IS_URL_CHAR(ch)) - { - return s; - } + case s_req_fragment: + if (IS_URL_CHAR(ch)) + { + return s; + } - switch (ch) - { - case '?': - case '#': - return s; - } + switch (ch) + { + case '?': + case '#': + return s; + } - break; + break; - default: - break; + default: + break; } /* We should never fall out of the switch above unless there's an error */ return s_dead; - } +} - static size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) - { +static size_t http_parser_execute(http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len) +{ char c, ch; int8_t unhex_val; const char *p = data; @@ -1099,1322 +1111,1322 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; const char *url_mark = 0; const char *body_mark = 0; const char *status_mark = 0; - enum state p_state = (enum state)parser->state; + enum state p_state = (enum state) parser->state; const unsigned int lenient = parser->lenient_http_headers; uint32_t nread = parser->nread; /* We're in an error state. Don't bother doing anything. */ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; + return 0; } if (len == 0) { - switch (CURRENT_STATE()) - { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if + switch (CURRENT_STATE()) + { + case s_body_identity_eof: + /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if * we got paused. */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; + CALLBACK_NOTIFY_NOADVANCE(message_complete); + return 0; - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; + case s_dead: + case s_start_req_or_res: + case s_start_res: + case s_start_req: + return 0; - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } + default: + SET_ERRNO(HPE_INVALID_EOF_STATE); + return 1; + } } if (CURRENT_STATE() == s_header_field) - header_field_mark = data; + header_field_mark = data; if (CURRENT_STATE() == s_header_value) - header_value_mark = data; + header_value_mark = data; switch (CURRENT_STATE()) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - case s_res_status: - status_mark = data; - break; - default: - break; + case s_req_path: + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + case s_req_server: + case s_req_server_with_at: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + url_mark = data; + break; + case s_res_status: + status_mark = data; + break; + default: + break; } for (p = data; p != data + len; p++) { - ch = *p; + ch = *p; - if (PARSING_HEADER(CURRENT_STATE())) - COUNT_HEADER_SIZE(1); + if (PARSING_HEADER(CURRENT_STATE())) + COUNT_HEADER_SIZE(1); reexecute: - switch (CURRENT_STATE()) - { + switch (CURRENT_STATE()) + { - case s_dead: - /* this state is used after a 'Connection: close' message + case s_dead: + /* this state is used after a 'Connection: close' message * the parser will error out if it reads another message */ - if (LIKELY(ch == CR || ch == LF)) - break; + if (LIKELY(ch == CR || ch == LF)) + break; - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; + SET_ERRNO(HPE_CLOSED_CONNECTION); + goto error; - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') - { - UPDATE_STATE(s_res_or_resp_H); - - CALLBACK_NOTIFY(message_begin); - } - else - { - parser->type = HTTP_REQUEST; - UPDATE_STATE(s_start_req); - REEXECUTE(); - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') - { - parser->type = HTTP_RESPONSE; - UPDATE_STATE(s_res_HT); - } - else - { - if (UNLIKELY(ch != 'E')) - { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - UPDATE_STATE(s_req_method); - } - break; - - case s_start_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') - { - UPDATE_STATE(s_res_H); - } - else - { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HT); - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HTT); - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_res_HTTP); - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_res_http_major); - break; - - case s_res_http_major: - if (UNLIKELY(!IS_NUM(ch))) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_res_http_dot); - break; - - case s_res_http_dot: - { - if (UNLIKELY(ch != '.')) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - UPDATE_STATE(s_res_http_minor); - break; - } - - case s_res_http_minor: - if (UNLIKELY(!IS_NUM(ch))) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_res_http_end); - break; - - case s_res_http_end: - { - if (UNLIKELY(ch != ' ')) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - UPDATE_STATE(s_res_first_status_code); - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) - { - if (ch == ' ') - { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - UPDATE_STATE(s_res_status_code); - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) - { - switch (ch) - { - case ' ': - UPDATE_STATE(s_res_status_start); - break; - case CR: - case LF: - UPDATE_STATE(s_res_status_start); - REEXECUTE(); - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (UNLIKELY(parser->status_code > 999)) - { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status_start: - { - MARK(status); - UPDATE_STATE(s_res_status); - parser->index = 0; - - if (ch == CR || ch == LF) - REEXECUTE(); - - break; - } - - case s_res_status: - if (ch == CR) - { - UPDATE_STATE(s_res_line_almost_done); - CALLBACK_DATA(status); - break; - } - - if (ch == LF) - { - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA(status); - break; - } - - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_field_start); - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (UNLIKELY(!IS_ALPHA(ch))) - { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method)0; - parser->index = 1; - switch (ch) - { - case 'A': - parser->method = HTTP_ACL; - break; - case 'B': - parser->method = HTTP_BIND; - break; - case 'C': - parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ - break; - case 'D': - parser->method = HTTP_DELETE; - break; - case 'G': - parser->method = HTTP_GET; - break; - case 'H': - parser->method = HTTP_HEAD; - break; - case 'L': - parser->method = HTTP_LOCK; /* or LINK */ - break; - case 'M': - parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ - break; - case 'N': - parser->method = HTTP_NOTIFY; - break; - case 'O': - parser->method = HTTP_OPTIONS; - break; - case 'P': - parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': - parser->method = HTTP_REPORT; /* or REBIND */ - break; - case 'S': - parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ - break; - case 'T': - parser->method = HTTP_TRACE; - break; - case 'U': - parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ - break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - UPDATE_STATE(s_req_method); - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (UNLIKELY(ch == '\0')) - { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') - { - UPDATE_STATE(s_req_spaces_before_url); - } - else if (ch == matcher[parser->index]) - { - ; /* nada */ - } - else if ((ch >= 'A' && ch <= 'Z') || ch == '-') - { - - switch (parser->method << 16 | parser->index << 8 | ch) - { -#define XX(meth, pos, ch, new_meth) \ - case (HTTP_##meth << 16 | pos << 8 | ch): \ - parser->method = HTTP_##new_meth; \ - break; - - XX(POST, 1, 'U', PUT) - XX(POST, 1, 'A', PATCH) - XX(POST, 1, 'R', PROPFIND) - XX(PUT, 2, 'R', PURGE) - XX(CONNECT, 1, 'H', CHECKOUT) - XX(CONNECT, 2, 'P', COPY) - XX(MKCOL, 1, 'O', MOVE) - XX(MKCOL, 1, 'E', MERGE) - XX(MKCOL, 1, '-', MSEARCH) - XX(MKCOL, 2, 'A', MKACTIVITY) - XX(MKCOL, 3, 'A', MKCALENDAR) - XX(SUBSCRIBE, 1, 'E', SEARCH) - XX(SUBSCRIBE, 1, 'O', SOURCE) - XX(REPORT, 2, 'B', REBIND) - XX(PROPFIND, 4, 'P', PROPPATCH) - XX(LOCK, 1, 'I', LINK) - XX(UNLOCK, 2, 'S', UNSUBSCRIBE) - XX(UNLOCK, 2, 'B', UNBIND) - XX(UNLOCK, 3, 'I', UNLINK) -#undef XX - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } - else - { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') - break; - - MARK(url); - if (parser->method == HTTP_CONNECT) - { - UPDATE_STATE(s_req_server_start); - } - - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) - { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) - { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) - { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) - { - case ' ': - UPDATE_STATE(s_req_http_start); - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - UPDATE_STATE((ch == CR) ? s_req_line_almost_done : s_header_field_start); - CALLBACK_DATA(url); - break; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) - { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) - { - case ' ': - break; - case 'H': - UPDATE_STATE(s_req_http_H); - break; - case 'I': - if (parser->method == HTTP_SOURCE) - { - UPDATE_STATE(s_req_http_I); - break; - } - /* fall through */ - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HT); - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HTT); - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_req_http_HTTP); - break; - - case s_req_http_I: - STRICT_CHECK(ch != 'C'); - UPDATE_STATE(s_req_http_IC); - break; - - case s_req_http_IC: - STRICT_CHECK(ch != 'E'); - UPDATE_STATE(s_req_http_HTTP); /* Treat "ICE" as "HTTP". */ - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_req_http_major); - break; - - case s_req_http_major: - if (UNLIKELY(!IS_NUM(ch))) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_req_http_dot); - break; - - case s_req_http_dot: - { - if (UNLIKELY(ch != '.')) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - UPDATE_STATE(s_req_http_minor); - break; - } - - case s_req_http_minor: - if (UNLIKELY(!IS_NUM(ch))) - { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_req_http_end); - break; - - case s_req_http_end: - { - if (ch == CR) - { - UPDATE_STATE(s_req_line_almost_done); - break; - } - - if (ch == LF) - { - UPDATE_STATE(s_header_field_start); - break; - } - - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (UNLIKELY(ch != LF)) - { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_field_start); - break; - } - - case s_header_field_start: - { - if (ch == CR) - { - UPDATE_STATE(s_headers_almost_done); - break; - } - - if (ch == LF) - { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - UPDATE_STATE(s_headers_almost_done); - REEXECUTE(); - } - - c = TOKEN(ch); - - if (UNLIKELY(!c)) - { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - UPDATE_STATE(s_header_field); - - switch (c) - { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - const char *start = p; - for (; p != data + len; p++) - { - ch = *p; - c = TOKEN(ch); - - if (!c) - break; - - switch (parser->header_state) - { - case h_general: - { - size_t left = data + len - p; - const char *pe = p + MIN(left, max_header_size); - while (p + 1 < pe && TOKEN(p[1])) + case s_start_req_or_res: { - p++; - } - break; - } + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; + if (ch == 'H') + { + UPDATE_STATE(s_res_or_resp_H); - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; + CALLBACK_NOTIFY(message_begin); + } + else + { + parser->type = HTTP_REQUEST; + UPDATE_STATE(s_start_req); + REEXECUTE(); + } - case h_CON: - parser->index++; - switch (c) - { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION) - 1 || c != CONNECTION[parser->index]) - { - parser->header_state = h_general; - } - else if (parser->index == sizeof(CONNECTION) - 2) - { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION) - 1 || c != PROXY_CONNECTION[parser->index]) - { - parser->header_state = h_general; - } - else if (parser->index == sizeof(PROXY_CONNECTION) - 2) - { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH) - 1 || c != CONTENT_LENGTH[parser->index]) - { - parser->header_state = h_general; - } - else if (parser->index == sizeof(CONTENT_LENGTH) - 2) - { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING) - 1 || c != TRANSFER_ENCODING[parser->index]) - { - parser->header_state = h_general; - } - else if (parser->index == sizeof(TRANSFER_ENCODING) - 2) - { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE) - 1 || c != UPGRADE[parser->index]) - { - parser->header_state = h_general; - } - else if (parser->index == sizeof(UPGRADE) - 2) - { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') - parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - } - - if (p == data + len) - { - --p; - COUNT_HEADER_SIZE(p - start); - break; - } - - COUNT_HEADER_SIZE(p - start); - - if (ch == ':') - { - UPDATE_STATE(s_header_value_discard_ws); - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_discard_ws: - if (ch == ' ' || ch == '\t') - break; - - if (ch == CR) - { - UPDATE_STATE(s_header_value_discard_ws_almost_done); - break; - } - - if (ch == LF) - { - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - /* fall through */ - - case s_header_value_start: - { - MARK(header_value); - - UPDATE_STATE(s_header_value); - parser->index = 0; - - c = LOWER(ch); - - switch (parser->header_state) - { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) - { - parser->header_state = h_matching_transfer_encoding_chunked; - } - else - { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (UNLIKELY(!IS_NUM(ch))) - { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - if (parser->flags & F_CONTENTLENGTH) - { - SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); - goto error; - } - - parser->flags |= F_CONTENTLENGTH; - parser->content_length = ch - '0'; - parser->header_state = h_content_length_num; - break; - - /* when obsolete line folding is encountered for content length - * continue to the s_header_value state */ - case h_content_length_ws: - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') - { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } - else if (c == 'c') - { - parser->header_state = h_matching_connection_close; - } - else if (c == 'u') - { - parser->header_state = h_matching_connection_upgrade; - } - else - { - parser->header_state = h_matching_connection_token; - } - break; - - /* Multi-value `Connection` header */ - case h_matching_connection_token_start: - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - const char *start = p; - enum header_states h_state = (enum header_states)parser->header_state; - for (; p != data + len; p++) - { - ch = *p; - if (ch == CR) - { - UPDATE_STATE(s_header_almost_done); - parser->header_state = h_state; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) - { - UPDATE_STATE(s_header_almost_done); - COUNT_HEADER_SIZE(p - start); - parser->header_state = h_state; - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - - if (!lenient && !IS_HEADER_CHAR(ch)) - { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - c = LOWER(ch); - - switch (h_state) - { - case h_general: - { - size_t left = data + len - p; - const char *pe = p + MIN(left, max_header_size); - - for (; p != pe; p++) - { - ch = *p; - if (ch == CR || ch == LF) - { - --p; break; - } - if (!lenient && !IS_HEADER_CHAR(ch)) - { + } + + case s_res_or_resp_H: + if (ch == 'T') + { + parser->type = HTTP_RESPONSE; + UPDATE_STATE(s_res_HT); + } + else + { + if (UNLIKELY(ch != 'E')) + { + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + parser->type = HTTP_REQUEST; + parser->method = HTTP_HEAD; + parser->index = 2; + UPDATE_STATE(s_req_method); + } + break; + + case s_start_res: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (ch == 'H') + { + UPDATE_STATE(s_res_H); + } + else + { + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + CALLBACK_NOTIFY(message_begin); + break; + } + + case s_res_H: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_res_HT); + break; + + case s_res_HT: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_res_HTT); + break; + + case s_res_HTT: + STRICT_CHECK(ch != 'P'); + UPDATE_STATE(s_res_HTTP); + break; + + case s_res_HTTP: + STRICT_CHECK(ch != '/'); + UPDATE_STATE(s_res_http_major); + break; + + case s_res_http_major: + if (UNLIKELY(!IS_NUM(ch))) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + UPDATE_STATE(s_res_http_dot); + break; + + case s_res_http_dot: + { + if (UNLIKELY(ch != '.')) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + UPDATE_STATE(s_res_http_minor); + break; + } + + case s_res_http_minor: + if (UNLIKELY(!IS_NUM(ch))) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + UPDATE_STATE(s_res_http_end); + break; + + case s_res_http_end: + { + if (UNLIKELY(ch != ' ')) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + UPDATE_STATE(s_res_first_status_code); + break; + } + + case s_res_first_status_code: + { + if (!IS_NUM(ch)) + { + if (ch == ' ') + { + break; + } + + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + parser->status_code = ch - '0'; + UPDATE_STATE(s_res_status_code); + break; + } + + case s_res_status_code: + { + if (!IS_NUM(ch)) + { + switch (ch) + { + case ' ': + UPDATE_STATE(s_res_status_start); + break; + case CR: + case LF: + UPDATE_STATE(s_res_status_start); + REEXECUTE(); + break; + default: + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + break; + } + + parser->status_code *= 10; + parser->status_code += ch - '0'; + + if (UNLIKELY(parser->status_code > 999)) + { + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + + break; + } + + case s_res_status_start: + { + MARK(status); + UPDATE_STATE(s_res_status); + parser->index = 0; + + if (ch == CR || ch == LF) + REEXECUTE(); + + break; + } + + case s_res_status: + if (ch == CR) + { + UPDATE_STATE(s_res_line_almost_done); + CALLBACK_DATA(status); + break; + } + + if (ch == LF) + { + UPDATE_STATE(s_header_field_start); + CALLBACK_DATA(status); + break; + } + + break; + + case s_res_line_almost_done: + STRICT_CHECK(ch != LF); + UPDATE_STATE(s_header_field_start); + break; + + case s_start_req: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (UNLIKELY(!IS_ALPHA(ch))) + { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + parser->method = (enum http_method) 0; + parser->index = 1; + switch (ch) + { + case 'A': + parser->method = HTTP_ACL; + break; + case 'B': + parser->method = HTTP_BIND; + break; + case 'C': + parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ + break; + case 'D': + parser->method = HTTP_DELETE; + break; + case 'G': + parser->method = HTTP_GET; + break; + case 'H': + parser->method = HTTP_HEAD; + break; + case 'L': + parser->method = HTTP_LOCK; /* or LINK */ + break; + case 'M': + parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ + break; + case 'N': + parser->method = HTTP_NOTIFY; + break; + case 'O': + parser->method = HTTP_OPTIONS; + break; + case 'P': + parser->method = HTTP_POST; + /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ + break; + case 'R': + parser->method = HTTP_REPORT; /* or REBIND */ + break; + case 'S': + parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ + break; + case 'T': + parser->method = HTTP_TRACE; + break; + case 'U': + parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ + break; + default: + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + UPDATE_STATE(s_req_method); + + CALLBACK_NOTIFY(message_begin); + + break; + } + + case s_req_method: + { + const char *matcher; + if (UNLIKELY(ch == '\0')) + { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + matcher = method_strings[parser->method]; + if (ch == ' ' && matcher[parser->index] == '\0') + { + UPDATE_STATE(s_req_spaces_before_url); + } + else if (ch == matcher[parser->index]) + { + ; /* nada */ + } + else if ((ch >= 'A' && ch <= 'Z') || ch == '-') + { + + switch (parser->method << 16 | parser->index << 8 | ch) + { +#define XX(meth, pos, ch, new_meth) \ + case (HTTP_##meth << 16 | pos << 8 | ch): \ + parser->method = HTTP_##new_meth; \ + break; + + XX(POST, 1, 'U', PUT) + XX(POST, 1, 'A', PATCH) + XX(POST, 1, 'R', PROPFIND) + XX(PUT, 2, 'R', PURGE) + XX(CONNECT, 1, 'H', CHECKOUT) + XX(CONNECT, 2, 'P', COPY) + XX(MKCOL, 1, 'O', MOVE) + XX(MKCOL, 1, 'E', MERGE) + XX(MKCOL, 1, '-', MSEARCH) + XX(MKCOL, 2, 'A', MKACTIVITY) + XX(MKCOL, 3, 'A', MKCALENDAR) + XX(SUBSCRIBE, 1, 'E', SEARCH) + XX(SUBSCRIBE, 1, 'O', SOURCE) + XX(REPORT, 2, 'B', REBIND) + XX(PROPFIND, 4, 'P', PROPPATCH) + XX(LOCK, 1, 'I', LINK) + XX(UNLOCK, 2, 'S', UNSUBSCRIBE) + XX(UNLOCK, 2, 'B', UNBIND) + XX(UNLOCK, 3, 'I', UNLINK) +#undef XX + default: + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + } + else + { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + ++parser->index; + break; + } + + case s_req_spaces_before_url: + { + if (ch == ' ') + break; + + MARK(url); + if (parser->method == HTTP_CONNECT) + { + UPDATE_STATE(s_req_server_start); + } + + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); + if (UNLIKELY(CURRENT_STATE() == s_dead)) + { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + + break; + } + + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + { + switch (ch) + { + /* No whitespace allowed here */ + case ' ': + case CR: + case LF: + SET_ERRNO(HPE_INVALID_URL); + goto error; + default: + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); + if (UNLIKELY(CURRENT_STATE() == s_dead)) + { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + + break; + } + + case s_req_server: + case s_req_server_with_at: + case s_req_path: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + { + switch (ch) + { + case ' ': + UPDATE_STATE(s_req_http_start); + CALLBACK_DATA(url); + break; + case CR: + case LF: + parser->http_major = 0; + parser->http_minor = 9; + UPDATE_STATE((ch == CR) ? s_req_line_almost_done : s_header_field_start); + CALLBACK_DATA(url); + break; + default: + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); + if (UNLIKELY(CURRENT_STATE() == s_dead)) + { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + break; + } + + case s_req_http_start: + switch (ch) + { + case ' ': + break; + case 'H': + UPDATE_STATE(s_req_http_H); + break; + case 'I': + if (parser->method == HTTP_SOURCE) + { + UPDATE_STATE(s_req_http_I); + break; + } + /* fall through */ + default: + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + break; + + case s_req_http_H: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_req_http_HT); + break; + + case s_req_http_HT: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_req_http_HTT); + break; + + case s_req_http_HTT: + STRICT_CHECK(ch != 'P'); + UPDATE_STATE(s_req_http_HTTP); + break; + + case s_req_http_I: + STRICT_CHECK(ch != 'C'); + UPDATE_STATE(s_req_http_IC); + break; + + case s_req_http_IC: + STRICT_CHECK(ch != 'E'); + UPDATE_STATE(s_req_http_HTTP); /* Treat "ICE" as "HTTP". */ + break; + + case s_req_http_HTTP: + STRICT_CHECK(ch != '/'); + UPDATE_STATE(s_req_http_major); + break; + + case s_req_http_major: + if (UNLIKELY(!IS_NUM(ch))) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + UPDATE_STATE(s_req_http_dot); + break; + + case s_req_http_dot: + { + if (UNLIKELY(ch != '.')) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + UPDATE_STATE(s_req_http_minor); + break; + } + + case s_req_http_minor: + if (UNLIKELY(!IS_NUM(ch))) + { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + UPDATE_STATE(s_req_http_end); + break; + + case s_req_http_end: + { + if (ch == CR) + { + UPDATE_STATE(s_req_line_almost_done); + break; + } + + if (ch == LF) + { + UPDATE_STATE(s_header_field_start); + break; + } + + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + break; + } + + /* end of request line */ + case s_req_line_almost_done: + { + if (UNLIKELY(ch != LF)) + { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } + + UPDATE_STATE(s_header_field_start); + break; + } + + case s_header_field_start: + { + if (ch == CR) + { + UPDATE_STATE(s_headers_almost_done); + break; + } + + if (ch == LF) + { + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + UPDATE_STATE(s_headers_almost_done); + REEXECUTE(); + } + + c = TOKEN(ch); + + if (UNLIKELY(!c)) + { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + MARK(header_field); + + parser->index = 0; + UPDATE_STATE(s_header_field); + + switch (c) + { + case 'c': + parser->header_state = h_C; + break; + + case 'p': + parser->header_state = h_matching_proxy_connection; + break; + + case 't': + parser->header_state = h_matching_transfer_encoding; + break; + + case 'u': + parser->header_state = h_matching_upgrade; + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_field: + { + const char *start = p; + for (; p != data + len; p++) + { + ch = *p; + c = TOKEN(ch); + + if (!c) + break; + + switch (parser->header_state) + { + case h_general: + { + size_t left = data + len - p; + const char *pe = p + MIN(left, max_header_size); + while (p + 1 < pe && TOKEN(p[1])) + { + p++; + } + break; + } + + case h_C: + parser->index++; + parser->header_state = (c == 'o' ? h_CO : h_general); + break; + + case h_CO: + parser->index++; + parser->header_state = (c == 'n' ? h_CON : h_general); + break; + + case h_CON: + parser->index++; + switch (c) + { + case 'n': + parser->header_state = h_matching_connection; + break; + case 't': + parser->header_state = h_matching_content_length; + break; + default: + parser->header_state = h_general; + break; + } + break; + + /* connection */ + + case h_matching_connection: + parser->index++; + if (parser->index > sizeof(CONNECTION) - 1 || c != CONNECTION[parser->index]) + { + parser->header_state = h_general; + } + else if (parser->index == sizeof(CONNECTION) - 2) + { + parser->header_state = h_connection; + } + break; + + /* proxy-connection */ + + case h_matching_proxy_connection: + parser->index++; + if (parser->index > sizeof(PROXY_CONNECTION) - 1 || c != PROXY_CONNECTION[parser->index]) + { + parser->header_state = h_general; + } + else if (parser->index == sizeof(PROXY_CONNECTION) - 2) + { + parser->header_state = h_connection; + } + break; + + /* content-length */ + + case h_matching_content_length: + parser->index++; + if (parser->index > sizeof(CONTENT_LENGTH) - 1 || c != CONTENT_LENGTH[parser->index]) + { + parser->header_state = h_general; + } + else if (parser->index == sizeof(CONTENT_LENGTH) - 2) + { + parser->header_state = h_content_length; + } + break; + + /* transfer-encoding */ + + case h_matching_transfer_encoding: + parser->index++; + if (parser->index > sizeof(TRANSFER_ENCODING) - 1 || c != TRANSFER_ENCODING[parser->index]) + { + parser->header_state = h_general; + } + else if (parser->index == sizeof(TRANSFER_ENCODING) - 2) + { + parser->header_state = h_transfer_encoding; + } + break; + + /* upgrade */ + + case h_matching_upgrade: + parser->index++; + if (parser->index > sizeof(UPGRADE) - 1 || c != UPGRADE[parser->index]) + { + parser->header_state = h_general; + } + else if (parser->index == sizeof(UPGRADE) - 2) + { + parser->header_state = h_upgrade; + } + break; + + case h_connection: + case h_content_length: + case h_transfer_encoding: + case h_upgrade: + if (ch != ' ') + parser->header_state = h_general; + break; + + default: + assert(0 && "Unknown header_state"); + break; + } + } + + if (p == data + len) + { + --p; + COUNT_HEADER_SIZE(p - start); + break; + } + + COUNT_HEADER_SIZE(p - start); + + if (ch == ':') + { + UPDATE_STATE(s_header_value_discard_ws); + CALLBACK_DATA(header_field); + break; + } + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; - } } - if (p == data + len) - --p; - break; - } - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; + case s_header_value_discard_ws: + if (ch == ' ' || ch == '\t') + break; - case h_content_length: - if (ch == ' ') - break; - h_state = h_content_length_num; - /* fall through */ + if (ch == CR) + { + UPDATE_STATE(s_header_value_discard_ws_almost_done); + break; + } - case h_content_length_num: - { - uint64_t t; + if (ch == LF) + { + UPDATE_STATE(s_header_value_discard_lws); + break; + } - if (ch == ' ') + /* fall through */ + + case s_header_value_start: { - h_state = h_content_length_ws; - break; + MARK(header_value); + + UPDATE_STATE(s_header_value); + parser->index = 0; + + c = LOWER(ch); + + switch (parser->header_state) + { + case h_upgrade: + parser->flags |= F_UPGRADE; + parser->header_state = h_general; + break; + + case h_transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if ('c' == c) + { + parser->header_state = h_matching_transfer_encoding_chunked; + } + else + { + parser->header_state = h_general; + } + break; + + case h_content_length: + if (UNLIKELY(!IS_NUM(ch))) + { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + if (parser->flags & F_CONTENTLENGTH) + { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } + + parser->flags |= F_CONTENTLENGTH; + parser->content_length = ch - '0'; + parser->header_state = h_content_length_num; + break; + + /* when obsolete line folding is encountered for content length + * continue to the s_header_value state */ + case h_content_length_ws: + break; + + case h_connection: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') + { + parser->header_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } + else if (c == 'c') + { + parser->header_state = h_matching_connection_close; + } + else if (c == 'u') + { + parser->header_state = h_matching_connection_upgrade; + } + else + { + parser->header_state = h_matching_connection_token; + } + break; + + /* Multi-value `Connection` header */ + case h_matching_connection_token_start: + break; + + default: + parser->header_state = h_general; + break; + } + break; } - if (UNLIKELY(!IS_NUM(ch))) + case s_header_value: { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; + const char *start = p; + enum header_states h_state = (enum header_states) parser->header_state; + for (; p != data + len; p++) + { + ch = *p; + if (ch == CR) + { + UPDATE_STATE(s_header_almost_done); + parser->header_state = h_state; + CALLBACK_DATA(header_value); + break; + } + + if (ch == LF) + { + UPDATE_STATE(s_header_almost_done); + COUNT_HEADER_SIZE(p - start); + parser->header_state = h_state; + CALLBACK_DATA_NOADVANCE(header_value); + REEXECUTE(); + } + + if (!lenient && !IS_HEADER_CHAR(ch)) + { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + c = LOWER(ch); + + switch (h_state) + { + case h_general: + { + size_t left = data + len - p; + const char *pe = p + MIN(left, max_header_size); + + for (; p != pe; p++) + { + ch = *p; + if (ch == CR || ch == LF) + { + --p; + break; + } + if (!lenient && !IS_HEADER_CHAR(ch)) + { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + } + if (p == data + len) + --p; + break; + } + + case h_connection: + case h_transfer_encoding: + assert(0 && "Shouldn't get here."); + break; + + case h_content_length: + if (ch == ' ') + break; + h_state = h_content_length_num; + /* fall through */ + + case h_content_length_num: + { + uint64_t t; + + if (ch == ' ') + { + h_state = h_content_length_ws; + break; + } + + if (UNLIKELY(!IS_NUM(ch))) + { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + parser->header_state = h_state; + goto error; + } + + t = parser->content_length; + t *= 10; + t += ch - '0'; + + /* Overflow? Test against a conservative limit for simplicity. */ + if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) + { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + parser->header_state = h_state; + goto error; + } + + parser->content_length = t; + break; + } + + case h_content_length_ws: + if (ch == ' ') + break; + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + parser->header_state = h_state; + goto error; + + /* Transfer-Encoding: chunked */ + case h_matching_transfer_encoding_chunked: + parser->index++; + if (parser->index > sizeof(CHUNKED) - 1 || c != CHUNKED[parser->index]) + { + h_state = h_general; + } + else if (parser->index == sizeof(CHUNKED) - 2) + { + h_state = h_transfer_encoding_chunked; + } + break; + + case h_matching_connection_token_start: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') + { + h_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } + else if (c == 'c') + { + h_state = h_matching_connection_close; + } + else if (c == 'u') + { + h_state = h_matching_connection_upgrade; + } + else if (STRICT_TOKEN(c)) + { + h_state = h_matching_connection_token; + } + else if (c == ' ' || c == '\t') + { + /* Skip lws */ + } + else + { + h_state = h_general; + } + break; + + /* looking for 'Connection: keep-alive' */ + case h_matching_connection_keep_alive: + parser->index++; + if (parser->index > sizeof(KEEP_ALIVE) - 1 || c != KEEP_ALIVE[parser->index]) + { + h_state = h_matching_connection_token; + } + else if (parser->index == sizeof(KEEP_ALIVE) - 2) + { + h_state = h_connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case h_matching_connection_close: + parser->index++; + if (parser->index > sizeof(CLOSE) - 1 || c != CLOSE[parser->index]) + { + h_state = h_matching_connection_token; + } + else if (parser->index == sizeof(CLOSE) - 2) + { + h_state = h_connection_close; + } + break; + + /* looking for 'Connection: upgrade' */ + case h_matching_connection_upgrade: + parser->index++; + if (parser->index > sizeof(UPGRADE) - 1 || + c != UPGRADE[parser->index]) + { + h_state = h_matching_connection_token; + } + else if (parser->index == sizeof(UPGRADE) - 2) + { + h_state = h_connection_upgrade; + } + break; + + case h_matching_connection_token: + if (ch == ',') + { + h_state = h_matching_connection_token_start; + parser->index = 0; + } + break; + + case h_transfer_encoding_chunked: + if (ch != ' ') + h_state = h_general; + break; + + case h_connection_keep_alive: + case h_connection_close: + case h_connection_upgrade: + if (ch == ',') + { + if (h_state == h_connection_keep_alive) + { + parser->flags |= F_CONNECTION_KEEP_ALIVE; + } + else if (h_state == h_connection_close) + { + parser->flags |= F_CONNECTION_CLOSE; + } + else if (h_state == h_connection_upgrade) + { + parser->flags |= F_CONNECTION_UPGRADE; + } + h_state = h_matching_connection_token_start; + parser->index = 0; + } + else if (ch != ' ') + { + h_state = h_matching_connection_token; + } + break; + + default: + UPDATE_STATE(s_header_value); + h_state = h_general; + break; + } + } + parser->header_state = h_state; + + if (p == data + len) + --p; + + COUNT_HEADER_SIZE(p - start); + break; } - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) + case s_header_almost_done: { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; + if (UNLIKELY(ch != LF)) + { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } + + UPDATE_STATE(s_header_value_lws); + break; } - parser->content_length = t; - break; - } - - case h_content_length_ws: - if (ch == ' ') - break; - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED) - 1 || c != CHUNKED[parser->index]) + case s_header_value_lws: { - h_state = h_general; + if (ch == ' ' || ch == '\t') + { + if (parser->header_state == h_content_length_num) + { + /* treat obsolete line folding as space */ + parser->header_state = h_content_length_ws; + } + UPDATE_STATE(s_header_value_start); + REEXECUTE(); + } + + /* finished the header */ + switch (parser->header_state) + { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + case h_connection_upgrade: + parser->flags |= F_CONNECTION_UPGRADE; + break; + default: + break; + } + + UPDATE_STATE(s_header_field_start); + REEXECUTE(); } - else if (parser->index == sizeof(CHUNKED) - 2) + + case s_header_value_discard_ws_almost_done: { - h_state = h_transfer_encoding_chunked; + STRICT_CHECK(ch != LF); + UPDATE_STATE(s_header_value_discard_lws); + break; } - break; - case h_matching_connection_token_start: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') + case s_header_value_discard_lws: { - h_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ + if (ch == ' ' || ch == '\t') + { + UPDATE_STATE(s_header_value_discard_ws); + break; + } + else + { + switch (parser->header_state) + { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_connection_upgrade: + parser->flags |= F_CONNECTION_UPGRADE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + case h_content_length: + /* do not allow empty content length */ + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + break; + default: + break; + } + + /* header value was empty */ + MARK(header_value); + UPDATE_STATE(s_header_field_start); + CALLBACK_DATA_NOADVANCE(header_value); + REEXECUTE(); + } } - else if (c == 'c') + + case s_headers_almost_done: { - h_state = h_matching_connection_close; - } - else if (c == 'u') - { - h_state = h_matching_connection_upgrade; - } - else if (STRICT_TOKEN(c)) - { - h_state = h_matching_connection_token; - } - else if (c == ' ' || c == '\t') - { - /* Skip lws */ - } - else - { - h_state = h_general; - } - break; + STRICT_CHECK(ch != LF); - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE) - 1 || c != KEEP_ALIVE[parser->index]) - { - h_state = h_matching_connection_token; - } - else if (parser->index == sizeof(KEEP_ALIVE) - 2) - { - h_state = h_connection_keep_alive; - } - break; + if (parser->flags & F_TRAILING) + { + /* End of a chunked request */ + UPDATE_STATE(s_message_done); + CALLBACK_NOTIFY_NOADVANCE(chunk_complete); + REEXECUTE(); + } - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE) - 1 || c != CLOSE[parser->index]) - { - h_state = h_matching_connection_token; - } - else if (parser->index == sizeof(CLOSE) - 2) - { - h_state = h_connection_close; - } - break; - - /* looking for 'Connection: upgrade' */ - case h_matching_connection_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE) - 1 || - c != UPGRADE[parser->index]) - { - h_state = h_matching_connection_token; - } - else if (parser->index == sizeof(UPGRADE) - 2) - { - h_state = h_connection_upgrade; - } - break; - - case h_matching_connection_token: - if (ch == ',') - { - h_state = h_matching_connection_token_start; - parser->index = 0; - } - break; - - case h_transfer_encoding_chunked: - if (ch != ' ') - h_state = h_general; - break; - - case h_connection_keep_alive: - case h_connection_close: - case h_connection_upgrade: - if (ch == ',') - { - if (h_state == h_connection_keep_alive) - { - parser->flags |= F_CONNECTION_KEEP_ALIVE; - } - else if (h_state == h_connection_close) - { - parser->flags |= F_CONNECTION_CLOSE; - } - else if (h_state == h_connection_upgrade) - { - parser->flags |= F_CONNECTION_UPGRADE; - } - h_state = h_matching_connection_token_start; - parser->index = 0; - } - else if (ch != ' ') - { - h_state = h_matching_connection_token; - } - break; - - default: - UPDATE_STATE(s_header_value); - h_state = h_general; - break; - } - } - parser->header_state = h_state; - - if (p == data + len) - --p; - - COUNT_HEADER_SIZE(p - start); - break; - } - - case s_header_almost_done: - { - if (UNLIKELY(ch != LF)) - { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_value_lws); - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') - { - if (parser->header_state == h_content_length_num) - { - /* treat obsolete line folding as space */ - parser->header_state = h_content_length_ws; - } - UPDATE_STATE(s_header_value_start); - REEXECUTE(); - } - - /* finished the header */ - switch (parser->header_state) - { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - default: - break; - } - - UPDATE_STATE(s_header_field_start); - REEXECUTE(); - } - - case s_header_value_discard_ws_almost_done: - { - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - case s_header_value_discard_lws: - { - if (ch == ' ' || ch == '\t') - { - UPDATE_STATE(s_header_value_discard_ws); - break; - } - else - { - switch (parser->header_state) - { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - case h_content_length: - /* do not allow empty content length */ - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - break; - default: - break; - } - - /* header value was empty */ - MARK(header_value); - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) - { - /* End of a chunked request */ - UPDATE_STATE(s_message_done); - CALLBACK_NOTIFY_NOADVANCE(chunk_complete); - REEXECUTE(); - } - - /* Cannot use chunked encoding and a content-length header together + /* Cannot use chunked encoding and a content-length header together per the HTTP specification. */ - if ((parser->flags & F_CHUNKED) && - (parser->flags & F_CONTENTLENGTH)) - { - SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); - goto error; - } + if ((parser->flags & F_CHUNKED) && + (parser->flags & F_CONTENTLENGTH)) + { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } - UPDATE_STATE(s_headers_done); + UPDATE_STATE(s_headers_done); - /* Set this here so that on_headers_complete() callbacks can see it */ - if ((parser->flags & F_UPGRADE) && - (parser->flags & F_CONNECTION_UPGRADE)) - { - /* For responses, "Upgrade: foo" and "Connection: upgrade" are + /* Set this here so that on_headers_complete() callbacks can see it */ + if ((parser->flags & F_UPGRADE) && + (parser->flags & F_CONNECTION_UPGRADE)) + { + /* For responses, "Upgrade: foo" and "Connection: upgrade" are * mandatory only when it is a 101 Switching Protocols response, * otherwise it is purely informational, to announce support. */ - parser->upgrade = - (parser->type == HTTP_REQUEST || parser->status_code == 101); - } - else - { - parser->upgrade = (parser->method == HTTP_CONNECT); - } + parser->upgrade = + (parser->type == HTTP_REQUEST || parser->status_code == 101); + } + else + { + parser->upgrade = (parser->method == HTTP_CONNECT); + } - /* Here we call the headers_complete callback. This is somewhat + /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This * is needed for the annoying case of recieving a response to a HEAD @@ -2423,117 +2435,117 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so * we have to simulate it by handling a change in errno below. */ - if (settings->on_headers_complete) - { - switch (settings->on_headers_complete(parser)) - { - case 0: - break; + if (settings->on_headers_complete) + { + switch (settings->on_headers_complete(parser)) + { + case 0: + break; - case 2: - parser->upgrade = 1; + case 2: + parser->upgrade = 1; - /* fall through */ - case 1: - parser->flags |= F_SKIPBODY; - break; + /* fall through */ + case 1: + parser->flags |= F_SKIPBODY; + break; - default: - SET_ERRNO(HPE_CB_headers_complete); - RETURN(p - data); /* Error */ - } - } + default: + SET_ERRNO(HPE_CB_headers_complete); + RETURN(p - data); /* Error */ + } + } - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) - { - RETURN(p - data); - } + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) + { + RETURN(p - data); + } - REEXECUTE(); - } - - case s_headers_done: - { - int hasBody; - STRICT_CHECK(ch != LF); - - parser->nread = 0; - nread = 0; - - hasBody = parser->flags & F_CHUNKED || - (parser->content_length > 0 && parser->content_length != ULLONG_MAX); - if (parser->upgrade && (parser->method == HTTP_CONNECT || - (parser->flags & F_SKIPBODY) || !hasBody)) - { - /* Exit, the rest of the message is in a different protocol. */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - RETURN((p - data) + 1); - } - - if (parser->flags & F_SKIPBODY) - { - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } - else if (parser->flags & F_CHUNKED) - { - /* chunked encoding - ignore Content-Length header */ - UPDATE_STATE(s_chunk_size_start); - } - else - { - if (parser->content_length == 0) - { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } - else if (parser->content_length != ULLONG_MAX) - { - /* Content-Length header given and non-zero */ - UPDATE_STATE(s_body_identity); - } - else - { - if (!http_message_needs_eof(parser)) - { - /* Assume content-length 0 - read the next */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); + REEXECUTE(); } - else + + case s_headers_done: { - /* Read body until EOF */ - UPDATE_STATE(s_body_identity_eof); + int hasBody; + STRICT_CHECK(ch != LF); + + parser->nread = 0; + nread = 0; + + hasBody = parser->flags & F_CHUNKED || + (parser->content_length > 0 && parser->content_length != ULLONG_MAX); + if (parser->upgrade && (parser->method == HTTP_CONNECT || + (parser->flags & F_SKIPBODY) || !hasBody)) + { + /* Exit, the rest of the message is in a different protocol. */ + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + RETURN((p - data) + 1); + } + + if (parser->flags & F_SKIPBODY) + { + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + } + else if (parser->flags & F_CHUNKED) + { + /* chunked encoding - ignore Content-Length header */ + UPDATE_STATE(s_chunk_size_start); + } + else + { + if (parser->content_length == 0) + { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + } + else if (parser->content_length != ULLONG_MAX) + { + /* Content-Length header given and non-zero */ + UPDATE_STATE(s_body_identity); + } + else + { + if (!http_message_needs_eof(parser)) + { + /* Assume content-length 0 - read the next */ + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + } + else + { + /* Read body until EOF */ + UPDATE_STATE(s_body_identity_eof); + } + } + } + + break; } - } - } - break; - } + case s_body_identity: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t)((data + len) - p)); - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t)((data + len) - p)); + assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); - assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because + /* The difference between advancing content_length and p is because * the latter will automaticaly advance on the next loop iteration. * Further, if content_length ends up at 0, we want to see the last * byte again for our message complete callback. */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; - if (parser->content_length == 0) - { - UPDATE_STATE(s_message_done); + if (parser->content_length == 0) + { + UPDATE_STATE(s_message_done); - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. + /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. * * The alternative to doing this is to wait for the next byte to * trigger the data callback, just as in every other case. The @@ -2542,166 +2554,166 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; * complete-on-length. It's not clear that this distinction is * important for applications, but let's keep it for now. */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - REEXECUTE(); - } + CALLBACK_DATA_(body, p - body_mark + 1, p - data); + REEXECUTE(); + } - break; - } + break; + } - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; + /* read until EOF */ + case s_body_identity_eof: + MARK(body); + p = data + len - 1; - break; + break; - case s_message_done: - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - if (parser->upgrade) - { - /* Exit, the rest of the message is in a different protocol. */ - RETURN((p - data) + 1); - } - break; + case s_message_done: + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + if (parser->upgrade) + { + /* Exit, the rest of the message is in a different protocol. */ + RETURN((p - data) + 1); + } + break; - case s_chunk_size_start: - { - assert(nread == 1); - assert(parser->flags & F_CHUNKED); + case s_chunk_size_start: + { + assert(nread == 1); + assert(parser->flags & F_CHUNKED); - unhex_val = unhex[(unsigned char)ch]; - if (UNLIKELY(unhex_val == -1)) - { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } + unhex_val = unhex[(unsigned char) ch]; + if (UNLIKELY(unhex_val == -1)) + { + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } - parser->content_length = unhex_val; - UPDATE_STATE(s_chunk_size); - break; - } + parser->content_length = unhex_val; + UPDATE_STATE(s_chunk_size); + break; + } - case s_chunk_size: - { - uint64_t t; + case s_chunk_size: + { + uint64_t t; - assert(parser->flags & F_CHUNKED); + assert(parser->flags & F_CHUNKED); - if (ch == CR) - { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } + if (ch == CR) + { + UPDATE_STATE(s_chunk_size_almost_done); + break; + } - unhex_val = unhex[(unsigned char)ch]; + unhex_val = unhex[(unsigned char) ch]; - if (unhex_val == -1) - { - if (ch == ';' || ch == ' ') - { - UPDATE_STATE(s_chunk_parameters); - break; - } + if (unhex_val == -1) + { + if (ch == ';' || ch == ' ') + { + UPDATE_STATE(s_chunk_parameters); + break; + } - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } - t = parser->content_length; - t *= 16; - t += unhex_val; + t = parser->content_length; + t *= 16; + t += unhex_val; - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) - { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } + /* Overflow? Test against a conservative limit for simplicity. */ + if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) + { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } - parser->content_length = t; - break; - } + parser->content_length = t; + break; + } - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this shit. TODO check for overflow */ - if (ch == CR) - { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - break; - } + case s_chunk_parameters: + { + assert(parser->flags & F_CHUNKED); + /* just ignore this shit. TODO check for overflow */ + if (ch == CR) + { + UPDATE_STATE(s_chunk_size_almost_done); + break; + } + break; + } - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); + case s_chunk_size_almost_done: + { + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); - parser->nread = 0; - nread = 0; + parser->nread = 0; + nread = 0; - if (parser->content_length == 0) - { - parser->flags |= F_TRAILING; - UPDATE_STATE(s_header_field_start); - } - else - { - UPDATE_STATE(s_chunk_data); - } - CALLBACK_NOTIFY(chunk_header); - break; - } + if (parser->content_length == 0) + { + parser->flags |= F_TRAILING; + UPDATE_STATE(s_header_field_start); + } + else + { + UPDATE_STATE(s_chunk_data); + } + CALLBACK_NOTIFY(chunk_header); + break; + } - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t)((data + len) - p)); + case s_chunk_data: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t)((data + len) - p)); - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); + assert(parser->flags & F_CHUNKED); + assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); - /* See the explanation in s_body_identity for why the content + /* See the explanation in s_body_identity for why the content * length and data pointers are managed this way. */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; - if (parser->content_length == 0) - { - UPDATE_STATE(s_chunk_data_almost_done); + if (parser->content_length == 0) + { + UPDATE_STATE(s_chunk_data_almost_done); + } + + break; + } + + case s_chunk_data_almost_done: + assert(parser->flags & F_CHUNKED); + assert(parser->content_length == 0); + STRICT_CHECK(ch != CR); + UPDATE_STATE(s_chunk_data_done); + CALLBACK_DATA(body); + break; + + case s_chunk_data_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + parser->nread = 0; + nread = 0; + UPDATE_STATE(s_chunk_size_start); + CALLBACK_NOTIFY(chunk_complete); + break; + + default: + assert(0 && "unhandled state"); + SET_ERRNO(HPE_INVALID_INTERNAL_STATE); + goto error; } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - UPDATE_STATE(s_chunk_data_done); - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - nread = 0; - UPDATE_STATE(s_chunk_size_start); - CALLBACK_NOTIFY(chunk_complete); - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } } /* Run callbacks for any marks that we have leftover after we ran out of @@ -2728,21 +2740,21 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; RETURN(len); - error: +error: if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); + SET_ERRNO(HPE_UNKNOWN); } RETURN(p - data); - } +} - /* Does the parser need to see an EOF to find the end of the message? */ - static int http_message_needs_eof(const http_parser *parser) - { +/* Does the parser need to see an EOF to find the end of the message? */ +static int http_message_needs_eof(const http_parser *parser) +{ if (parser->type == HTTP_REQUEST) { - return 0; + return 0; } /* See RFC 2616 section 4.4 */ @@ -2751,190 +2763,190 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; parser->status_code == 304 || /* Not Modified */ parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; + return 0; } if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; + return 0; } return 1; - } +} - static int http_should_keep_alive(const http_parser *parser) - { +static int http_should_keep_alive(const http_parser *parser) +{ if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) - { - return 0; - } + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) + { + return 0; + } } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) - { - return 0; - } + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) + { + return 0; + } } return !http_message_needs_eof(parser); - } +} - static const char * - http_method_str(enum http_method m) - { +static const char * +http_method_str(enum http_method m) +{ return ELEM_AT(method_strings, m, ""); - } +} - static const char * - http_status_str(enum http_status s) - { +static const char * +http_status_str(enum http_status s) +{ switch (s) { #define XX(num, name, string) \ - case HTTP_STATUS_##name: \ - return #string; - HTTP_STATUS_MAP(XX) + case HTTP_STATUS_##name: \ + return #string; + HTTP_STATUS_MAP(XX) #undef XX - default: - return ""; + default: + return ""; } - } +} - static void - http_parser_init(http_parser *parser, enum http_parser_type t) - { +static void +http_parser_init(http_parser *parser, enum http_parser_type t) +{ void *data = parser->data; /* preserve application data */ memset(parser, 0, sizeof(*parser)); parser->data = data; parser->type = t; parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); parser->http_errno = HPE_OK; - } +} - static void - http_parser_settings_init(http_parser_settings *settings) - { +static void +http_parser_settings_init(http_parser_settings *settings) +{ memset(settings, 0, sizeof(*settings)); - } +} - static const char * - http_errno_name(enum http_errno err) - { - assert(((size_t)err) < ARRAY_SIZE(http_strerror_tab)); +static const char * +http_errno_name(enum http_errno err) +{ + assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); return http_strerror_tab[err].name; - } +} - static const char * - http_errno_description(enum http_errno err) - { - assert(((size_t)err) < ARRAY_SIZE(http_strerror_tab)); +static const char * +http_errno_description(enum http_errno err) +{ + assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); return http_strerror_tab[err].description; - } +} - static enum http_host_state - http_parse_host_char(enum http_host_state s, const char ch) - { +static enum http_host_state +http_parse_host_char(enum http_host_state s, const char ch) +{ switch (s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') - { - return s_http_host_start; - } + case s_http_userinfo: + case s_http_userinfo_start: + if (ch == '@') + { + return s_http_host_start; + } - if (IS_USERINFO_CHAR(ch)) - { - return s_http_userinfo; - } - break; + if (IS_USERINFO_CHAR(ch)) + { + return s_http_userinfo; + } + break; - case s_http_host_start: - if (ch == '[') - { - return s_http_host_v6_start; - } + case s_http_host_start: + if (ch == '[') + { + return s_http_host_v6_start; + } - if (IS_HOST_CHAR(ch)) - { - return s_http_host; - } + if (IS_HOST_CHAR(ch)) + { + return s_http_host; + } - break; + break; - case s_http_host: - if (IS_HOST_CHAR(ch)) - { - return s_http_host; - } + case s_http_host: + if (IS_HOST_CHAR(ch)) + { + return s_http_host; + } - /* fall through */ - case s_http_host_v6_end: - if (ch == ':') - { - return s_http_host_port_start; - } + /* fall through */ + case s_http_host_v6_end: + if (ch == ':') + { + return s_http_host_port_start; + } - break; + break; - case s_http_host_v6: - if (ch == ']') - { - return s_http_host_v6_end; - } + case s_http_host_v6: + if (ch == ']') + { + return s_http_host_v6_end; + } - /* fall through */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':' || ch == '.') - { - return s_http_host_v6; - } + /* fall through */ + case s_http_host_v6_start: + if (IS_HEX(ch) || ch == ':' || ch == '.') + { + return s_http_host_v6; + } - if (s == s_http_host_v6 && ch == '%') - { - return s_http_host_v6_zone_start; - } - break; + if (s == s_http_host_v6 && ch == '%') + { + return s_http_host_v6_zone_start; + } + break; - case s_http_host_v6_zone: - if (ch == ']') - { - return s_http_host_v6_end; - } + case s_http_host_v6_zone: + if (ch == ']') + { + return s_http_host_v6_end; + } - /* fall through */ - case s_http_host_v6_zone_start: - /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ - if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || - ch == '~') - { - return s_http_host_v6_zone; - } - break; + /* fall through */ + case s_http_host_v6_zone_start: + /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ + if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || + ch == '~') + { + return s_http_host_v6_zone; + } + break; - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) - { - return s_http_host_port; - } + case s_http_host_port: + case s_http_host_port_start: + if (IS_NUM(ch)) + { + return s_http_host_port; + } - break; + break; - default: - break; + default: + break; } return s_http_host_dead; - } +} - static int - http_parse_host(const char *buf, struct http_parser_url *u, int found_at) - { +static int +http_parse_host(const char *buf, struct http_parser_url *u, int found_at) +{ enum http_host_state s; const char *p; @@ -2948,90 +2960,90 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); + enum http_host_state new_s = http_parse_host_char(s, *p); - if (new_s == s_http_host_dead) - { - return 1; - } - - switch (new_s) - { - case s_http_host: - if (s != s_http_host) + if (new_s == s_http_host_dead) { - u->field_data[UF_HOST].off = (uint16_t)(p - buf); + return 1; } - u->field_data[UF_HOST].len++; - break; - case s_http_host_v6: - if (s != s_http_host_v6) + switch (new_s) { - u->field_data[UF_HOST].off = (uint16_t)(p - buf); + case s_http_host: + if (s != s_http_host) + { + u->field_data[UF_HOST].off = (uint16_t)(p - buf); + } + u->field_data[UF_HOST].len++; + break; + + case s_http_host_v6: + if (s != s_http_host_v6) + { + u->field_data[UF_HOST].off = (uint16_t)(p - buf); + } + u->field_data[UF_HOST].len++; + break; + + case s_http_host_v6_zone_start: + case s_http_host_v6_zone: + u->field_data[UF_HOST].len++; + break; + + case s_http_host_port: + if (s != s_http_host_port) + { + u->field_data[UF_PORT].off = (uint16_t)(p - buf); + u->field_data[UF_PORT].len = 0; + u->field_set |= (1 << UF_PORT); + } + u->field_data[UF_PORT].len++; + break; + + case s_http_userinfo: + if (s != s_http_userinfo) + { + u->field_data[UF_USERINFO].off = (uint16_t)(p - buf); + u->field_data[UF_USERINFO].len = 0; + u->field_set |= (1 << UF_USERINFO); + } + u->field_data[UF_USERINFO].len++; + break; + + default: + break; } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) - { - u->field_data[UF_PORT].off = (uint16_t)(p - buf); - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) - { - u->field_data[UF_USERINFO].off = (uint16_t)(p - buf); - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; + s = new_s; } /* Make sure we don't end somewhere unexpected */ switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - case s_http_host_port_start: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; + case s_http_host_start: + case s_http_host_v6_start: + case s_http_host_v6: + case s_http_host_v6_zone_start: + case s_http_host_v6_zone: + case s_http_host_port_start: + case s_http_userinfo: + case s_http_userinfo_start: + return 1; + default: + break; } return 0; - } +} - static void - http_parser_url_init(struct http_parser_url *u) - { +static void +http_parser_url_init(struct http_parser_url *u) +{ memset(u, 0, sizeof(*u)); - } +} - static int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) - { +static int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, + struct http_parser_url *u) +{ enum state s; const char *p; enum http_parser_url_fields uf, old_uf; @@ -3039,7 +3051,7 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; if (buflen == 0) { - return 1; + return 1; } u->port = u->field_set = 0; @@ -3048,63 +3060,63 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); + s = parse_url_char(s, *p); - /* Figure out the next field that we're operating on */ - switch (s) - { - case s_dead: - return 1; + /* Figure out the next field that we're operating on */ + switch (s) + { + case s_dead: + return 1; - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; + /* Skip delimeters */ + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + case s_req_query_string_start: + case s_req_fragment_start: + continue; - case s_req_schema: - uf = UF_SCHEMA; - break; + case s_req_schema: + uf = UF_SCHEMA; + break; - case s_req_server_with_at: - found_at = 1; + case s_req_server_with_at: + found_at = 1; - /* fall through */ - case s_req_server: - uf = UF_HOST; - break; + /* fall through */ + case s_req_server: + uf = UF_HOST; + break; - case s_req_path: - uf = UF_PATH; - break; + case s_req_path: + uf = UF_PATH; + break; - case s_req_query_string: - uf = UF_QUERY; - break; + case s_req_query_string: + uf = UF_QUERY; + break; - case s_req_fragment: - uf = UF_FRAGMENT; - break; + case s_req_fragment: + uf = UF_FRAGMENT; + break; - default: - assert(!"Unexpected state"); - return 1; - } + default: + assert(!"Unexpected state"); + return 1; + } - /* Nothing's changed; soldier on */ - if (uf == old_uf) - { - u->field_data[uf].len++; - continue; - } + /* Nothing's changed; soldier on */ + if (uf == old_uf) + { + u->field_data[uf].len++; + continue; + } - u->field_data[uf].off = (uint16_t)(p - buf); - u->field_data[uf].len = 1; + u->field_data[uf].off = (uint16_t)(p - buf); + u->field_data[uf].len = 1; - u->field_set |= (1 << uf); - old_uf = uf; + u->field_set |= (1 << uf); + old_uf = uf; } /* host must be present if there is a schema */ @@ -3112,59 +3124,59 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; if ((u->field_set & (1 << UF_SCHEMA)) && (u->field_set & (1 << UF_HOST)) == 0) { - return 1; + return 1; } if (u->field_set & (1 << UF_HOST)) { - if (http_parse_host(buf, u, found_at) != 0) - { - return 1; - } + if (http_parse_host(buf, u, found_at) != 0) + { + return 1; + } } /* CONNECT requests can only contain "hostname:port" */ if (is_connect && u->field_set != ((1 << UF_HOST) | (1 << UF_PORT))) { - return 1; + return 1; } if (u->field_set & (1 << UF_PORT)) { - uint16_t off; - uint16_t len; - const char *p; - const char *end; - unsigned long v; + uint16_t off; + uint16_t len; + const char *p; + const char *end; + unsigned long v; - off = u->field_data[UF_PORT].off; - len = u->field_data[UF_PORT].len; - end = buf + off + len; + off = u->field_data[UF_PORT].off; + len = u->field_data[UF_PORT].len; + end = buf + off + len; - /* NOTE: The characters are already validated and are in the [0-9] range */ - assert(off + len <= buflen && "Port number overflow"); - v = 0; - for (p = buf + off; p < end; p++) - { - v *= 10; - v += *p - '0'; - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) + /* NOTE: The characters are already validated and are in the [0-9] range */ + assert(off + len <= buflen && "Port number overflow"); + v = 0; + for (p = buf + off; p < end; p++) { - return 1; - } - } + v *= 10; + v += *p - '0'; - u->port = (uint16_t)v; + /* Ports have a max value of 2^16 */ + if (v > 0xffff) + { + return 1; + } + } + + u->port = (uint16_t) v; } return 0; - } +} - static void - http_parser_pause(http_parser *parser, int paused) - { +static void +http_parser_pause(http_parser *parser, int paused) +{ /* Users should only be pausing/unpausing a parser that is not in an error * state. In non-debug builds, there's not much that we can do about this * other than ignore it. @@ -3172,33 +3184,33 @@ static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; if (HTTP_PARSER_ERRNO(parser) == HPE_OK || HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */ - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); + uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */ + SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); } else { - assert(0 && "Attempting to pause parser in error state"); + assert(0 && "Attempting to pause parser in error state"); } - } +} - static int http_body_is_final(const struct http_parser *parser) - { +static int http_body_is_final(const struct http_parser *parser) +{ return parser->state == s_message_done; - } +} - static unsigned long - http_parser_version(void) - { +static unsigned long +http_parser_version(void) +{ return HTTP_PARSER_VERSION_MAJOR * 0x10000 | HTTP_PARSER_VERSION_MINOR * 0x00100 | HTTP_PARSER_VERSION_PATCH * 0x00001; - } +} - static void - http_parser_set_max_header_size(uint32_t size) - { +static void +http_parser_set_max_header_size(uint32_t size) +{ max_header_size = size; - } +} #ifdef __cplusplus } diff --git a/libs/brynet/net/port/Win.hpp b/libs/brynet/net/port/Win.hpp index 07e0bd7..a48845f 100644 --- a/libs/brynet/net/port/Win.hpp +++ b/libs/brynet/net/port/Win.hpp @@ -5,27 +5,27 @@ namespace brynet { namespace net { namespace port { #ifdef BRYNET_PLATFORM_WINDOWS - class Win +class Win +{ +public: + enum class OverlappedType { - public: - enum class OverlappedType - { - OverlappedNone = 0, - OverlappedRecv, - OverlappedSend, - }; - - struct OverlappedExt - { - OVERLAPPED base; - const OverlappedType OP; - - OverlappedExt(OverlappedType op) BRYNET_NOEXCEPT : OP(op) - { - memset(&base, 0, sizeof(base)); - } - }; + OverlappedNone = 0, + OverlappedRecv, + OverlappedSend, }; + + struct OverlappedExt + { + OVERLAPPED base; + const OverlappedType OP; + + OverlappedExt(OverlappedType op) BRYNET_NOEXCEPT : OP(op) + { + memset(&base, 0, sizeof(base)); + } + }; +}; #endif -} } } \ No newline at end of file +}}}// namespace brynet::net::port diff --git a/libs/brynet/net/wrapper/ConnectionBuilder.hpp b/libs/brynet/net/wrapper/ConnectionBuilder.hpp index 7cdc8ee..4989fbd 100644 --- a/libs/brynet/net/wrapper/ConnectionBuilder.hpp +++ b/libs/brynet/net/wrapper/ConnectionBuilder.hpp @@ -1,191 +1,210 @@ #pragma once -#include -#include #include #include +#include +#include +#include namespace brynet { namespace net { namespace wrapper { - template - class BaseSocketConnectBuilder +using CompletedCallback = detail::AsyncConnectAddr::CompletedCallback; +using ProcessTcpSocketCallback = detail::AsyncConnectAddr::ProcessTcpSocketCallback; +using FailedCallback = detail::AsyncConnectAddr::FailedCallback; + +template +class BaseSocketConnectBuilder +{ +public: + virtual ~BaseSocketConnectBuilder() = default; + + Derived& WithConnector(AsyncConnector::Ptr connector) { - protected: - using AddSocketOptionFunc = detail::AddSocketOptionFunc; - using ConnectOptionFunc = detail::ConnectOptionFunc; + mConnector = std::move(connector); + return static_cast(*this); + } - public: - virtual ~BaseSocketConnectBuilder() = default; - - Derived& configureConnector(AsyncConnector::Ptr connector) - { - mConnector = std::move(connector); - return static_cast(*this); - } - - Derived& configureConnectOptions( - std::vector options) - { - mConnectOptions = std::move(options); - return static_cast(*this); - } - - void asyncConnect() const - { - asyncConnect(mConnectOptions); - } - - TcpSocket::Ptr syncConnect() const - { - return syncConnect(mConnectOptions); - } - - protected: - void asyncConnect(std::vector connectOptions) const - { - if (mConnector == nullptr) - { - throw BrynetCommonException("connector is nullptr"); - } - if (connectOptions.empty()) - { - throw BrynetCommonException("options is empty"); - } - - mConnector->asyncConnect(connectOptions); - } - - TcpSocket::Ptr syncConnect(std::vector connectOptions) const - { - auto timeout = ConnectOption::ExtractTimeout(connectOptions); - - auto socketPromise = std::make_shared>(); - connectOptions.push_back(ConnectOption::WithCompletedCallback( - [socketPromise](TcpSocket::Ptr socket) { - socketPromise->set_value(std::move(socket)); - })); - connectOptions.push_back(ConnectOption::WithFailedCallback([socketPromise]() { - socketPromise->set_value(nullptr); - })); - - asyncConnect(connectOptions); - - auto future = socketPromise->get_future(); - if (future.wait_for(timeout) != std::future_status::ready) - { - return nullptr; - } - - return future.get(); - } - - std::vector getConnectOptions() const - { - return mConnectOptions; - } - - private: - AsyncConnector::Ptr mConnector; - std::vector mConnectOptions; - }; - - class SocketConnectBuilder : public BaseSocketConnectBuilder + Derived& WithAddr(std::string ip, size_t port) { - }; + mConnectOption.ip = std::move(ip); + mConnectOption.port = port; + return static_cast(*this); + } - template - class BaseConnectionBuilder : public BaseSocketConnectBuilder + Derived& WithTimeout(std::chrono::nanoseconds timeout) { - protected: - using AddSocketOptionFunc = detail::AddSocketOptionFunc; - using ConnectOptionFunc = detail::ConnectOptionFunc; + mConnectOption.timeout = timeout; + return static_cast(*this); + } - public: - Derived& configureService(TcpService::Ptr service) - { - mTcpService = std::move(service); - return static_cast(*this); - } - - Derived& configureConnectionOptions(std::vector options) - { - mConnectionOptions = std::move(options); - return static_cast(*this); - } - - void asyncConnect() const - { - asyncConnect(BaseSocketConnectBuilder::getConnectOptions(), - mConnectionOptions); - } - - TcpConnection::Ptr syncConnect() const - { - return syncConnect(BaseSocketConnectBuilder::getConnectOptions(), - mConnectionOptions); - } - - protected: - void asyncConnect(std::vector connectOptions, - std::vector connectionOptions) const - { - if (mTcpService == nullptr) - { - throw BrynetCommonException("tcp serviceis nullptr"); - } - if (connectionOptions.empty()) - { - throw BrynetCommonException("options is empty"); - } - - auto service = mTcpService; - auto enterCallback = [service, connectionOptions](TcpSocket::Ptr socket) mutable { - service->addTcpConnection(std::move(socket), connectionOptions); - }; - connectOptions.push_back(ConnectOption::WithCompletedCallback(enterCallback)); - - BaseSocketConnectBuilder::asyncConnect(connectOptions); - } - - TcpConnection::Ptr syncConnect(std::vector connectOptions, - std::vector connectionOptions) const - { - auto timeout = ConnectOption::ExtractTimeout(connectOptions); - auto sessionPromise = std::make_shared>(); - - connectOptions.push_back(ConnectOption::WithFailedCallback( - [sessionPromise]() { - sessionPromise->set_value(nullptr); - })); - - connectionOptions.push_back(AddSocketOption::AddEnterCallback( - [sessionPromise](const TcpConnection::Ptr& session) { - sessionPromise->set_value(session); - })); - - asyncConnect(connectOptions, connectionOptions); - - auto future = sessionPromise->get_future(); - if (future.wait_for(timeout) != std::future_status::ready) - { - return nullptr; - } - - return future.get(); - } - - std::vector getConnectionOptions() const - { - return mConnectionOptions; - } - - private: - TcpService::Ptr mTcpService; - std::vector mConnectionOptions; - }; - - class ConnectionBuilder : public BaseConnectionBuilder + Derived& AddSocketProcessCallback(const ProcessTcpSocketCallback& callback) { - }; + mConnectOption.processCallbacks.push_back(callback); + return static_cast(*this); + } -} } } \ No newline at end of file + Derived& WithCompletedCallback(CompletedCallback callback) + { + mConnectOption.completedCallback = std::move(callback); + return static_cast(*this); + } + + Derived& WithFailedCallback(FailedCallback callback) + { + mConnectOption.failedCallback = std::move(callback); + return static_cast(*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>(); + 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 +{ +}; + +template +class BaseConnectionBuilder +{ +public: + Derived& WithService(TcpService::Ptr service) + { + mTcpService = std::move(service); + return static_cast(*this); + } + + Derived& WithConnector(AsyncConnector::Ptr connector) + { + mConnectBuilder.WithConnector(std::move(connector)); + return static_cast(*this); + } + + Derived& WithAddr(std::string ip, size_t port) + { + mConnectBuilder.WithAddr(std::move(ip), port); + return static_cast(*this); + } + + Derived& WithTimeout(std::chrono::nanoseconds timeout) + { + mConnectBuilder.WithTimeout(timeout); + return static_cast(*this); + } + + Derived& AddSocketProcessCallback(const ProcessTcpSocketCallback& callback) + { + mConnectBuilder.AddSocketProcessCallback(callback); + return static_cast(*this); + } + + Derived& WithFailedCallback(FailedCallback callback) + { + mConnectBuilder.WithFailedCallback(std::move(callback)); + return static_cast(*this); + } + + Derived& WithMaxRecvBufferSize(size_t size) + { + mOption.maxRecvBufferSize = size; + return static_cast(*this); + } + +#ifdef BRYNET_USE_OPENSSL + Derived& WithSSL() + { + mOption.useSSL = true; + return static_cast(*this); + } +#endif + Derived& WithForceSameThreadLoop() + { + mOption.forceSameThreadLoop = true; + return static_cast(*this); + } + + Derived& AddEnterCallback(const TcpConnection::EnterCallback& callback) + { + mOption.enterCallback.push_back(callback); + return static_cast(*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>(); + + 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 +{ +}; + +}}}// namespace brynet::net::wrapper diff --git a/libs/brynet/net/wrapper/HttpConnectionBuilder.hpp b/libs/brynet/net/wrapper/HttpConnectionBuilder.hpp index 7f4467d..2b48e21 100644 --- a/libs/brynet/net/wrapper/HttpConnectionBuilder.hpp +++ b/libs/brynet/net/wrapper/HttpConnectionBuilder.hpp @@ -2,43 +2,92 @@ #include #include +#include namespace brynet { namespace net { namespace wrapper { - class HttpConnectionBuilder : public BaseConnectionBuilder +class HttpConnectionBuilder +{ +public: + HttpConnectionBuilder& WithService(TcpService::Ptr service) { - public: - HttpConnectionBuilder& configureEnterCallback( - http::HttpSession::EnterCallback&& callback) + mBuilder.WithService(std::move(service)); + return *this; + } + + HttpConnectionBuilder& WithConnector(AsyncConnector::Ptr connector) + { + mBuilder.WithConnector(std::move(connector)); + return *this; + } + + HttpConnectionBuilder& WithAddr(std::string ip, size_t port) + { + mBuilder.WithAddr(std::move(ip), port); + return *this; + } + + HttpConnectionBuilder& WithTimeout(std::chrono::nanoseconds timeout) + { + mBuilder.WithTimeout(timeout); + return *this; + } + + HttpConnectionBuilder& AddSocketProcessCallback(const ProcessTcpSocketCallback& callback) + { + mBuilder.AddSocketProcessCallback(callback); + return *this; + } + + HttpConnectionBuilder& WithEnterCallback(http::HttpSession::EnterCallback&& callback) + { + mHttpEnterCallback = std::move(callback); + return *this; + } + + HttpConnectionBuilder& WithFailedCallback(FailedCallback callback) + { + mBuilder.WithFailedCallback(std::move(callback)); + return *this; + } + + HttpConnectionBuilder& WithMaxRecvBufferSize(size_t size) + { + mBuilder.WithMaxRecvBufferSize(size); + return *this; + } + +#ifdef BRYNET_USE_OPENSSL + HttpConnectionBuilder& WithSSL() + { + mBuilder.WithSSL(); + return *this; + } +#endif + HttpConnectionBuilder& WithForceSameThreadLoop() + { + mBuilder.WithForceSameThreadLoop(); + return *this; + } + + void asyncConnect() + { + if (mHttpEnterCallback == nullptr) { - mHttpEnterCallback = std::move(callback); - return *this; + throw BrynetCommonException("not setting http enter callback"); } - void asyncConnect() const - { - if (mHttpEnterCallback == nullptr) - { - throw BrynetCommonException("not setting http enter callback"); - } + auto callback = mHttpEnterCallback; + auto builder = mBuilder; + builder.AddEnterCallback([callback](const TcpConnection::Ptr& session) { + http::HttpService::setup(session, callback); + }); + builder.asyncConnect(); + } - auto connectionOptions = - BaseConnectionBuilder::getConnectionOptions(); - auto callback = mHttpEnterCallback; +private: + http::HttpSession::EnterCallback mHttpEnterCallback; + ConnectionBuilder mBuilder; +}; - connectionOptions.push_back( - AddSocketOption::AddEnterCallback( - [callback](const TcpConnection::Ptr& session) { - http::HttpService::setup(session, callback); - })); - - BaseConnectionBuilder::asyncConnect( - BaseConnectionBuilder::getConnectOptions(), - connectionOptions); - } - - private: - http::HttpSession::EnterCallback mHttpEnterCallback; - }; - -} } } \ No newline at end of file +}}}// namespace brynet::net::wrapper diff --git a/libs/brynet/net/wrapper/HttpServiceBuilder.hpp b/libs/brynet/net/wrapper/HttpServiceBuilder.hpp index 692d412..1c6abd1 100644 --- a/libs/brynet/net/wrapper/HttpServiceBuilder.hpp +++ b/libs/brynet/net/wrapper/HttpServiceBuilder.hpp @@ -2,38 +2,78 @@ #include #include +#include namespace brynet { namespace net { namespace wrapper { - class HttpListenerBuilder : public BaseListenerBuilder +class HttpListenerBuilder +{ +public: + HttpListenerBuilder& WithService(TcpService::Ptr service) { - public: - HttpListenerBuilder& configureEnterCallback(http::HttpSession::EnterCallback&& callback) + mBuilder.WithService(std::move(service)); + return *this; + } + + HttpListenerBuilder& WithEnterCallback(http::HttpSession::EnterCallback&& callback) + { + mHttpEnterCallback = std::move(callback); + return *this; + } + + HttpListenerBuilder& AddSocketProcess(const ListenThread::TcpSocketProcessCallback& callback) + { + mBuilder.AddSocketProcess(callback); + return *this; + } + + HttpListenerBuilder& WithMaxRecvBufferSize(size_t size) + { + mBuilder.WithMaxRecvBufferSize(size); + return *this; + } +#ifdef BRYNET_USE_OPENSSL + HttpListenerBuilder& WithSSL(SSLHelper::Ptr sslHelper) + { + mBuilder.WithSSL(std::move(sslHelper)); + return *this; + } +#endif + HttpListenerBuilder& WithForceSameThreadLoop() + { + mBuilder.WithForceSameThreadLoop(); + return *this; + } + + HttpListenerBuilder& WithAddr(bool ipV6, std::string ip, size_t port) + { + mBuilder.WithAddr(ipV6, std::move(ip), port); + return *this; + } + + HttpListenerBuilder& WithReusePort() + { + mBuilder.WithReusePort(); + return *this; + } + + void asyncRun() + { + if (mHttpEnterCallback == nullptr) { - mHttpEnterCallback = std::move(callback); - return *this; + throw BrynetCommonException("not setting http enter callback"); } - void asyncRun() - { - if (mHttpEnterCallback == nullptr) - { - throw BrynetCommonException("not setting http enter callback"); - } + auto callback = mHttpEnterCallback; + mBuilder.AddEnterCallback([callback](const TcpConnection::Ptr& session) { + http::HttpService::setup(session, callback); + }); + mBuilder.asyncRun(); + } - auto connectionOptions = - BaseListenerBuilder::getConnectionOptions(); - auto callback = mHttpEnterCallback; - connectionOptions.push_back( - AddSocketOption::AddEnterCallback( - [callback](const TcpConnection::Ptr& session) { - http::HttpService::setup(session, callback); - })); - BaseListenerBuilder::asyncRun(connectionOptions); - } +private: + http::HttpSession::EnterCallback mHttpEnterCallback; + ListenerBuilder mBuilder; +}; - private: - http::HttpSession::EnterCallback mHttpEnterCallback; - }; - -} } } \ No newline at end of file +}}}// namespace brynet::net::wrapper diff --git a/libs/brynet/net/wrapper/ServiceBuilder.hpp b/libs/brynet/net/wrapper/ServiceBuilder.hpp index ce340ee..0694b80 100644 --- a/libs/brynet/net/wrapper/ServiceBuilder.hpp +++ b/libs/brynet/net/wrapper/ServiceBuilder.hpp @@ -1,167 +1,116 @@ #pragma once -#include -#include #include +#include +#include +#include +#include namespace brynet { namespace net { namespace wrapper { - class ListenConfig final +template +class BaseListenerBuilder +{ +public: + virtual ~BaseListenerBuilder() = default; + + Derived& WithService(TcpService::Ptr service) { - public: - ListenConfig() - { - mSetting = false; - mIsIpV6 = false; - mPort = 0; - } + mTcpService = std::move(service); + return static_cast(*this); + } - void setAddr(bool ipV6, std::string ip, int port) - { - mIsIpV6 = ipV6; - mListenAddr = ip; - mPort = port; - mSetting = true; - } - - std::string ip() const - { - return mListenAddr; - } - - int port() const - { - return mPort; - } - - bool useIpV6() const - { - return mIsIpV6; - } - - bool hasSetting() const - { - return mSetting; - } - - private: - std::string mListenAddr; - int mPort; - bool mIsIpV6; - bool mSetting; - }; - - class BuildListenConfig + Derived& WithAddr(bool ipV6, std::string ip, size_t port) { - public: - explicit BuildListenConfig(ListenConfig* config) - : - mConfig(config) - { - } + mIsIpV6 = ipV6; + mListenAddr = std::move(ip); + mPort = port; + return static_cast(*this); + } - void setAddr(bool ipV6, std::string ip, int port) - { - mConfig->setAddr(ipV6, ip, port); - } - - private: - ListenConfig* mConfig; - }; - - template - class BaseListenerBuilder + Derived& WithReusePort() { - protected: - using AddSocketOptionFunc = detail::AddSocketOptionFunc; - using ConnectOptionFunc = detail::ConnectOptionFunc; + mEnabledReusePort = true; + return static_cast(*this); + } - public: - virtual ~BaseListenerBuilder() = default; + Derived& AddSocketProcess(const ListenThread::TcpSocketProcessCallback& callback) + { + mSocketProcessCallbacks.push_back(callback); + return static_cast(*this); + } - Derived& configureService(TcpService::Ptr service) + Derived& WithMaxRecvBufferSize(size_t size) + { + mSocketOption.maxRecvBufferSize = size; + return static_cast(*this); + } +#ifdef BRYNET_USE_OPENSSL + Derived& WithSSL(SSLHelper::Ptr sslHelper) + { + mSocketOption.sslHelper = std::move(sslHelper); + mSocketOption.useSSL = true; + return static_cast(*this); + } +#endif + Derived& WithForceSameThreadLoop() + { + mSocketOption.forceSameThreadLoop = true; + return static_cast(*this); + } + + Derived& AddEnterCallback(const TcpConnection::EnterCallback& callback) + { + mSocketOption.enterCallback.push_back(callback); + return static_cast(*this); + } + + void asyncRun() + { + if (mTcpService == nullptr) { - mTcpService = std::move(service); - return static_cast(*this); + throw BrynetCommonException("tcp service is nullptr"); + } + if (mListenAddr.empty()) + { + throw BrynetCommonException("not config listen addr"); } - Derived& configureSocketOptions(std::vector options) - { - mSocketOptions = std::move(options); - return static_cast(*this); - } - - Derived& configureConnectionOptions(std::vector options) - { - mConnectionOptions = std::move(options); - return static_cast(*this); - } - - template - Derived& configureListen(const BuilderFunc& builder) - { - BuildListenConfig buildConfig(&mListenConfig); - builder(buildConfig); - return static_cast(*this); - } - - void asyncRun() - { - asyncRun(getConnectionOptions()); - } - - void stop() - { - if (mListenThread) - { - mListenThread->stopListen(); - } - } - - std::vector getConnectionOptions() const - { - return mConnectionOptions; - } - - protected: - void asyncRun(std::vector connectionOptions) - { - if (mTcpService == nullptr) - { - throw BrynetCommonException("tcp service is nullptr"); - } - if (connectionOptions.empty()) - { - throw BrynetCommonException("options is empty"); - } - if (!mListenConfig.hasSetting()) - { - throw BrynetCommonException("not config listen addr"); - } - - auto service = mTcpService; - mListenThread = ListenThread::Create(mListenConfig.useIpV6(), - mListenConfig.ip(), - mListenConfig.port(), - [service, connectionOptions](brynet::net::TcpSocket::Ptr socket) { - service->addTcpConnection(std::move(socket), connectionOptions); + auto service = mTcpService; + auto option = mSocketOption; + mListenThread = ListenThread::Create( + mIsIpV6, + mListenAddr, + mPort, + [service, option](brynet::net::TcpSocket::Ptr socket) { + service->addTcpConnection(std::move(socket), option); }, - mSocketOptions); - mListenThread->startListen(); - } + mSocketProcessCallbacks, + mEnabledReusePort); + mListenThread->startListen(); + } - private: - TcpService::Ptr mTcpService; - std::vector mSocketOptions; - ListenConfig mListenConfig; - ListenThread::Ptr mListenThread; - - private: - std::vector mConnectionOptions; - }; - - class ListenerBuilder : public BaseListenerBuilder + void stop() { - }; + if (mListenThread) + { + mListenThread->stopListen(); + } + } -} } } \ No newline at end of file +private: + TcpService::Ptr mTcpService; + std::vector mSocketProcessCallbacks; + ConnectionOption mSocketOption; + std::string mListenAddr; + int mPort = 0; + bool mIsIpV6 = false; + bool mEnabledReusePort = false; + ListenThread::Ptr mListenThread; +}; + +class ListenerBuilder : public BaseListenerBuilder +{ +}; + +}}}// namespace brynet::net::wrapper