mirror of https://github.com/axmolengine/axmol.git
Update yasio to latest
This commit is contained in:
parent
2547e8d3f8
commit
5bd36bfa7c
|
@ -40,7 +40,7 @@ THE SOFTWARE.
|
|||
# include "audio/AudioDecoderEXT.h"
|
||||
#endif
|
||||
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
|
||||
NS_AX_BEGIN
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ THE SOFTWARE.
|
|||
|
||||
#include <unordered_map>
|
||||
#include "mio/mio.hpp"
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
|
||||
/**
|
||||
* @addtogroup base
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
|
||||
// minizip 1.2.0 is same with other platforms
|
||||
#define unzGoToFirstFile64(A, B, C, D) unzGoToFirstFile2(A, B, C, D, NULL, 0, NULL, 0)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Copyright (c) 2010-2013 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2022-2023 Bytedance Inc.
|
||||
|
||||
https://axmolengine.github.io/
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ THE SOFTWARE.
|
|||
#include <WinVer.h>
|
||||
#include <timeapi.h>
|
||||
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
#include "ntcvt/ntcvt.hpp"
|
||||
/**
|
||||
@brief This function change the PVRFrame show/hide setting in register.
|
||||
|
|
|
@ -31,7 +31,7 @@ THE SOFTWARE.
|
|||
#include "scripting/lua-bindings/manual/CCLuaStack.h"
|
||||
#include "scripting/lua-bindings/manual/CCLuaEngine.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
|
||||
USING_NS_AX;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "renderer/backend/VertexLayout.h"
|
||||
#include "ui/GUIDefine.h"
|
||||
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
#include <thread>
|
||||
|
||||
USING_NS_AX;
|
||||
|
|
|
@ -29,7 +29,7 @@ SOFTWARE.
|
|||
#include "yasio/bindings/lyasio.hpp"
|
||||
#include "yasio/detail/object_pool.hpp"
|
||||
#include "yasio/detail/ref_ptr.hpp"
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
|
||||
// A workaround to fix compile issue caused by `CCPlatformMacros.h` doesn't handle `__has_attribute` it properly
|
||||
# if !__has_attribute(format)
|
||||
|
|
|
@ -36,6 +36,10 @@ SOFTWARE.
|
|||
# include <sdkddkver.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// Tests whether compiler has(fully) c++11 support and keywords workaround for msvc
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1900
|
||||
# define YASIO__HAS_CXX11 1
|
||||
|
@ -50,8 +54,7 @@ SOFTWARE.
|
|||
#endif
|
||||
|
||||
// Tests whether compiler has c++14 support
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1900 && (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_MSC_VER) && _MSC_VER >= 1900 && (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
|
||||
# ifndef YASIO_HAS_CXX14
|
||||
# define YASIO__HAS_CXX14 1
|
||||
# endif // C++14 features macro
|
||||
|
@ -62,9 +65,7 @@ SOFTWARE.
|
|||
|
||||
// Tests whether compiler has c++17 support
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||
(defined(_MSC_VER) && _MSC_VER > 1900 && \
|
||||
((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || \
|
||||
(defined(_MSVC_LANG) && (_MSVC_LANG > 201402L))))
|
||||
(defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L))))
|
||||
# ifndef YASIO_HAS_CXX17
|
||||
# define YASIO__HAS_CXX17 1
|
||||
# endif // C++17 features macro
|
||||
|
@ -75,9 +76,7 @@ SOFTWARE.
|
|||
|
||||
// Tests whether compiler has c++20 support
|
||||
#if (defined(__cplusplus) && __cplusplus > 201703L) || \
|
||||
(defined(_MSC_VER) && _MSC_VER > 1900 && \
|
||||
((defined(_HAS_CXX20) && _HAS_CXX20 == 1) || \
|
||||
(defined(_MSVC_LANG) && (_MSVC_LANG > 201703L))))
|
||||
(defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX20) && _HAS_CXX20 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201703L))))
|
||||
# ifndef YASIO__HAS_CXX20
|
||||
# define YASIO__HAS_CXX20 1
|
||||
# endif // C++20 features macro
|
||||
|
@ -103,8 +102,7 @@ SOFTWARE.
|
|||
// Tests whether current OS is BSD-like system for process common BSD socket behaviors
|
||||
#if !defined(_WIN32) && !defined(__linux__)
|
||||
# include <sys/param.h>
|
||||
# if defined(BSD) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
|
||||
# if defined(BSD) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
|
||||
# define YASIO__OS_BSD_LIKE 1
|
||||
# else
|
||||
# define YASIO__OS_BSD_LIKE 0
|
||||
|
@ -128,8 +126,7 @@ SOFTWARE.
|
|||
#endif
|
||||
|
||||
// 64bits Sense Macros
|
||||
#if defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64) || \
|
||||
defined(__x86_64) || defined(__arm64__) || defined(__aarch64__)
|
||||
#if defined(_M_X64) || defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(__x86_64) || defined(__arm64__) || defined(__aarch64__)
|
||||
# define YASIO__64BITS 1
|
||||
#else
|
||||
# define YASIO__64BITS 0
|
||||
|
@ -149,8 +146,7 @@ SOFTWARE.
|
|||
#endif
|
||||
|
||||
#include <system_error>
|
||||
#define yasio__throw_error(ec, what) \
|
||||
YASIO__THROW0(std::system_error(std::error_code{(int)ec, std::system_category()}, what))
|
||||
#define yasio__throw_error(ec, what) YASIO__THROW0(std::system_error(std::error_code{(int)ec, std::system_category()}, what))
|
||||
#define yasio__throw_error0(ec) yasio__throw_error(ec, "")
|
||||
|
||||
// Compatibility with non-clang compilers...
|
||||
|
|
|
@ -206,13 +206,6 @@ SOFTWARE.
|
|||
// The default max listen count of tcp server.
|
||||
#define YASIO_SOMAXCONN 19
|
||||
|
||||
// The max wait duration in microseconds when io_service nothing to do.
|
||||
#define YASIO_MAX_WAIT_DURATION (5LL * 60LL * 1000LL * 1000LL)
|
||||
|
||||
// The min wait duration in microseconds when io_service have outstanding work to do.
|
||||
// !!!Only affects Single Core CPU
|
||||
#define YASIO_MIN_WAIT_DURATION 10LL
|
||||
|
||||
// The default ttl of multicast
|
||||
#define YASIO_DEFAULT_MULTICAST_TTL (int)128
|
||||
|
||||
|
@ -238,4 +231,7 @@ SOFTWARE.
|
|||
#define YASIO_SSL_PIN "yasio_ssl_client"
|
||||
#define YASIO_SSL_PIN_LEN (sizeof(YASIO_SSL_PIN) - 1)
|
||||
|
||||
#define YASIO_SSL_PON "yasio_ssl_server"
|
||||
#define YASIO_SSL_PON_LEN (sizeof(YASIO_SSL_PON) - 1)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// A multi-platform support c++11 library with focus on asynchronous socket I/O for any
|
||||
// client application.
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2023 HALX99
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef YASIO__MBEDTLS_INL
|
||||
#define YASIO__MBEDTLS_INL
|
||||
|
||||
#if YASIO_SSL_BACKEND == 2
|
||||
|
||||
YASIO__DECL ssl_ctx_st* yssl_ctx_new(const yssl_options& opts)
|
||||
{
|
||||
auto ctx = new ssl_ctx_st();
|
||||
::mbedtls_ctr_drbg_init(&ctx->ctr_drbg);
|
||||
::mbedtls_entropy_init(&ctx->entropy);
|
||||
::mbedtls_ssl_config_init(&ctx->conf);
|
||||
::mbedtls_x509_crt_init(&ctx->cert);
|
||||
::mbedtls_pk_init(&ctx->pkey);
|
||||
|
||||
do
|
||||
{
|
||||
int ret = 0;
|
||||
// ssl role
|
||||
if ((ret = ::mbedtls_ssl_config_defaults(&ctx->conf, opts.client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
|
||||
YASIO_LOG("mbedtls_ssl_config_defaults fail with ret=%d", ret);
|
||||
|
||||
// rgn engine
|
||||
cxx17::string_view pers = opts.client ? cxx17::string_view{YASIO_SSL_PIN, YASIO_SSL_PIN_LEN} : cxx17::string_view{YASIO_SSL_PON, YASIO_SSL_PON_LEN};
|
||||
ret = ::mbedtls_ctr_drbg_seed(&ctx->ctr_drbg, ::mbedtls_entropy_func, &ctx->entropy, (const unsigned char*)pers.data(), pers.length());
|
||||
if (ret != 0)
|
||||
{
|
||||
YASIO_LOG("mbedtls_ctr_drbg_seed fail with ret=%d", ret);
|
||||
break;
|
||||
}
|
||||
::mbedtls_ssl_conf_rng(&ctx->conf, ::mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
|
||||
|
||||
// --- load cert
|
||||
int authmode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
if (yasio__valid_str(opts.crtfile_)) // the cafile_ must be full path
|
||||
{
|
||||
if ((ret = ::mbedtls_x509_crt_parse_file(&ctx->cert, opts.crtfile_)) == 0)
|
||||
authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
else
|
||||
{
|
||||
YASIO_LOG("mbedtls_x509_crt_parse_file with ret=-0x%x", (unsigned int)-ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.client)
|
||||
{
|
||||
::mbedtls_ssl_conf_authmode(&ctx->conf, authmode);
|
||||
::mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->cert, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// --- load server private key
|
||||
if (yasio__valid_str(opts.keyfile_))
|
||||
{
|
||||
# if MBEDTLS_VERSION_MAJOR >= 3
|
||||
if (::mbedtls_pk_parse_keyfile(&ctx->pkey, opts.keyfile_, nullptr, mbedtls_ctr_drbg_random, &ctx->ctr_drbg) != 0)
|
||||
# else
|
||||
if (::mbedtls_pk_parse_keyfile(&ctx->pkey, opts.keyfile_, nullptr) != 0)
|
||||
# endif
|
||||
{
|
||||
YASIO_LOG("mbedtls_x509_crt_parse_file with ret=-0x%x", (unsigned int)-ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
::mbedtls_ssl_conf_ca_chain(&ctx->conf, ctx->cert.next, nullptr);
|
||||
if ((ret = mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->pkey)) != 0)
|
||||
{
|
||||
YASIO_LOG("mbedtls_ssl_conf_own_cert with ret=-0x%x", (unsigned int)-ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
YASIO__DECL void yssl_ctx_free(ssl_ctx_st*& ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
::mbedtls_pk_free(&ctx->pkey);
|
||||
::mbedtls_x509_crt_free(&ctx->cert);
|
||||
::mbedtls_ssl_config_free(&ctx->conf);
|
||||
::mbedtls_entropy_free(&ctx->entropy);
|
||||
::mbedtls_ctr_drbg_free(&ctx->ctr_drbg);
|
||||
|
||||
delete ctx;
|
||||
ctx = nullptr;
|
||||
}
|
||||
|
||||
YASIO__DECL ssl_st* yssl_new(ssl_ctx_st* ctx, int fd, const char* hostname, bool client)
|
||||
{
|
||||
auto ssl = new ssl_st();
|
||||
::mbedtls_ssl_init(ssl);
|
||||
::mbedtls_ssl_setup(ssl, &ctx->conf);
|
||||
|
||||
// ssl_set_fd
|
||||
ssl->bio.fd = fd;
|
||||
::mbedtls_ssl_set_bio(ssl, &ssl->bio, ::mbedtls_net_send, ::mbedtls_net_recv, nullptr /* rev_timeout() */);
|
||||
::mbedtls_ssl_set_hostname(ssl, hostname);
|
||||
return ssl;
|
||||
}
|
||||
YASIO__DECL void yssl_shutdown(ssl_st*& ssl)
|
||||
{
|
||||
::mbedtls_ssl_close_notify(ssl);
|
||||
::mbedtls_ssl_free(ssl);
|
||||
delete ssl;
|
||||
ssl = nullptr;
|
||||
}
|
||||
YASIO__DECL int yssl_do_handshake(ssl_st* ssl, int& err)
|
||||
{
|
||||
int ret = ::mbedtls_ssl_handshake_step(ssl);
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
if (ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER)
|
||||
return 0;
|
||||
err = EWOULDBLOCK;
|
||||
ret = -1;
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
err = EWOULDBLOCK;
|
||||
break; // Nothing need to do
|
||||
default:
|
||||
err = yasio::errc::ssl_handshake_failed;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
const char* yssl_strerror(ssl_st* ssl, int sslerr, char* buf, size_t buflen)
|
||||
{
|
||||
int n = snprintf(buf, buflen, "error:%d:", sslerr);
|
||||
::mbedtls_strerror(sslerr, buf + n, buflen - n);
|
||||
return buf;
|
||||
}
|
||||
YASIO__DECL int yssl_write(ssl_st* ssl, const void* data, size_t len, int& err)
|
||||
{
|
||||
int n = ::mbedtls_ssl_write(ssl, static_cast<const uint8_t*>(data), len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
switch (n)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
err = EWOULDBLOCK;
|
||||
break;
|
||||
default:
|
||||
err = yasio::errc::ssl_write_failed;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
YASIO__DECL int yssl_read(ssl_st* ssl, void* data, size_t len, int& err)
|
||||
{
|
||||
int n = ::mbedtls_ssl_read(ssl, static_cast<uint8_t*>(data), len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
switch (n)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: // n=0, the upper caller will regards as eof
|
||||
n = 0;
|
||||
case 0:
|
||||
err = yasio::xxsocket::get_last_errno();
|
||||
::mbedtls_ssl_close_notify(ssl);
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
err = EWOULDBLOCK;
|
||||
break;
|
||||
default:
|
||||
err = yasio::errc::ssl_read_failed;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// A multi-platform support c++11 library with focus on asynchronous socket I/O for any
|
||||
// A multi-platform support c++11 library with focus on asynchronous socket I/O for any
|
||||
// client application.
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
|
@ -49,33 +49,30 @@ namespace gc
|
|||
#define YASIO_POOL_FL_BEGIN(chunk) reinterpret_cast<free_link_node*>(chunk->data)
|
||||
#define YASIO_POOL_PREALLOCATE 1
|
||||
|
||||
template <typename _Ty> static size_t aligned_storage_size()
|
||||
template <typename _Ty>
|
||||
static size_t aligned_storage_size()
|
||||
{
|
||||
return sizeof(typename std::aligned_storage<sizeof(_Ty), std::alignment_of<_Ty>::value>::type);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class object_pool
|
||||
{
|
||||
typedef struct free_link_node
|
||||
{
|
||||
class object_pool {
|
||||
typedef struct free_link_node {
|
||||
free_link_node* next;
|
||||
} * free_link;
|
||||
}* free_link;
|
||||
|
||||
typedef struct chunk_link_node
|
||||
{
|
||||
typedef struct chunk_link_node {
|
||||
chunk_link_node* next;
|
||||
char data[0];
|
||||
} * chunk_link;
|
||||
}* chunk_link;
|
||||
|
||||
object_pool(const object_pool&) = delete;
|
||||
object_pool(const object_pool&) = delete;
|
||||
void operator=(const object_pool&) = delete;
|
||||
|
||||
public:
|
||||
OBJECT_POOL_DECL object_pool(size_t element_size, size_t element_count)
|
||||
: free_link_(nullptr), chunk_(nullptr), element_size_(element_size),
|
||||
element_count_(element_count)
|
||||
: free_link_(nullptr), chunk_(nullptr), element_size_(element_size), element_count_(element_count)
|
||||
{
|
||||
#if YASIO_POOL_PREALLOCATE
|
||||
release(allocate_from_process_heap()); // preallocate 1 chunk
|
||||
|
@ -93,7 +90,7 @@ public:
|
|||
while ((p = *q) != nullptr)
|
||||
{
|
||||
*q = p->next;
|
||||
free(p);
|
||||
delete[] (uint8_t*)(p);
|
||||
}
|
||||
|
||||
free_link_ = nullptr;
|
||||
|
@ -147,8 +144,7 @@ private:
|
|||
}
|
||||
OBJECT_POOL_DECL void* allocate_from_process_heap(void)
|
||||
{
|
||||
chunk_link new_chunk =
|
||||
(chunk_link)malloc(sizeof(chunk_link_node) + element_size_ * element_count_);
|
||||
chunk_link new_chunk = (chunk_link) new uint8_t[sizeof(chunk_link_node) + element_size_ * element_count_];
|
||||
#ifdef _DEBUG
|
||||
::memset(new_chunk, 0x00, sizeof(chunk_link_node));
|
||||
#endif
|
||||
|
@ -171,8 +167,7 @@ private:
|
|||
|
||||
for (char* ptr = chunk->data; ptr < rbegin; ptr += element_size_)
|
||||
{
|
||||
reinterpret_cast<free_link_node*>(ptr)->next =
|
||||
reinterpret_cast<free_link_node*>(ptr + element_size_);
|
||||
reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + element_size_);
|
||||
}
|
||||
return reinterpret_cast<free_link_node*>(rbegin);
|
||||
}
|
||||
|
@ -185,14 +180,13 @@ private:
|
|||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename _Ty, typename _Mutex = std::mutex> class object_pool : public detail::object_pool
|
||||
{
|
||||
template <typename _Ty, typename _Mutex = std::mutex>
|
||||
class object_pool : public detail::object_pool {
|
||||
public:
|
||||
object_pool(size_t _ElemCount = 512)
|
||||
: detail::object_pool(yasio::gc::aligned_storage_size<_Ty>(), _ElemCount)
|
||||
{}
|
||||
object_pool(size_t _ElemCount = 512) : detail::object_pool(yasio::gc::aligned_storage_size<_Ty>(), _ElemCount) {}
|
||||
|
||||
template <typename... _Types> _Ty* construct(_Types&&... args)
|
||||
template <typename... _Types>
|
||||
_Ty* construct(_Types&&... args)
|
||||
{
|
||||
return new (allocate()) _Ty(std::forward<_Types>(args)...);
|
||||
}
|
||||
|
@ -218,17 +212,16 @@ public:
|
|||
_Mutex mutex_;
|
||||
};
|
||||
|
||||
template <typename _Ty> class object_pool<_Ty, void> : public detail::object_pool
|
||||
{
|
||||
object_pool(const object_pool&) = delete;
|
||||
template <typename _Ty>
|
||||
class object_pool<_Ty, void> : public detail::object_pool {
|
||||
object_pool(const object_pool&) = delete;
|
||||
void operator=(const object_pool&) = delete;
|
||||
|
||||
public:
|
||||
object_pool(size_t _ElemCount = 512)
|
||||
: detail::object_pool(yasio::gc::aligned_storage_size<_Ty>(), _ElemCount)
|
||||
{}
|
||||
object_pool(size_t _ElemCount = 512) : detail::object_pool(yasio::gc::aligned_storage_size<_Ty>(), _ElemCount) {}
|
||||
|
||||
template <typename... _Types> _Ty* construct(_Types&&... args)
|
||||
template <typename... _Types>
|
||||
_Ty* construct(_Types&&... args)
|
||||
{
|
||||
return new (allocate()) _Ty(std::forward<_Types>(args)...);
|
||||
}
|
||||
|
@ -244,39 +237,57 @@ public:
|
|||
void deallocate(void* _Ptr) { release(_Ptr); }
|
||||
};
|
||||
|
||||
#define DEFINE_OBJECT_POOL_ALLOCATION(ELEMENT_TYPE, ELEMENT_COUNT) \
|
||||
public: \
|
||||
static void* operator new(size_t /*size*/) { return get_pool().allocate(); } \
|
||||
\
|
||||
static void* operator new(size_t /*size*/, std::nothrow_t) { return get_pool().allocate(); } \
|
||||
\
|
||||
static void operator delete(void* p) { get_pool().deallocate(p); } \
|
||||
\
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, void>& get_pool() \
|
||||
{ \
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, void> s_pool(ELEMENT_COUNT); \
|
||||
return s_pool; \
|
||||
#define DEFINE_OBJECT_POOL_ALLOCATION(ELEMENT_TYPE, ELEMENT_COUNT) \
|
||||
public: \
|
||||
static void* operator new(size_t /*size*/) \
|
||||
{ \
|
||||
return get_pool().allocate(); \
|
||||
} \
|
||||
\
|
||||
static void* operator new(size_t /*size*/, std::nothrow_t) \
|
||||
{ \
|
||||
return get_pool().allocate(); \
|
||||
} \
|
||||
\
|
||||
static void operator delete(void* p) \
|
||||
{ \
|
||||
get_pool().deallocate(p); \
|
||||
} \
|
||||
\
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, void>& get_pool() \
|
||||
{ \
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, void> s_pool(ELEMENT_COUNT); \
|
||||
return s_pool; \
|
||||
}
|
||||
|
||||
// The thread safe edition
|
||||
#define DEFINE_CONCURRENT_OBJECT_POOL_ALLOCATION(ELEMENT_TYPE, ELEMENT_COUNT) \
|
||||
public: \
|
||||
static void* operator new(size_t /*size*/) { return get_pool().allocate(); } \
|
||||
\
|
||||
static void* operator new(size_t /*size*/, std::nothrow_t) { return get_pool().allocate(); } \
|
||||
\
|
||||
static void operator delete(void* p) { get_pool().deallocate(p); } \
|
||||
\
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, std::mutex>& get_pool() \
|
||||
{ \
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, std::mutex> s_pool(ELEMENT_COUNT); \
|
||||
return s_pool; \
|
||||
#define DEFINE_CONCURRENT_OBJECT_POOL_ALLOCATION(ELEMENT_TYPE, ELEMENT_COUNT) \
|
||||
public: \
|
||||
static void* operator new(size_t /*size*/) \
|
||||
{ \
|
||||
return get_pool().allocate(); \
|
||||
} \
|
||||
\
|
||||
static void* operator new(size_t /*size*/, std::nothrow_t) \
|
||||
{ \
|
||||
return get_pool().allocate(); \
|
||||
} \
|
||||
\
|
||||
static void operator delete(void* p) \
|
||||
{ \
|
||||
get_pool().deallocate(p); \
|
||||
} \
|
||||
\
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, std::mutex>& get_pool() \
|
||||
{ \
|
||||
static yasio::gc::object_pool<ELEMENT_TYPE, std::mutex> s_pool(ELEMENT_COUNT); \
|
||||
return s_pool; \
|
||||
}
|
||||
|
||||
//////////////////////// allocator /////////////////
|
||||
// TEMPLATE CLASS object_pool_allocator, can't used by std::vector, DO NOT use at non-msvc compiler.
|
||||
template <class _Ty, size_t _ElemCount = 512, class _Mutex = void> class object_pool_allocator
|
||||
{ // generic allocator for objects of class _Ty
|
||||
template <class _Ty, size_t _ElemCount = 512, class _Mutex = void>
|
||||
class object_pool_allocator { // generic allocator for objects of class _Ty
|
||||
public:
|
||||
typedef _Ty value_type;
|
||||
|
||||
|
@ -292,8 +303,8 @@ public:
|
|||
typedef long difference_type;
|
||||
#endif
|
||||
|
||||
template <class _Other> struct rebind
|
||||
{ // convert this type to _ALLOCATOR<_Other>
|
||||
template <class _Other>
|
||||
struct rebind { // convert this type to _ALLOCATOR<_Other>
|
||||
typedef object_pool_allocator<_Other> other;
|
||||
};
|
||||
|
||||
|
@ -315,7 +326,8 @@ public:
|
|||
{ // construct by copying (do nothing)
|
||||
}
|
||||
|
||||
template <class _Other> object_pool_allocator(const object_pool_allocator<_Other>&) throw()
|
||||
template <class _Other>
|
||||
object_pool_allocator(const object_pool_allocator<_Other>&) throw()
|
||||
{ // construct from a related allocator (do nothing)
|
||||
}
|
||||
|
||||
|
@ -357,17 +369,20 @@ public:
|
|||
new ((void*)_Ptr) _Ty(std::forward<_Ty>(_Val));
|
||||
}
|
||||
|
||||
template <class _Other> void construct(pointer _Ptr, _Other&& _Val)
|
||||
template <class _Other>
|
||||
void construct(pointer _Ptr, _Other&& _Val)
|
||||
{ // construct object at _Ptr with value _Val
|
||||
new ((void*)_Ptr) _Ty(std::forward<_Other>(_Val));
|
||||
}
|
||||
|
||||
template <class _Objty, class... _Types> void construct(_Objty* _Ptr, _Types&&... _Args)
|
||||
template <class _Objty, class... _Types>
|
||||
void construct(_Objty* _Ptr, _Types&&... _Args)
|
||||
{ // construct _Objty(_Types...) at _Ptr
|
||||
::new ((void*)_Ptr) _Objty(std::forward<_Types>(_Args)...);
|
||||
}
|
||||
|
||||
template <class _Uty> void destroy(_Uty* _Ptr)
|
||||
template <class _Uty>
|
||||
void destroy(_Uty* _Ptr)
|
||||
{ // destroy object at _Ptr, do nothing
|
||||
_Ptr->~_Uty();
|
||||
}
|
||||
|
@ -386,15 +401,13 @@ public:
|
|||
};
|
||||
|
||||
template <class _Ty, class _Other>
|
||||
inline bool operator==(const object_pool_allocator<_Ty>&,
|
||||
const object_pool_allocator<_Other>&) throw()
|
||||
inline bool operator==(const object_pool_allocator<_Ty>&, const object_pool_allocator<_Other>&) throw()
|
||||
{ // test for allocator equality
|
||||
return (true);
|
||||
}
|
||||
|
||||
template <class _Ty, class _Other>
|
||||
inline bool operator!=(const object_pool_allocator<_Ty>& _Left,
|
||||
const object_pool_allocator<_Other>& _Right) throw()
|
||||
inline bool operator!=(const object_pool_allocator<_Ty>& _Left, const object_pool_allocator<_Other>& _Right) throw()
|
||||
{ // test for allocator inequality
|
||||
return (!(_Left == _Right));
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ SOFTWARE.
|
|||
#include <limits>
|
||||
#include <stack>
|
||||
#include <fstream>
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
#include "yasio/detail/endian_portable.hpp"
|
||||
#include "yasio/detail/utils.hpp"
|
||||
#include "yasio/detail/byte_buffer.hpp"
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// A multi-platform support c++11 library with focus on asynchronous socket I/O for any
|
||||
// client application.
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2023 HALX99
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef YASIO__OPENSSL_INL
|
||||
#define YASIO__OPENSSL_INL
|
||||
|
||||
#if YASIO_SSL_BACKEND == 1 // OpenSSL
|
||||
|
||||
// The ssl error mask (1 << 31), a little hack, but works
|
||||
# define YSSL_ERR_MASK 0x80000000
|
||||
|
||||
YASIO__DECL ssl_ctx_st* yssl_ctx_new(const yssl_options& opts)
|
||||
{
|
||||
auto ctx = ::SSL_CTX_new(opts.client ? ::SSLv23_client_method() : SSLv23_server_method());
|
||||
|
||||
auto mode = SSL_CTX_get_mode(ctx);
|
||||
# if defined(SSL_MODE_RELEASE_BUFFERS)
|
||||
mode |= SSL_MODE_RELEASE_BUFFERS;
|
||||
# endif
|
||||
|
||||
::SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | mode);
|
||||
|
||||
if (opts.client)
|
||||
{
|
||||
if (yasio__valid_str(opts.crtfile_))
|
||||
{
|
||||
if (::SSL_CTX_load_verify_locations(ctx, opts.crtfile_, nullptr) == 1)
|
||||
{
|
||||
::SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, ::SSL_CTX_get_verify_callback(ctx));
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||
::SSL_CTX_set_post_handshake_auth(ctx, 1);
|
||||
# endif
|
||||
# if defined(X509_V_FLAG_PARTIAL_CHAIN)
|
||||
/* Have intermediate certificates in the trust store be treated as
|
||||
trust-anchors, in the same way as self-signed root CA certificates
|
||||
are. This allows users to verify servers using the intermediate cert
|
||||
only, instead of needing the whole chain. */
|
||||
X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), X509_V_FLAG_PARTIAL_CHAIN);
|
||||
# endif
|
||||
}
|
||||
else
|
||||
YASIO_LOG("[global] load ca certifaction file failed!");
|
||||
}
|
||||
else
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yasio__valid_str(opts.crtfile_) && ::SSL_CTX_use_certificate_file(ctx, opts.crtfile_, SSL_FILETYPE_PEM) <= 0)
|
||||
YASIO_LOG("[gobal] load server cert file failed!");
|
||||
|
||||
if (yasio__valid_str(opts.keyfile_) && ::SSL_CTX_use_PrivateKey_file(ctx, opts.keyfile_, SSL_FILETYPE_PEM) <= 0)
|
||||
YASIO_LOG("[gobal] load server private key file failed!");
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
YASIO__DECL void yssl_ctx_free(ssl_ctx_st*& ctx)
|
||||
{
|
||||
::SSL_CTX_free((SSL_CTX*)ctx);
|
||||
ctx = nullptr;
|
||||
}
|
||||
YASIO__DECL ssl_st* yssl_new(ssl_ctx_st* ctx, int fd, const char* hostname, bool client)
|
||||
{
|
||||
auto ssl = ::SSL_new(ctx);
|
||||
::SSL_set_fd(ssl, fd);
|
||||
if (client)
|
||||
{
|
||||
::SSL_set_connect_state(ssl);
|
||||
::SSL_set_tlsext_host_name(ssl, hostname);
|
||||
}
|
||||
else
|
||||
::SSL_set_accept_state(ssl);
|
||||
return ssl;
|
||||
}
|
||||
YASIO__DECL void yssl_shutdown(ssl_st*& ssl)
|
||||
{
|
||||
::SSL_shutdown(ssl);
|
||||
::SSL_free(ssl);
|
||||
ssl = nullptr;
|
||||
}
|
||||
YASIO__DECL int yssl_do_handshake(ssl_st* ssl, int& err)
|
||||
{
|
||||
ERR_clear_error();
|
||||
int ret = ::SSL_do_handshake(ssl);
|
||||
if (ret == 1) // handshake succeed
|
||||
return 0;
|
||||
|
||||
int sslerr = ::SSL_get_error(ssl, ret);
|
||||
/*
|
||||
When using a non-blocking socket, nothing is to be done, but select() can be used to check for
|
||||
the required condition: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
|
||||
*/
|
||||
if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
err = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ssl handshake fail */
|
||||
err = yasio::errc::ssl_handshake_failed; // emit ssl handshake failed, continue handle close flow
|
||||
return (sslerr != SSL_ERROR_SYSCALL) ? static_cast<int>(ERR_get_error() | YSSL_ERR_MASK) : yasio::xxsocket::get_last_errno();
|
||||
}
|
||||
YASIO__DECL const char* yssl_strerror(ssl_st* ssl, int sslerr, char* buf, size_t buflen)
|
||||
{
|
||||
if (yasio__testbits(sslerr, YSSL_ERR_MASK))
|
||||
::ERR_error_string_n((unsigned int)sslerr & ~YSSL_ERR_MASK, buf, buflen);
|
||||
else
|
||||
yasio::xxsocket::strerror_r(sslerr, buf, buflen);
|
||||
return buf;
|
||||
}
|
||||
YASIO__DECL int yssl_write(ssl_st* ssl, const void* data, size_t len, int& err)
|
||||
{
|
||||
ERR_clear_error();
|
||||
int n = ::SSL_write(ssl, data, static_cast<int>(len));
|
||||
if (n > 0)
|
||||
return n;
|
||||
|
||||
int sslerr = ::SSL_get_error(ssl, n);
|
||||
if (sslerr == SSL_ERROR_ZERO_RETURN)
|
||||
{ // SSL_ERROR_SYSCALL
|
||||
err = yasio::xxsocket::get_last_errno();
|
||||
return 0;
|
||||
}
|
||||
switch (sslerr)
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
err = EWOULDBLOCK;
|
||||
break;
|
||||
default:
|
||||
err = yasio::errc::ssl_write_failed;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
YASIO__DECL int yssl_read(ssl_st* ssl, void* data, size_t len, int& err)
|
||||
{
|
||||
ERR_clear_error();
|
||||
int n = ::SSL_read(ssl, data, static_cast<int>(len));
|
||||
if (n > 0)
|
||||
return n;
|
||||
int sslerr = ::SSL_get_error(ssl, n);
|
||||
switch (sslerr)
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* The operation did not complete; the same TLS/SSL I/O function
|
||||
should be called again later. This is basically an EWOULDBLOCK
|
||||
equivalent. */
|
||||
err = EWOULDBLOCK;
|
||||
break;
|
||||
default:
|
||||
err = sslerr == SSL_ERROR_SYSCALL ? yasio::xxsocket::get_last_errno() : yasio::errc::ssl_read_failed;
|
||||
if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) // peer closed connection in SSL handshake
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
void reset() { this->fd_set_.clear(); }
|
||||
|
||||
int poll_io(timeval& waitd_tv) { return ::poll(this->fd_set_.data(), static_cast<int>(this->fd_set_.size()), waitd_tv.tv_sec * 1000 + waitd_tv.tv_usec / 1000); }
|
||||
int poll_io(int wait_ms) { return ::poll(this->fd_set_.data(), static_cast<int>(this->fd_set_.size()), wait_ms); }
|
||||
|
||||
int is_set(socket_native_type fd, int events) const
|
||||
{
|
||||
|
|
|
@ -36,7 +36,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
int poll_io(timeval& waitd_tv) { return ::select(this->max_descriptor_, &(fd_set_[read_op]), &(fd_set_[write_op]), nullptr, &waitd_tv); }
|
||||
int poll_io(int waitd_ms)
|
||||
{
|
||||
timeval waitd_tv = {(decltype(timeval::tv_sec))(waitd_ms / 1000), (decltype(timeval::tv_usec))(waitd_ms % 1000)};
|
||||
return ::select(this->max_descriptor_, &(fd_set_[read_op]), &(fd_set_[write_op]), nullptr, &waitd_tv);
|
||||
}
|
||||
|
||||
int is_set(socket_native_type fd, int events) const
|
||||
{
|
||||
|
|
|
@ -241,12 +241,13 @@ namespace inet
|
|||
struct socket_event {
|
||||
enum
|
||||
{ // event mask
|
||||
read = 1,
|
||||
write = 2,
|
||||
error = 4,
|
||||
null = 0,
|
||||
read = 1,
|
||||
write = 2,
|
||||
error = 4,
|
||||
readwrite = read | write,
|
||||
};
|
||||
};
|
||||
}
|
||||
} // namespace inet
|
||||
} // namespace yasio
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,8 @@ SOFTWARE.
|
|||
#ifndef YASIO__SSL_HPP
|
||||
#define YASIO__SSL_HPP
|
||||
|
||||
#include "yasio/detail/config.hpp"
|
||||
|
||||
#if YASIO_SSL_BACKEND == 1 // OpenSSL
|
||||
# include <openssl/bio.h>
|
||||
# include <openssl/ssl.h>
|
||||
|
@ -41,27 +43,56 @@ SOFTWARE.
|
|||
# include "mbedtls/entropy.h"
|
||||
# include "mbedtls/ctr_drbg.h"
|
||||
# include "mbedtls/error.h"
|
||||
# include "mbedtls/version.h"
|
||||
struct ssl_ctx_st {
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_x509_crt cert;
|
||||
mbedtls_pk_context pkey;
|
||||
mbedtls_ssl_config conf;
|
||||
};
|
||||
struct ssl_st : public mbedtls_ssl_context {
|
||||
mbedtls_net_context bio;
|
||||
};
|
||||
inline ssl_st* mbedtls_ssl_new(ssl_ctx_st* ctx)
|
||||
{
|
||||
auto ssl = new ssl_st();
|
||||
::mbedtls_ssl_init(ssl);
|
||||
::mbedtls_ssl_setup(ssl, &ctx->conf);
|
||||
return ssl;
|
||||
}
|
||||
inline void mbedtls_ssl_set_fd(ssl_st* ssl, int fd)
|
||||
{
|
||||
ssl->bio.fd = fd;
|
||||
::mbedtls_ssl_set_bio(ssl, &ssl->bio, ::mbedtls_net_send, ::mbedtls_net_recv, nullptr /* rev_timeout() */);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
struct yssl_options {
|
||||
const char* crtfile_;
|
||||
const char* keyfile_;
|
||||
bool client;
|
||||
};
|
||||
|
||||
YASIO__DECL ssl_ctx_st* yssl_ctx_new(const yssl_options& opts);
|
||||
YASIO__DECL void yssl_ctx_free(ssl_ctx_st*& ctx);
|
||||
|
||||
YASIO__DECL ssl_st* yssl_new(ssl_ctx_st* ctx, int fd, const char* hostname, bool client);
|
||||
YASIO__DECL void yssl_shutdown(ssl_st*&);
|
||||
|
||||
/**
|
||||
* @returns
|
||||
* 0: succeed
|
||||
* other: use yssl_strerror(ret & YSSL_ERROR_MASK, ...) get error message
|
||||
* - err can bb
|
||||
- EWOULDBLOCK: status ok, repeat call next time
|
||||
* - yasio::errc::ssl_handshake_failed: failed
|
||||
*/
|
||||
YASIO__DECL int yssl_do_handshake(ssl_st* ssl, int& err);
|
||||
YASIO__DECL const char* yssl_strerror(ssl_st* ssl, int sslerr, char* buf, size_t buflen);
|
||||
|
||||
YASIO__DECL int yssl_write(ssl_st* ssl, const void* data, size_t len, int& err);
|
||||
YASIO__DECL int yssl_read(ssl_st* ssl, void* data, size_t len, int& err);
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// --- Implement common yasio ssl api with different ssl backends
|
||||
|
||||
#define yasio__valid_str(str) (str && *str)
|
||||
|
||||
#if YASIO_SSL_BACKEND == 1 // openssl
|
||||
# include "yasio/detail/openssl.inl"
|
||||
#elif YASIO_SSL_BACKEND == 2 // mbedtls
|
||||
# include "yasio/detail/mbedtls.inl"
|
||||
#else
|
||||
# error "yasio - Unsupported ssl backend provided!"
|
||||
#endif
|
||||
|
|
|
@ -1436,6 +1436,15 @@ inline std::basic_string<_CharT, _Traits, Allocator>& assign(std::basic_string<_
|
|||
lhs.clear();
|
||||
return lhs;
|
||||
}
|
||||
template <typename _CharT, typename _Traits, typename Allocator>
|
||||
inline std::basic_string<_CharT, _Traits, Allocator>& append(std::basic_string<_CharT, _Traits, Allocator>& lhs, const basic_string_view<_CharT, _Traits>& rhs)
|
||||
{
|
||||
if (!rhs.empty())
|
||||
lhs.append(rhs.data(), rhs.size());
|
||||
else
|
||||
lhs.clear();
|
||||
return lhs;
|
||||
}
|
||||
template <typename _CharT, typename _Traits, typename Allocator = std::allocator<_CharT>>
|
||||
inline std::basic_string<_CharT, _Traits, Allocator> svtos(const basic_string_view<_CharT, _Traits>& value)
|
||||
{
|
|
@ -303,6 +303,7 @@ void xxsocket::traverse_local_address(std::function<bool(const ip::endpoint&)> h
|
|||
|
||||
endpoint ep;
|
||||
int iret = getaddrinfo(hostname, nullptr, &hint, &ailist);
|
||||
(void)iret;
|
||||
if (ailist != nullptr)
|
||||
{
|
||||
for (auto aip = ailist; aip != nullptr; aip = aip->ai_next)
|
||||
|
@ -362,17 +363,17 @@ void xxsocket::traverse_local_address(std::function<bool(const ip::endpoint&)> h
|
|||
|
||||
xxsocket::xxsocket(void) : fd(invalid_socket) {}
|
||||
xxsocket::xxsocket(socket_native_type h) : fd(h) {}
|
||||
xxsocket::xxsocket(xxsocket&& right) : fd(invalid_socket) { swap(right); }
|
||||
xxsocket::xxsocket(xxsocket&& right) YASIO__NOEXCEPT : fd(invalid_socket) { swap(right); }
|
||||
xxsocket::xxsocket(int af, int type, int protocol) : fd(invalid_socket) { open(af, type, protocol); }
|
||||
xxsocket::~xxsocket(void) { close(); }
|
||||
|
||||
xxsocket& xxsocket::operator=(socket_native_type handle)
|
||||
xxsocket& xxsocket::operator=(socket_native_type handle) YASIO__NOEXCEPT
|
||||
{
|
||||
if (!this->is_open())
|
||||
this->fd = handle;
|
||||
return *this;
|
||||
}
|
||||
xxsocket& xxsocket::operator=(xxsocket&& right) { return swap(right); }
|
||||
xxsocket& xxsocket::operator=(xxsocket&& right) YASIO__NOEXCEPT { return swap(right); }
|
||||
|
||||
xxsocket& xxsocket::swap(xxsocket& rhs)
|
||||
{
|
||||
|
@ -550,7 +551,7 @@ int xxsocket::connect_n(socket_native_type s, const endpoint& ep, const std::chr
|
|||
if (ret == 0)
|
||||
goto done; /* connect completed immediately */
|
||||
|
||||
if ((ret = xxsocket::select(s, &rset, &wset, nullptr, wtimeout)) <= 0)
|
||||
if (xxsocket::select(s, &rset, &wset, nullptr, wtimeout) <= 0)
|
||||
error = xxsocket::get_last_errno();
|
||||
else if ((FD_ISSET(s, &rset) || FD_ISSET(s, &wset)))
|
||||
{ /* Everythings are ok */
|
||||
|
@ -930,17 +931,27 @@ const char* xxsocket::strerror(int error)
|
|||
{
|
||||
#if defined(_WIN32)
|
||||
static char error_msg[256];
|
||||
ZeroMemory(error_msg, sizeof(error_msg));
|
||||
::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK /* remove line-end charactors \r\n */, NULL,
|
||||
error, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), // english language
|
||||
error_msg, sizeof(error_msg), nullptr);
|
||||
|
||||
return error_msg;
|
||||
return xxsocket::strerror_r(error, error_msg, sizeof(error_msg));
|
||||
#else
|
||||
return ::strerror(error);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* xxsocket::strerror_r(int error, char* buf, size_t buflen)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
ZeroMemory(buf, buflen);
|
||||
::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK /* remove line-end charactors \r\n */, NULL,
|
||||
error, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), // english language
|
||||
buf, static_cast<DWORD>(buflen), nullptr);
|
||||
|
||||
return buf;
|
||||
#else
|
||||
(void)::strerror_r(error, buf, buflen);
|
||||
return buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* xxsocket::gai_strerror(int error)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
|
@ -960,7 +971,7 @@ struct ws2_32_gc {
|
|||
ws2_32_gc(void)
|
||||
{
|
||||
WSADATA dat = {0};
|
||||
WSAStartup(0x0202, &dat);
|
||||
(void)WSAStartup(0x0202, &dat);
|
||||
}
|
||||
~ws2_32_gc(void) { WSACleanup(); }
|
||||
};
|
||||
|
|
|
@ -635,13 +635,13 @@ public:
|
|||
// Disable copy constructor
|
||||
YASIO__DECL xxsocket(const xxsocket&) = delete;
|
||||
// Construct with a exist socket, it will replace the source
|
||||
YASIO__DECL xxsocket(xxsocket&&);
|
||||
YASIO__DECL xxsocket(xxsocket&&) YASIO__NOEXCEPT;
|
||||
|
||||
YASIO__DECL xxsocket& operator=(socket_native_type handle);
|
||||
YASIO__DECL xxsocket& operator=(socket_native_type handle) YASIO__NOEXCEPT;
|
||||
// Disable copy assign operator
|
||||
YASIO__DECL xxsocket& operator=(const xxsocket&) = delete;
|
||||
// Construct with a exist socket, it will replace the source
|
||||
YASIO__DECL xxsocket& operator=(xxsocket&&);
|
||||
YASIO__DECL xxsocket& operator=(xxsocket&&) YASIO__NOEXCEPT;
|
||||
|
||||
// See also as function: open
|
||||
YASIO__DECL xxsocket(int af, int type, int protocol);
|
||||
|
@ -1022,6 +1022,7 @@ public:
|
|||
YASIO__DECL static bool not_recv_error(int error);
|
||||
|
||||
YASIO__DECL static const char* strerror(int error);
|
||||
YASIO__DECL static const char* strerror_r(int error, char* buf, size_t buflen);
|
||||
YASIO__DECL static const char* gai_strerror(int error);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -117,15 +117,15 @@ enum
|
|||
YCPF_NEEDS_QUERY = 1 << 21,
|
||||
|
||||
/// below is byte2 of private flags (25~32) are mutable, and will be cleared automatically when connect flow done, see clear_mutable_flags.
|
||||
|
||||
/* whether ssl client in handshaking */
|
||||
YCPF_SSL_HANDSHAKING = 1 << 25,
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// the minimal wait duration for select
|
||||
static highp_time_t yasio__min_wait_duration = 0LL;
|
||||
static highp_time_t yasio__min_wait_usec = 0LL;
|
||||
// By default we will wait no longer than 5 minutes. This will ensure that
|
||||
// any changes to the system clock are detected after no longer than this.
|
||||
static const highp_time_t yasio__max_wait_usec = 5 * 60 * 1000 * 1000LL;
|
||||
// the max transport alloc size
|
||||
static const size_t yasio__max_tsize = (std::max)({sizeof(io_transport_tcp), sizeof(io_transport_udp), sizeof(io_transport_ssl), sizeof(io_transport_kcp)});
|
||||
} // namespace
|
||||
|
@ -139,11 +139,14 @@ struct yasio__global_state {
|
|||
{
|
||||
auto __get_cprint = [&]() -> const print_fn2_t& { return custom_print; };
|
||||
// for single core CPU, we set minimal wait duration to 10us by default
|
||||
yasio__min_wait_duration = std::thread::hardware_concurrency() > 1 ? 0LL : YASIO_MIN_WAIT_DURATION;
|
||||
yasio__min_wait_usec = std::thread::hardware_concurrency() > 1 ? 0LL : 10LL;
|
||||
#if defined(YASIO_SSL_BACKEND) && YASIO_SSL_BACKEND == 1
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
if (OPENSSL_init_ssl(0, nullptr) == 1)
|
||||
{
|
||||
yasio__setbits(this->init_flags_, INITF_SSL);
|
||||
ERR_clear_error();
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
|
@ -190,27 +193,13 @@ void highp_timer::cancel(io_service& service)
|
|||
}
|
||||
|
||||
/// io_send_op
|
||||
int io_send_op::perform(io_transport* transport, const void* buf, int n) { return transport->write_cb_(buf, n, nullptr); }
|
||||
int io_send_op::perform(io_transport* transport, const void* buf, int n, int& error) { return transport->write_cb_(buf, n, nullptr, error); }
|
||||
|
||||
/// io_sendto_op
|
||||
int io_sendto_op::perform(io_transport* transport, const void* buf, int n) { return transport->write_cb_(buf, n, std::addressof(destination_)); }
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
void ssl_auto_handle::destroy()
|
||||
int io_sendto_op::perform(io_transport* transport, const void* buf, int n, int& error)
|
||||
{
|
||||
if (ssl_)
|
||||
{
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
::SSL_shutdown(ssl_);
|
||||
::SSL_free(ssl_);
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
::mbedtls_ssl_free(ssl_);
|
||||
delete ssl_;
|
||||
# endif
|
||||
ssl_ = nullptr;
|
||||
}
|
||||
return transport->write_cb_(buf, n, std::addressof(destination_), error);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// io_channel
|
||||
io_channel::io_channel(io_service& service, int index) : io_base(), service_(service)
|
||||
|
@ -220,6 +209,15 @@ io_channel::io_channel(io_service& service, int index) : io_base(), service_(ser
|
|||
index_ = index;
|
||||
decode_len_ = [=](void* ptr, int len) { return this->__builtin_decode_len(ptr, len); };
|
||||
}
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
SSL_CTX* io_channel::get_ssl_context(bool client) const
|
||||
{
|
||||
if (client)
|
||||
return service_.ssl_roles_[YSSL_CLIENT];
|
||||
auto& ctx = service_.ssl_roles_[YSSL_SERVER];
|
||||
return (ctx) ? ctx : service_.init_ssl_context(YSSL_SERVER);
|
||||
}
|
||||
#endif
|
||||
const print_fn2_t& io_channel::__get_cprint() const { return get_service().options_.print_; }
|
||||
std::string io_channel::format_destination() const
|
||||
{
|
||||
|
@ -251,7 +249,6 @@ void io_channel::join_multicast_group()
|
|||
case AF_INET6:
|
||||
socket_->set_optval(IPPROTO_IPV6, IP_MULTICAST_IF, multiif_.in6_.sin6_scope_id);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
||||
int loopback = yasio__testbits(properties_, YCPF_MCAST_LOOPBACK) ? 1 : 0;
|
||||
|
@ -340,14 +337,14 @@ io_transport::io_transport(io_channel* ctx, xxsocket_ptr&& s) : ctx_(ctx)
|
|||
#endif
|
||||
}
|
||||
const print_fn2_t& io_transport::__get_cprint() const { return ctx_->get_service().options_.print_; }
|
||||
int io_transport::write(dynamic_buffer_t&& buffer, completion_cb_t&& handler)
|
||||
int io_transport::write(sbyte_buffer&& buffer, completion_cb_t&& handler)
|
||||
{
|
||||
int n = static_cast<int>(buffer.size());
|
||||
send_queue_.emplace(cxx14::make_unique<io_send_op>(std::move(buffer), std::move(handler)));
|
||||
get_service().interrupt();
|
||||
return n;
|
||||
}
|
||||
int io_transport::do_read(int revent, int& error, highp_time_t&) { return revent ? this->call_read(buffer_ + offset_, sizeof(buffer_) - offset_, error) : 0; }
|
||||
int io_transport::do_read(int revent, int& error, highp_time_t&) { return this->call_read(buffer_ + offset_, sizeof(buffer_) - offset_, revent, error); }
|
||||
bool io_transport::do_write(highp_time_t& wait_duration)
|
||||
{
|
||||
bool ret = false;
|
||||
|
@ -381,7 +378,7 @@ bool io_transport::do_write(highp_time_t& wait_duration)
|
|||
}
|
||||
}
|
||||
else
|
||||
wait_duration = yasio__min_wait_duration;
|
||||
wait_duration = yasio__min_wait_usec;
|
||||
}
|
||||
if (no_wevent && pollout_registerred_)
|
||||
{
|
||||
|
@ -393,9 +390,9 @@ bool io_transport::do_write(highp_time_t& wait_duration)
|
|||
|
||||
return ret;
|
||||
}
|
||||
int io_transport::call_read(void* data, int size, int& error)
|
||||
int io_transport::call_read(void* data, int size, int revent, int& error)
|
||||
{
|
||||
int n = read_cb_(data, size);
|
||||
int n = read_cb_(data, size, revent, error);
|
||||
if (n > 0)
|
||||
{
|
||||
ctx_->bytes_transferred_ += n;
|
||||
|
@ -403,7 +400,6 @@ int io_transport::call_read(void* data, int size, int& error)
|
|||
}
|
||||
if (n < 0)
|
||||
{
|
||||
error = xxsocket::get_last_errno();
|
||||
if (xxsocket::not_recv_error(error))
|
||||
return (error = 0); // status ok, clear error
|
||||
return n;
|
||||
|
@ -417,7 +413,7 @@ int io_transport::call_read(void* data, int size, int& error)
|
|||
}
|
||||
int io_transport::call_write(io_send_op* op, int& error)
|
||||
{
|
||||
int n = op->perform(this, op->buffer_.data() + op->offset_, static_cast<int>(op->buffer_.size() - op->offset_));
|
||||
int n = op->perform(this, op->buffer_.data() + op->offset_, static_cast<int>(op->buffer_.size() - op->offset_), error);
|
||||
if (n > 0)
|
||||
{
|
||||
// #performance: change offset only, remain data will be send at next frame.
|
||||
|
@ -427,7 +423,6 @@ int io_transport::call_write(io_send_op* op, int& error)
|
|||
}
|
||||
else if (n < 0)
|
||||
{
|
||||
error = xxsocket::get_last_errno();
|
||||
if (xxsocket::not_send_error(error))
|
||||
n = 0;
|
||||
else if (yasio__testbits(ctx_->properties_, YCM_UDP))
|
||||
|
@ -448,97 +443,81 @@ void io_transport::complete_op(io_send_op* op, int error)
|
|||
}
|
||||
void io_transport::set_primitives()
|
||||
{
|
||||
this->write_cb_ = [=](const void* data, int len, const ip::endpoint*) { return socket_->send(data, len); };
|
||||
this->read_cb_ = [=](void* data, int len) { return socket_->recv(data, len, 0); };
|
||||
this->write_cb_ = [=](const void* data, int len, const ip::endpoint*, int& error) {
|
||||
int n = socket_->send(data, len);
|
||||
if (n < 0)
|
||||
error = xxsocket::get_last_errno();
|
||||
return n;
|
||||
};
|
||||
this->read_cb_ = [=](void* data, int len, int revent, int& error) {
|
||||
if (revent)
|
||||
{
|
||||
int n = socket_->recv(data, len);
|
||||
if (n < 0)
|
||||
error = xxsocket::get_last_errno();
|
||||
return n;
|
||||
}
|
||||
|
||||
error = EWOULDBLOCK;
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
// -------------------- io_transport_tcp ---------------------
|
||||
inline io_transport_tcp::io_transport_tcp(io_channel* ctx, xxsocket_ptr&& s) : io_transport(ctx, std::forward<xxsocket_ptr>(s)) {}
|
||||
// ----------------------- io_transport_ssl ----------------
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
io_transport_ssl::io_transport_ssl(io_channel* ctx, xxsocket_ptr&& s) : io_transport_tcp(ctx, std::forward<xxsocket_ptr>(s)), ssl_(std::move(ctx->ssl_)) {}
|
||||
io_transport_ssl::io_transport_ssl(io_channel* ctx, xxsocket_ptr&& sock) : io_transport_tcp(ctx, std::forward<xxsocket_ptr>(sock))
|
||||
{
|
||||
this->state_ = io_base::state::CONNECTING; // for ssl, inital state shoud be connecing for ssl handshake
|
||||
bool client = yasio__testbits(ctx->properties_, YCM_CLIENT);
|
||||
this->ssl_ = yssl_new(ctx->get_ssl_context(client), static_cast<int>(this->socket_->native_handle()), ctx->remote_host_.c_str(), client);
|
||||
}
|
||||
int io_transport_ssl::do_ssl_handshake(int& error)
|
||||
{
|
||||
int ret = yssl_do_handshake(ssl_, error);
|
||||
if (ret == 0) // handshake succeed
|
||||
{ // because we invoke handshake in call_read, so we emit EWOULDBLOCK to mark ssl transport status `ok`
|
||||
this->state_ = io_base::state::OPENED;
|
||||
this->read_cb_ = [=](void* data, int len, int revent, int& error) {
|
||||
if (revent)
|
||||
return yssl_read(ssl_, data, len, error);
|
||||
error = EWOULDBLOCK;
|
||||
return -1;
|
||||
};
|
||||
this->write_cb_ = [=](const void* data, int len, const ip::endpoint*, int& error) { return yssl_write(ssl_, data, len, error); };
|
||||
|
||||
YASIO_KLOGD("[index: %d] the connection #%u <%s> --> <%s> is established.", ctx_->index_, this->id_, this->local_endpoint().to_string().c_str(),
|
||||
this->remote_endpoint().to_string().c_str());
|
||||
get_service().fire_event(ctx_->index_, YEK_ON_OPEN, 0, this);
|
||||
|
||||
error = EWOULDBLOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error == EWOULDBLOCK)
|
||||
get_service().interrupt();
|
||||
else
|
||||
{ // handshake failed, print reason
|
||||
char buf[256] = {0};
|
||||
YASIO_KLOGE("[index: %d] do_ssl_handshake fail with %s", ctx_->index_, yssl_strerror(ssl_, ret, buf, sizeof(buf)));
|
||||
if (yasio__testbits(ctx_->properties_, YCM_CLIENT))
|
||||
{
|
||||
YASIO_KLOGE("[index: %d] connect server %s failed, ec=%d, detail:%s", ctx_->index_, ctx_->format_destination().c_str(), error,
|
||||
io_service::strerror(error));
|
||||
get_service().fire_event(ctx_->index(), YEK_ON_OPEN, error, ctx_);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void io_transport_ssl::do_ssl_shutdown()
|
||||
{
|
||||
if (ssl_)
|
||||
yssl_shutdown(ssl_);
|
||||
}
|
||||
void io_transport_ssl::set_primitives()
|
||||
{
|
||||
this->read_cb_ = [=](void* data, int len) {
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
ERR_clear_error();
|
||||
int n = ::SSL_read(ssl_, data, len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
int error = SSL_get_error(ssl_, n);
|
||||
switch (error)
|
||||
{
|
||||
case SSL_ERROR_ZERO_RETURN: // n=0, the upper caller will regards as eof
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* The operation did not complete; the same TLS/SSL I/O function
|
||||
should be called again later. This is basically an EWOULDBLOCK
|
||||
equivalent. */
|
||||
if (xxsocket::get_last_errno() != EWOULDBLOCK)
|
||||
xxsocket::set_last_errno(EWOULDBLOCK);
|
||||
break;
|
||||
default:
|
||||
xxsocket::set_last_errno(yasio::errc::ssl_read_failed);
|
||||
}
|
||||
return n;
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
auto ssl = static_cast<SSL*>(ssl_);
|
||||
int n = ::mbedtls_ssl_read(ssl, static_cast<uint8_t*>(data), len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
switch (n)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: // n=0, the upper caller will regards as eof
|
||||
n = 0;
|
||||
case 0:
|
||||
::mbedtls_ssl_close_notify(ssl);
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
if (xxsocket::get_last_errno() != EWOULDBLOCK)
|
||||
xxsocket::set_last_errno(EWOULDBLOCK);
|
||||
break;
|
||||
default:
|
||||
xxsocket::set_last_errno(yasio::errc::ssl_read_failed);
|
||||
}
|
||||
return n;
|
||||
# endif
|
||||
};
|
||||
this->write_cb_ = [=](const void* data, int len, const ip::endpoint*) {
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
ERR_clear_error();
|
||||
int n = ::SSL_write(ssl_, data, len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
|
||||
int error = SSL_get_error(ssl_, n);
|
||||
switch (error)
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
if (xxsocket::get_last_errno() != EWOULDBLOCK)
|
||||
xxsocket::set_last_errno(EWOULDBLOCK);
|
||||
break;
|
||||
default:
|
||||
xxsocket::set_last_errno(yasio::errc::ssl_write_failed);
|
||||
}
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
int n = ::mbedtls_ssl_write(static_cast<SSL*>(ssl_), static_cast<const uint8_t*>(data), len);
|
||||
if (n > 0)
|
||||
return n;
|
||||
switch (n)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
if (xxsocket::get_last_errno() != EWOULDBLOCK)
|
||||
xxsocket::set_last_errno(EWOULDBLOCK);
|
||||
break;
|
||||
default:
|
||||
xxsocket::set_last_errno(yasio::errc::ssl_write_failed);
|
||||
}
|
||||
# endif
|
||||
return -1;
|
||||
};
|
||||
this->read_cb_ = [=](void* /*data*/, int /*len*/, int /*revent*/, int& error) { return do_ssl_handshake(error); };
|
||||
}
|
||||
#endif
|
||||
// ----------------------- io_transport_udp ----------------
|
||||
|
@ -593,11 +572,11 @@ void io_transport_udp::disconnect()
|
|||
connected_ = false;
|
||||
set_primitives();
|
||||
}
|
||||
int io_transport_udp::write(dynamic_buffer_t&& buffer, completion_cb_t&& handler)
|
||||
int io_transport_udp::write(sbyte_buffer&& buffer, completion_cb_t&& handler)
|
||||
{
|
||||
return connected_ ? io_transport::write(std::move(buffer), std::move(handler)) : write_to(std::move(buffer), ensure_destination(), std::move(handler));
|
||||
}
|
||||
int io_transport_udp::write_to(dynamic_buffer_t&& buffer, const ip::endpoint& to, completion_cb_t&& handler)
|
||||
int io_transport_udp::write_to(sbyte_buffer&& buffer, const ip::endpoint& to, completion_cb_t&& handler)
|
||||
{
|
||||
int n = static_cast<int>(buffer.size());
|
||||
send_queue_.emplace(cxx14::make_unique<io_sendto_op>(std::move(buffer), std::move(handler), to));
|
||||
|
@ -610,23 +589,30 @@ void io_transport_udp::set_primitives()
|
|||
io_transport::set_primitives();
|
||||
else
|
||||
{
|
||||
this->write_cb_ = [=](const void* data, int len, const ip::endpoint* destination) {
|
||||
this->write_cb_ = [=](const void* data, int len, const ip::endpoint* destination, int& error) {
|
||||
assert(destination);
|
||||
int n = socket_->sendto(data, len, *destination);
|
||||
if (n < 0)
|
||||
{
|
||||
auto error = xxsocket::get_last_errno();
|
||||
error = xxsocket::get_last_errno();
|
||||
if (!xxsocket::not_send_error(error))
|
||||
YASIO_KLOGW("[index: %d] write udp socket failed, ec=%d, detail:%s", this->cindex(), error, io_service::strerror(error));
|
||||
}
|
||||
return n;
|
||||
};
|
||||
this->read_cb_ = [=](void* data, int len) {
|
||||
ip::endpoint peer;
|
||||
int n = socket_->recvfrom(data, len, peer);
|
||||
if (n > 0)
|
||||
this->peer_ = peer;
|
||||
return n;
|
||||
this->read_cb_ = [=](void* data, int len, int revent, int& error) {
|
||||
if (revent)
|
||||
{
|
||||
ip::endpoint peer;
|
||||
int n = socket_->recvfrom(data, len, peer);
|
||||
if (n > 0)
|
||||
this->peer_ = peer;
|
||||
if (n < 0)
|
||||
error = xxsocket::get_last_errno();
|
||||
return n;
|
||||
}
|
||||
error = EWOULDBLOCK;
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -645,15 +631,18 @@ io_transport_kcp::io_transport_kcp(io_channel* ctx, xxsocket_ptr&& s) : io_trans
|
|||
::ikcp_nodelay(this->kcp_, 1, 5000 /*kcp max interval is 5000(ms)*/, 2, 1);
|
||||
::ikcp_setoutput(this->kcp_, [](const char* buf, int len, ::ikcpcb* /*kcp*/, void* user) {
|
||||
auto t = (io_transport_kcp*)user;
|
||||
if (yasio__min_wait_duration == 0)
|
||||
return t->write_cb_(buf, len, std::addressof(t->ensure_destination()));
|
||||
if (yasio__min_wait_usec == 0)
|
||||
{
|
||||
int ignored_ec = 0;
|
||||
return t->write_cb_(buf, len, std::addressof(t->ensure_destination()), ignored_ec);
|
||||
}
|
||||
// Enqueue to transport queue
|
||||
return t->io_transport_udp::write(dynamic_buffer_t{buf, buf + len}, nullptr);
|
||||
return t->io_transport_udp::write(sbyte_buffer{buf, buf + len}, nullptr);
|
||||
});
|
||||
}
|
||||
io_transport_kcp::~io_transport_kcp() { ::ikcp_release(this->kcp_); }
|
||||
|
||||
int io_transport_kcp::write(dynamic_buffer_t&& buffer, completion_cb_t&& /*handler*/)
|
||||
int io_transport_kcp::write(sbyte_buffer&& buffer, completion_cb_t&& /*handler*/)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lck(send_mtx_);
|
||||
int len = static_cast<int>(buffer.size());
|
||||
|
@ -663,14 +652,14 @@ int io_transport_kcp::write(dynamic_buffer_t&& buffer, completion_cb_t&& /*handl
|
|||
}
|
||||
int io_transport_kcp::do_read(int revent, int& error, highp_time_t& wait_duration)
|
||||
{
|
||||
int n = revent ? this->call_read(&rawbuf_.front(), static_cast<int>(rawbuf_.size()), error) : 0;
|
||||
int n = this->call_read(&rawbuf_.front(), static_cast<int>(rawbuf_.size()), revent, error);
|
||||
if (n > 0)
|
||||
this->handle_input(rawbuf_.data(), n, error, wait_duration);
|
||||
if (!error)
|
||||
{ // !important, should always try to call ikcp_recv when no error occured.
|
||||
n = ::ikcp_recv(kcp_, buffer_ + offset_, sizeof(buffer_) - offset_);
|
||||
if (n > 0) // If got data from kcp, don't wait
|
||||
wait_duration = yasio__min_wait_duration;
|
||||
wait_duration = yasio__min_wait_usec;
|
||||
else if (n < 0)
|
||||
n = 0; // EAGAIN/EWOULDBLOCK
|
||||
}
|
||||
|
@ -696,7 +685,7 @@ bool io_transport_kcp::do_write(highp_time_t& wait_duration)
|
|||
::ikcp_update(kcp_, static_cast<IUINT32>(::yasio::clock()));
|
||||
::ikcp_flush(kcp_);
|
||||
this->check_timeout(wait_duration); // call ikcp_check
|
||||
if (yasio__min_wait_duration == 0)
|
||||
if (yasio__min_wait_usec == 0)
|
||||
return true;
|
||||
// Call super do_write to perform low layer socket.send
|
||||
// benefit of transport queue:
|
||||
|
@ -710,7 +699,7 @@ void io_transport_kcp::check_timeout(highp_time_t& wait_duration) const
|
|||
auto expire_time = ::ikcp_check(kcp_, current);
|
||||
highp_time_t duration = static_cast<highp_time_t>(expire_time - current) * std::milli::den;
|
||||
if (duration < 0)
|
||||
duration = yasio__min_wait_duration;
|
||||
duration = yasio__min_wait_usec;
|
||||
if (wait_duration > duration)
|
||||
wait_duration = duration;
|
||||
}
|
||||
|
@ -806,6 +795,12 @@ void io_service::handle_stop()
|
|||
}
|
||||
void io_service::initialize(const io_hostent* channel_eps, int channel_count)
|
||||
{
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
ssl_roles_[YSSL_CLIENT] = ssl_roles_[YSSL_SERVER] = nullptr;
|
||||
#endif
|
||||
|
||||
this->wait_duration_ = yasio__max_wait_usec;
|
||||
|
||||
// at least one channel
|
||||
if (channel_count < 1)
|
||||
channel_count = 1;
|
||||
|
@ -884,12 +879,11 @@ void io_service::run()
|
|||
yasio::set_thread_name("yasio");
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
init_ssl_context();
|
||||
init_ssl_context(YSSL_CLIENT); // by default, init ssl client context
|
||||
#endif
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
recreate_ares_channel();
|
||||
ares_socket_t ares_socks[ARES_GETSOCK_MAXNUM] = {0};
|
||||
int ares_socks_count = 0;
|
||||
#endif
|
||||
|
||||
// Call once at startup
|
||||
|
@ -897,24 +891,30 @@ void io_service::run()
|
|||
|
||||
// The core event loop
|
||||
fd_set_adapter fd_set; // The temp file descriptor set
|
||||
this->wait_duration_ = YASIO_MAX_WAIT_DURATION;
|
||||
|
||||
do
|
||||
{
|
||||
auto wait_duration = get_timeout(this->wait_duration_); // Gets current wait duration
|
||||
this->wait_duration_ = YASIO_MAX_WAIT_DURATION; // Reset next wait duration
|
||||
if (wait_duration > 0)
|
||||
{
|
||||
fd_set = this->fd_set_;
|
||||
timeval waitd_tv = {(decltype(timeval::tv_sec))(wait_duration / 1000000), (decltype(timeval::tv_usec))(wait_duration % 1000000)};
|
||||
this->wait_duration_ = yasio__max_wait_usec; // Reset next wait duration
|
||||
|
||||
fd_set = this->fd_set_;
|
||||
timeval waitd_tv = {(decltype(timeval::tv_sec))(wait_duration / 1000000), (decltype(timeval::tv_usec))(wait_duration % 1000000)};
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
if (ares_outstanding_work_)
|
||||
{
|
||||
ares_socks_count = register_ares_fds(ares_socks, fd_set);
|
||||
::ares_timeout(this->ares_, &waitd_tv, &waitd_tv);
|
||||
}
|
||||
/**
|
||||
* retrieves the set of file descriptors which the calling application should poll io,
|
||||
* after poll_io, for ares invoke flow, refer to:
|
||||
* https://c-ares.org/ares_fds.html
|
||||
* https://c-ares.org/ares_timeout.html
|
||||
* https://c-ares.org/ares_process_fd.html
|
||||
*/
|
||||
auto ares_nfds = do_ares_fds(ares_socks, fd_set, waitd_tv);
|
||||
#endif
|
||||
YASIO_KLOGV("[core] poll_io max_nfds=%d, waiting... %ld milliseconds", fd_set.max_descriptor(), waitd_tv.tv_sec * 1000 + waitd_tv.tv_usec / 1000);
|
||||
int retval = fd_set.poll_io(waitd_tv);
|
||||
|
||||
const int waitd_ms = static_cast<int>(waitd_tv.tv_sec * 1000 + waitd_tv.tv_usec / 1000);
|
||||
if (waitd_ms > 0)
|
||||
{
|
||||
YASIO_KLOGV("[core] poll_io max_nfds=%d, waiting... %ld milliseconds", fd_set.max_descriptor(), waitd_ms);
|
||||
int retval = fd_set.poll_io(waitd_ms);
|
||||
YASIO_KLOGV("[core] poll_io waked up, retval=%d", retval);
|
||||
if (retval < 0)
|
||||
{
|
||||
|
@ -936,8 +936,8 @@ void io_service::run()
|
|||
}
|
||||
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
// process possible async resolve requests.
|
||||
process_ares_requests(ares_socks, ares_socks_count, fd_set);
|
||||
// process events for name resolution.
|
||||
do_ares_process_fds(ares_socks, ares_nfds, fd_set);
|
||||
#endif
|
||||
|
||||
// process active transports
|
||||
|
@ -954,7 +954,8 @@ void io_service::run()
|
|||
destroy_ares_channel();
|
||||
#endif
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
cleanup_ssl_context();
|
||||
cleanup_ssl_context(YSSL_CLIENT);
|
||||
cleanup_ssl_context(YSSL_SERVER);
|
||||
#endif
|
||||
|
||||
this->state_ = io_service::state::AT_EXITING;
|
||||
|
@ -974,7 +975,8 @@ void io_service::process_transports(fd_set_adapter& fd_set)
|
|||
++iter;
|
||||
continue;
|
||||
}
|
||||
shutdown_internal(transport);
|
||||
if (transport->error_ == 0)
|
||||
transport->error_ = yasio::errc::shutdown_by_localhost;
|
||||
}
|
||||
|
||||
handle_close(transport);
|
||||
|
@ -1081,15 +1083,25 @@ bool io_service::open(size_t index, int kind)
|
|||
io_channel* io_service::channel_at(size_t index) const { return (index < channels_.size()) ? channels_[index] : nullptr; }
|
||||
void io_service::handle_close(transport_handle_t thandle)
|
||||
{
|
||||
auto ctx = thandle->ctx_;
|
||||
auto ec = thandle->error_;
|
||||
// @Because we can't retrive peer endpoint when connect reset by peer, so use id to trace.
|
||||
YASIO_KLOGD("[index: %d] the connection #%u is lost, ec=%d, where=%d, detail:%s", ctx->index_, thandle->id_, ec, (int)thandle->error_stage_,
|
||||
io_service::strerror(ec));
|
||||
this->fire_event(thandle->cindex(), YEK_ON_CLOSE, ec, thandle);
|
||||
auto ctx = thandle->ctx_;
|
||||
auto error = thandle->error_;
|
||||
const bool client = yasio__testbits(ctx->properties_, YCM_CLIENT);
|
||||
|
||||
if (thandle->state_ == io_base::state::OPENED)
|
||||
{ // @Because we can't retrive peer endpoint when connect reset by peer, so use id to trace.
|
||||
YASIO_KLOGD("[index: %d] the connection #%u is lost, ec=%d, where=%d, detail:%s", ctx->index_, thandle->id_, error, (int)thandle->error_stage_,
|
||||
io_service::strerror(error));
|
||||
this->fire_event(ctx->index(), YEK_ON_CLOSE, error, thandle);
|
||||
}
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
if (yasio__testbits(ctx->properties_, YCM_SSL))
|
||||
static_cast<io_transport_ssl*>(thandle)->do_ssl_shutdown();
|
||||
#endif
|
||||
if (yasio__testbits(ctx->properties_, YCM_TCP) && error == yasio::errc::shutdown_by_localhost)
|
||||
thandle->socket_->shutdown();
|
||||
cleanup_io(thandle);
|
||||
deallocate_transport(thandle);
|
||||
if (yasio__testbits(ctx->properties_, YCM_CLIENT))
|
||||
if (client)
|
||||
{
|
||||
yasio__clearbits(ctx->opmask_, YOPM_CLOSE);
|
||||
cleanup_channel(ctx, false);
|
||||
|
@ -1098,7 +1110,7 @@ void io_service::handle_close(transport_handle_t thandle)
|
|||
void io_service::register_descriptor(const socket_native_type fd, int events) { this->fd_set_.set(fd, events); }
|
||||
void io_service::deregister_descriptor(const socket_native_type fd, int events) { this->fd_set_.unset(fd, events); }
|
||||
|
||||
int io_service::write(transport_handle_t transport, dynamic_buffer_t buffer, completion_cb_t handler)
|
||||
int io_service::write(transport_handle_t transport, sbyte_buffer buffer, completion_cb_t handler)
|
||||
{
|
||||
if (transport && transport->is_open())
|
||||
return !buffer.empty() ? transport->write(std::move(buffer), std::move(handler)) : 0;
|
||||
|
@ -1108,7 +1120,7 @@ int io_service::write(transport_handle_t transport, dynamic_buffer_t buffer, com
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
int io_service::write_to(transport_handle_t transport, dynamic_buffer_t buffer, const ip::endpoint& to, completion_cb_t handler)
|
||||
int io_service::write_to(transport_handle_t transport, sbyte_buffer buffer, const ip::endpoint& to, completion_cb_t handler)
|
||||
{
|
||||
if (transport && transport->is_open())
|
||||
return !buffer.empty() ? transport->write_to(std::move(buffer), to, std::move(handler)) : 0;
|
||||
|
@ -1189,10 +1201,9 @@ void io_service::do_connect_completion(io_channel* ctx, fd_set_adapter& fd_set)
|
|||
assert(ctx->state_ == io_base::state::CONNECTING);
|
||||
if (ctx->state_ == io_base::state::CONNECTING)
|
||||
{
|
||||
int error = -1;
|
||||
#if !defined(YASIO_SSL_BACKEND)
|
||||
if (fd_set.is_set(ctx->socket_->native_handle(), socket_event::readwrite))
|
||||
{
|
||||
int error = -1;
|
||||
if (ctx->socket_->get_optval(SOL_SOCKET, SO_ERROR, error) >= 0 && error == 0)
|
||||
{
|
||||
// The nonblocking tcp handshake complete, remove write event avoid high-CPU occupation
|
||||
|
@ -1203,188 +1214,21 @@ void io_service::do_connect_completion(io_channel* ctx, fd_set_adapter& fd_set)
|
|||
handle_connect_failed(ctx, error);
|
||||
ctx->timer_.cancel(*this);
|
||||
}
|
||||
#else
|
||||
if (!yasio__testbits(ctx->properties_, YCPF_SSL_HANDSHAKING))
|
||||
{
|
||||
if (fd_set.is_set(ctx->socket_->native_handle(), socket_event::readwrite))
|
||||
{
|
||||
if (ctx->socket_->get_optval(SOL_SOCKET, SO_ERROR, error) >= 0 && error == 0)
|
||||
{
|
||||
// The nonblocking tcp handshake complete, remove write event avoid high-CPU occupation
|
||||
deregister_descriptor(ctx->socket_->native_handle(), socket_event::write);
|
||||
if (!yasio__testbits(ctx->properties_, YCM_SSL))
|
||||
handle_connect_succeed(ctx, ctx->socket_);
|
||||
else
|
||||
do_ssl_handshake(ctx);
|
||||
}
|
||||
else
|
||||
handle_connect_failed(ctx, error);
|
||||
}
|
||||
}
|
||||
else
|
||||
do_ssl_handshake(ctx);
|
||||
if (ctx->state_ != io_base::state::CONNECTING)
|
||||
ctx->timer_.cancel(*this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
void io_service::init_ssl_context()
|
||||
SSL_CTX* io_service::init_ssl_context(ssl_role role)
|
||||
{
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
# if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
auto req_method = ::TLS_client_method();
|
||||
# else
|
||||
auto req_method = ::SSLv23_client_method();
|
||||
# endif
|
||||
ssl_ctx_ = ::SSL_CTX_new(req_method);
|
||||
|
||||
# if defined(SSL_MODE_RELEASE_BUFFERS)
|
||||
::SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS);
|
||||
# endif
|
||||
|
||||
::SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
if (!this->options_.cafile_.empty())
|
||||
{
|
||||
if (::SSL_CTX_load_verify_locations(ssl_ctx_, this->options_.cafile_.c_str(), nullptr) == 1)
|
||||
{
|
||||
::SSL_CTX_set_verify(ssl_ctx_, SSL_VERIFY_PEER, ::SSL_CTX_get_verify_callback(ssl_ctx_));
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x10101000L
|
||||
::SSL_CTX_set_post_handshake_auth(ssl_ctx_, 1);
|
||||
# endif
|
||||
# if defined(X509_V_FLAG_PARTIAL_CHAIN)
|
||||
/* Have intermediate certificates in the trust store be treated as
|
||||
trust-anchors, in the same way as self-signed root CA certificates
|
||||
are. This allows users to verify servers using the intermediate cert
|
||||
only, instead of needing the whole chain. */
|
||||
X509_STORE_set_flags(SSL_CTX_get_cert_store(ssl_ctx_), X509_V_FLAG_PARTIAL_CHAIN);
|
||||
# endif
|
||||
}
|
||||
else
|
||||
YASIO_KLOGE("[global] load ca certifaction file failed!");
|
||||
}
|
||||
else
|
||||
SSL_CTX_set_verify(ssl_ctx_, SSL_VERIFY_NONE, nullptr);
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
ssl_ctx_ = new SSL_CTX();
|
||||
::mbedtls_ssl_config_init(&ssl_ctx_->conf);
|
||||
::mbedtls_x509_crt_init(&ssl_ctx_->cacert);
|
||||
::mbedtls_ctr_drbg_init(&ssl_ctx_->ctr_drbg);
|
||||
::mbedtls_entropy_init(&ssl_ctx_->entropy);
|
||||
cxx17::string_view pers{YASIO_SSL_PIN, YASIO_SSL_PIN_LEN};
|
||||
int ret = ::mbedtls_ctr_drbg_seed(&ssl_ctx_->ctr_drbg, ::mbedtls_entropy_func, &ssl_ctx_->entropy, (const unsigned char*)pers.data(), pers.length());
|
||||
if (ret != 0)
|
||||
YASIO_KLOGE("mbedtls_ctr_drbg_seed fail with ret=%d", ret);
|
||||
|
||||
int authmode = MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
if (!this->options_.cafile_.empty()) // the cafile_ must be full path
|
||||
{
|
||||
if ((ret = ::mbedtls_x509_crt_parse_file(&ssl_ctx_->cacert, this->options_.cafile_.c_str())) == 0)
|
||||
authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
else
|
||||
YASIO_KLOGE("mbedtls_x509_crt_parse_file with ret=-0x%x", (unsigned int)-ret);
|
||||
}
|
||||
|
||||
if ((ret = ::mbedtls_ssl_config_defaults(&ssl_ctx_->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
|
||||
YASIO_KLOGE("mbedtls_ssl_config_defaults fail with ret=%d", ret);
|
||||
|
||||
::mbedtls_ssl_conf_authmode(&ssl_ctx_->conf, authmode);
|
||||
::mbedtls_ssl_conf_ca_chain(&ssl_ctx_->conf, &ssl_ctx_->cacert, nullptr);
|
||||
::mbedtls_ssl_conf_rng(&ssl_ctx_->conf, ::mbedtls_ctr_drbg_random, &ssl_ctx_->ctr_drbg);
|
||||
# endif
|
||||
auto ctx = role == YSSL_CLIENT ? yssl_ctx_new(yssl_options{options_.cafile_.c_str(), nullptr, true})
|
||||
: yssl_ctx_new(yssl_options{options_.crtfile_.c_str(), options_.keyfile_.c_str(), false});
|
||||
ssl_roles_[role] = ctx;
|
||||
return ctx;
|
||||
}
|
||||
void io_service::cleanup_ssl_context()
|
||||
void io_service::cleanup_ssl_context(ssl_role role)
|
||||
{
|
||||
if (ssl_ctx_)
|
||||
{
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
SSL_CTX_free((SSL_CTX*)ssl_ctx_);
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
::mbedtls_x509_crt_free(&ssl_ctx_->cacert);
|
||||
::mbedtls_ssl_config_free(&ssl_ctx_->conf);
|
||||
::mbedtls_ctr_drbg_free(&ssl_ctx_->ctr_drbg);
|
||||
::mbedtls_entropy_free(&ssl_ctx_->entropy);
|
||||
delete ssl_ctx_;
|
||||
# endif
|
||||
ssl_ctx_ = nullptr;
|
||||
}
|
||||
}
|
||||
void io_service::do_ssl_handshake(io_channel* ctx)
|
||||
{
|
||||
if (!ctx->ssl_)
|
||||
{
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
auto ssl = ::SSL_new(ssl_ctx_);
|
||||
::SSL_set_fd(ssl, static_cast<int>(ctx->socket_->native_handle()));
|
||||
::SSL_set_connect_state(ssl);
|
||||
::SSL_set_tlsext_host_name(ssl, ctx->remote_host_.c_str());
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
auto ssl = ::mbedtls_ssl_new(ssl_ctx_);
|
||||
::mbedtls_ssl_set_fd(ssl, static_cast<int>(ctx->socket_->native_handle()));
|
||||
::mbedtls_ssl_set_hostname(ssl, ctx->remote_host_.c_str());
|
||||
# endif
|
||||
yasio__setbits(ctx->properties_, YCPF_SSL_HANDSHAKING); // start ssl handshake
|
||||
ctx->ssl_.reset(ssl);
|
||||
}
|
||||
|
||||
# if YASIO_SSL_BACKEND == 1
|
||||
int ret = ::SSL_do_handshake(ctx->ssl_);
|
||||
if (ret != 1)
|
||||
{
|
||||
int status = ::SSL_get_error(ctx->ssl_, ret);
|
||||
/*
|
||||
When using a non-blocking socket, nothing is to be done, but select() can be used to check for
|
||||
the required condition: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
|
||||
*/
|
||||
if (status == SSL_ERROR_WANT_READ || status == SSL_ERROR_WANT_WRITE)
|
||||
return;
|
||||
# if defined(SSL_ERROR_WANT_ASYNC)
|
||||
if (status == SSL_ERROR_WANT_ASYNC)
|
||||
return;
|
||||
# endif
|
||||
int error = static_cast<int>(ERR_get_error());
|
||||
if (error)
|
||||
{
|
||||
char errstring[256] = {0};
|
||||
ERR_error_string_n(error, errstring, sizeof(errstring));
|
||||
YASIO_KLOGE("[index: %d] SSL_do_handshake fail with ret=%d,error=%X, detail:%s", ctx->index_, ret, error, errstring);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = xxsocket::get_last_errno();
|
||||
YASIO_KLOGE("[index: %d] SSL_do_handshake fail with ret=%d,status=%d, error=%d, detail:%s", ctx->index_, ret, status, error, xxsocket::strerror(error));
|
||||
}
|
||||
ctx->ssl_.destroy();
|
||||
handle_connect_failed(ctx, yasio::errc::ssl_handshake_failed);
|
||||
}
|
||||
else
|
||||
handle_connect_succeed(ctx, ctx->socket_);
|
||||
# elif YASIO_SSL_BACKEND == 2
|
||||
auto ssl = static_cast<SSL*>(ctx->ssl_);
|
||||
int ret = ::mbedtls_ssl_handshake_step(ssl);
|
||||
if (ret == 0)
|
||||
{
|
||||
if (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER)
|
||||
interrupt();
|
||||
else // mbedtls_ssl_get_verify_result return 0 when valid cacert provided
|
||||
handle_connect_succeed(ctx, ctx->socket_);
|
||||
}
|
||||
else
|
||||
{
|
||||
char errstring[256] = {0};
|
||||
switch (ret)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
break; // Nothing need to do
|
||||
default:
|
||||
::mbedtls_strerror(ret, errstring, sizeof(errstring));
|
||||
YASIO_KLOGE("[index: %d] mbedtls_ssl_handshake_step fail with ret=%d, detail:%s", ctx->index_, ret, errstring);
|
||||
ctx->ssl_.destroy();
|
||||
handle_connect_failed(ctx, yasio::errc::ssl_handshake_failed);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
auto& ctx = ssl_roles_[role];
|
||||
if (ctx)
|
||||
yssl_ctx_free(ctx);
|
||||
}
|
||||
#endif
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
|
@ -1425,33 +1269,39 @@ void io_service::ares_getaddrinfo_cb(void* arg, int status, int /*timeouts*/, ar
|
|||
}
|
||||
current_service.interrupt();
|
||||
}
|
||||
int io_service::register_ares_fds(socket_native_type* ares_socks, fd_set_adapter& fd_set)
|
||||
int io_service::do_ares_fds(socket_native_type* socks, fd_set_adapter& fd_set, timeval& waitd_tv)
|
||||
{
|
||||
int count = 0;
|
||||
int bitmask = ::ares_getsock(this->ares_, ares_socks, ARES_GETSOCK_MAXNUM);
|
||||
for (int i = 0; i < ARES_GETSOCK_MAXNUM; ++i)
|
||||
int nfds = 0;
|
||||
if (ares_outstanding_work_)
|
||||
{
|
||||
if (ARES_GETSOCK_READABLE(bitmask, i) || ARES_GETSOCK_WRITABLE(bitmask, i))
|
||||
int bitmask = ::ares_getsock(this->ares_, socks, ARES_GETSOCK_MAXNUM);
|
||||
for (int i = 0; i < ARES_GETSOCK_MAXNUM; ++i)
|
||||
{
|
||||
auto fd = ares_socks[i];
|
||||
++count;
|
||||
fd_set.set(fd, socket_event::readwrite);
|
||||
int events = socket_event::null;
|
||||
if (ARES_GETSOCK_READABLE(bitmask, i))
|
||||
events |= socket_event::read;
|
||||
if (ARES_GETSOCK_WRITABLE(bitmask, i))
|
||||
events |= socket_event::write;
|
||||
if (events)
|
||||
{
|
||||
++nfds;
|
||||
fd_set.set(socks[i], events);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
if (nfds)
|
||||
::ares_timeout(this->ares_, &waitd_tv, &waitd_tv);
|
||||
}
|
||||
return count;
|
||||
return nfds;
|
||||
}
|
||||
void io_service::process_ares_requests(socket_native_type* socks, int count, fd_set_adapter& fd_set)
|
||||
void io_service::do_ares_process_fds(socket_native_type* socks, int nfds, fd_set_adapter& fd_set)
|
||||
{
|
||||
if (this->ares_outstanding_work_ > 0)
|
||||
for (auto i = 0; i < nfds; ++i)
|
||||
{
|
||||
for (auto i = 0; i < count; ++i)
|
||||
{
|
||||
auto fd = socks[i];
|
||||
::ares_process_fd(this->ares_, fd_set.is_set(fd, socket_event::read) ? fd : ARES_SOCKET_BAD,
|
||||
fd_set.is_set(fd, socket_event::write) ? fd : ARES_SOCKET_BAD);
|
||||
}
|
||||
auto fd = socks[i];
|
||||
::ares_process_fd(this->ares_, fd_set.is_set(fd, socket_event::read) ? fd : ARES_SOCKET_BAD, fd_set.is_set(fd, socket_event::write) ? fd : ARES_SOCKET_BAD);
|
||||
}
|
||||
}
|
||||
void io_service::recreate_ares_channel()
|
||||
|
@ -1668,7 +1518,7 @@ transport_handle_t io_service::do_dgram_accept(io_channel* ctx, const ip::endpoi
|
|||
// We always establish 4 tuple with clients
|
||||
transport->confgure_remote(peer);
|
||||
if (user_route)
|
||||
notify_connect_succeed(transport);
|
||||
active_transport(transport);
|
||||
else
|
||||
handle_connect_succeed(transport);
|
||||
return transport;
|
||||
|
@ -1705,18 +1555,23 @@ void io_service::handle_connect_succeed(transport_handle_t transport)
|
|||
connection->set_keepalive(options_.tcp_keepalive_.onoff, options_.tcp_keepalive_.idle, options_.tcp_keepalive_.interval, options_.tcp_keepalive_.probs);
|
||||
}
|
||||
|
||||
notify_connect_succeed(transport);
|
||||
active_transport(transport);
|
||||
}
|
||||
void io_service::notify_connect_succeed(transport_handle_t t)
|
||||
void io_service::active_transport(transport_handle_t t)
|
||||
{
|
||||
auto ctx = t->ctx_;
|
||||
auto& s = t->socket_;
|
||||
this->transports_.push_back(t);
|
||||
YASIO__UNUSED_PARAM(s);
|
||||
YASIO_KLOGV("[index: %d] sndbuf=%d, rcvbuf=%d", ctx->index_, s->get_optval<int>(SOL_SOCKET, SO_SNDBUF), s->get_optval<int>(SOL_SOCKET, SO_RCVBUF));
|
||||
YASIO_KLOGD("[index: %d] the connection #%u <%s> --> <%s> is established.", ctx->index_, t->id_, t->local_endpoint().to_string().c_str(),
|
||||
t->remote_endpoint().to_string().c_str());
|
||||
this->fire_event(ctx->index_, YEK_ON_OPEN, 0, t);
|
||||
if (!yasio__testbits(ctx->properties_, YCM_SSL))
|
||||
{
|
||||
YASIO__UNUSED_PARAM(s);
|
||||
YASIO_KLOGV("[index: %d] sndbuf=%d, rcvbuf=%d", ctx->index_, s->get_optval<int>(SOL_SOCKET, SO_SNDBUF), s->get_optval<int>(SOL_SOCKET, SO_RCVBUF));
|
||||
YASIO_KLOGD("[index: %d] the connection #%u <%s> --> <%s> is established.", ctx->index_, t->id_, t->local_endpoint().to_string().c_str(),
|
||||
t->remote_endpoint().to_string().c_str());
|
||||
this->fire_event(ctx->index_, YEK_ON_OPEN, 0, t);
|
||||
}
|
||||
else if (yasio__testbits(ctx->properties_, YCM_CLIENT))
|
||||
this->interrupt();
|
||||
}
|
||||
transport_handle_t io_service::allocate_transport(io_channel* ctx, xxsocket_ptr&& s)
|
||||
{
|
||||
|
@ -1836,7 +1691,7 @@ void io_service::unpack(transport_handle_t transport, int bytes_expected, int by
|
|||
if (offset > 0)
|
||||
{ /* move remain data to head of buffer and hold 'offset'. */
|
||||
::memmove(transport->buffer_, transport->buffer_ + bytes_expected, offset);
|
||||
this->wait_duration_ = yasio__min_wait_duration;
|
||||
this->wait_duration_ = yasio__min_wait_usec;
|
||||
}
|
||||
// move properly pdu to ready queue, the other thread who care about will retrieve it.
|
||||
YASIO_KLOGV("[index: %d] received a properly packet from peer, packet size:%d", transport->cindex(), transport->expected_size_);
|
||||
|
@ -1909,13 +1764,6 @@ bool io_service::open_internal(io_channel* ctx)
|
|||
this->interrupt();
|
||||
return true;
|
||||
}
|
||||
void io_service::shutdown_internal(transport_handle_t transport)
|
||||
{
|
||||
if (transport->error_ == 0)
|
||||
transport->error_ = yasio::errc::shutdown_by_localhost;
|
||||
if (yasio__testbits(transport->ctx_->properties_, YCM_TCP))
|
||||
transport->socket_->shutdown();
|
||||
}
|
||||
bool io_service::close_internal(io_channel* ctx)
|
||||
{
|
||||
yasio__clearbits(ctx->opmask_, YOPM_OPEN);
|
||||
|
@ -1973,9 +1821,6 @@ highp_time_t io_service::get_timeout(highp_time_t usec)
|
|||
}
|
||||
bool io_service::cleanup_channel(io_channel* ctx, bool clear_mask)
|
||||
{
|
||||
#if YASIO_SSL_BACKEND != 0
|
||||
ctx->ssl_.destroy();
|
||||
#endif
|
||||
ctx->clear_mutable_flags();
|
||||
bool bret = cleanup_io(ctx, clear_mask);
|
||||
#if defined(YAISO_ENABLE_PASSIVE_EVENT)
|
||||
|
@ -2238,9 +2083,21 @@ void io_service::set_option_internal(int opt, va_list ap) // lgtm [cpp/poorly-do
|
|||
options_.dns_dirty_ = true;
|
||||
break;
|
||||
#endif
|
||||
case YOPT_S_EVENT_CB:
|
||||
options_.on_event_ = *va_arg(ap, event_cb_t*);
|
||||
break;
|
||||
case YOPT_S_DEFER_EVENT_CB:
|
||||
options_.on_defer_event_ = *va_arg(ap, defer_event_cb_t*);
|
||||
break;
|
||||
case YOPT_S_FORWARD_EVENT:
|
||||
options_.forward_event_ = !!va_arg(ap, int);
|
||||
break;
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
case YOPT_S_SSL_CERT:
|
||||
options_.crtfile_ = va_arg(ap, const char*);
|
||||
options_.keyfile_ = va_arg(ap, const char*);
|
||||
break;
|
||||
#endif
|
||||
case YOPT_C_UNPACK_PARAMS: {
|
||||
auto channel = channel_at(static_cast<size_t>(va_arg(ap, int)));
|
||||
if (channel)
|
||||
|
@ -2264,12 +2121,6 @@ void io_service::set_option_internal(int opt, va_list ap) // lgtm [cpp/poorly-do
|
|||
channel->uparams_.no_bswap = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
case YOPT_S_EVENT_CB:
|
||||
options_.on_event_ = *va_arg(ap, event_cb_t*);
|
||||
break;
|
||||
case YOPT_S_DEFER_EVENT_CB:
|
||||
options_.on_defer_event_ = *va_arg(ap, defer_event_cb_t*);
|
||||
break;
|
||||
case YOPT_C_LFBFD_FN: {
|
||||
auto channel = channel_at(static_cast<size_t>(va_arg(ap, int)));
|
||||
if (channel)
|
||||
|
|
|
@ -49,12 +49,12 @@ SOFTWARE.
|
|||
#include "yasio/detail/errc.hpp"
|
||||
#include "yasio/detail/byte_buffer.hpp"
|
||||
#include "yasio/detail/fd_set_adapter.hpp"
|
||||
#include "yasio/cxx17/memory.hpp"
|
||||
#include "yasio/cxx17/string_view.hpp"
|
||||
#include "yasio/stl/memory.hpp"
|
||||
#include "yasio/stl/string_view.hpp"
|
||||
#include "yasio/xxsocket.hpp"
|
||||
|
||||
#if !defined(YASIO_HAVE_CARES)
|
||||
# include "yasio/cxx17/shared_mutex.hpp"
|
||||
# include "yasio/stl/shared_mutex.hpp"
|
||||
#endif
|
||||
|
||||
#if defined(YASIO_HAVE_KCP)
|
||||
|
@ -180,6 +180,12 @@ enum
|
|||
// when forward event enabled, the option YOPT_S_DEFERRED_EVENT was ignored
|
||||
YOPT_S_FORWARD_EVENT,
|
||||
|
||||
// Set ssl server cert and private key file
|
||||
// params:
|
||||
// crtfile: const char*
|
||||
// keyfile: const char*
|
||||
YOPT_S_SSL_CERT,
|
||||
|
||||
// Sets channel length field based frame decode function, native C++ ONLY
|
||||
// params: index:int, func:decode_len_fn_t*
|
||||
YOPT_C_UNPACK_FN = 101,
|
||||
|
@ -291,7 +297,8 @@ enum
|
|||
YCK_UDP_SERVER = YCM_UDP | YCM_SERVER,
|
||||
YCK_KCP_CLIENT = YCM_KCP | YCM_CLIENT | YCM_UDP,
|
||||
YCK_KCP_SERVER = YCM_KCP | YCM_SERVER | YCM_UDP,
|
||||
YCK_SSL_CLIENT = YCM_SSL | YCM_CLIENT | YCM_TCP,
|
||||
YCK_SSL_CLIENT = YCK_TCP_CLIENT | YCM_SSL,
|
||||
YCK_SSL_SERVER = YCK_TCP_SERVER | YCM_SSL,
|
||||
};
|
||||
|
||||
// channel flags
|
||||
|
@ -368,14 +375,17 @@ typedef highp_timer_ptr deadline_timer_ptr;
|
|||
typedef event_cb_t io_event_cb_t;
|
||||
typedef completion_cb_t io_completion_cb_t;
|
||||
|
||||
typedef sbyte_buffer dynamic_buffer_t;
|
||||
|
||||
inline dynamic_buffer_t make_dynamic_buffer(const void* p, size_t n) { return dynamic_buffer_t{(const char*)p, (const char*)p + n, std::true_type{}}; }
|
||||
// the ssl role
|
||||
enum ssl_role
|
||||
{
|
||||
YSSL_CLIENT,
|
||||
YSSL_SERVER,
|
||||
};
|
||||
|
||||
struct io_hostent {
|
||||
io_hostent() = default;
|
||||
io_hostent(cxx17::string_view ip, u_short port) : host_(cxx17::svtos(ip)), port_(port) {}
|
||||
io_hostent(io_hostent&& rhs) : host_(std::move(rhs.host_)), port_(rhs.port_) {}
|
||||
io_hostent(io_hostent&& rhs) YASIO__NOEXCEPT : host_(std::move(rhs.host_)), port_(rhs.port_) {}
|
||||
io_hostent(const io_hostent& rhs) : host_(rhs.host_), port_(rhs.port_) {}
|
||||
void set_ip(cxx17::string_view ip) { cxx17::assign(host_, ip); }
|
||||
const std::string& get_ip() const { return host_; }
|
||||
|
@ -483,37 +493,6 @@ public:
|
|||
unsigned int id() const { return id_; }
|
||||
};
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
class ssl_auto_handle {
|
||||
public:
|
||||
ssl_auto_handle() : ssl_(nullptr) {}
|
||||
~ssl_auto_handle() { destroy(); }
|
||||
ssl_auto_handle(ssl_auto_handle&& rhs) : ssl_(rhs.release()) {}
|
||||
ssl_auto_handle& operator=(ssl_auto_handle&& rhs)
|
||||
{
|
||||
this->reset(rhs.release());
|
||||
return *this;
|
||||
}
|
||||
SSL* release()
|
||||
{
|
||||
auto tmp = ssl_;
|
||||
ssl_ = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
void reset(SSL* ssl)
|
||||
{
|
||||
if (ssl_)
|
||||
destroy();
|
||||
ssl_ = ssl;
|
||||
}
|
||||
operator SSL*() { return ssl_; }
|
||||
YASIO__DECL void destroy();
|
||||
|
||||
protected:
|
||||
SSL* ssl_ = nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
class YASIO_API io_channel : public io_base {
|
||||
friend class io_service;
|
||||
friend class io_transport;
|
||||
|
@ -524,6 +503,9 @@ class YASIO_API io_channel : public io_base {
|
|||
|
||||
public:
|
||||
io_service& get_service() const { return service_; }
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
YASIO__DECL SSL_CTX* get_ssl_context(bool client) const;
|
||||
#endif
|
||||
int index() const { return index_; }
|
||||
u_short remote_port() const { return remote_port_; }
|
||||
YASIO__DECL std::string format_destination() const;
|
||||
|
@ -626,7 +608,7 @@ private:
|
|||
ip::endpoint multiaddr_, multiif_;
|
||||
|
||||
// Current it's only for UDP
|
||||
dynamic_buffer_t buffer_;
|
||||
sbyte_buffer buffer_;
|
||||
|
||||
// The bytes transferred from socket low layer, currently, only works for client channel
|
||||
long long bytes_transferred_ = 0;
|
||||
|
@ -636,23 +618,19 @@ private:
|
|||
#if defined(YASIO_HAVE_KCP)
|
||||
int kcp_conv_ = 0;
|
||||
#endif
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
ssl_auto_handle ssl_;
|
||||
#endif
|
||||
};
|
||||
|
||||
// for tcp transport only
|
||||
class YASIO_API io_send_op {
|
||||
public:
|
||||
io_send_op(dynamic_buffer_t&& buffer, completion_cb_t&& handler) : offset_(0), buffer_(std::move(buffer)), handler_(std::move(handler)) {}
|
||||
io_send_op(sbyte_buffer&& buffer, completion_cb_t&& handler) : offset_(0), buffer_(std::move(buffer)), handler_(std::move(handler)) {}
|
||||
virtual ~io_send_op() {}
|
||||
|
||||
size_t offset_; // read pos from sending buffer
|
||||
dynamic_buffer_t buffer_; // sending data buffer
|
||||
size_t offset_; // read pos from sending buffer
|
||||
sbyte_buffer buffer_; // sending data buffer
|
||||
completion_cb_t handler_;
|
||||
|
||||
YASIO__DECL virtual int perform(transport_handle_t transport, const void* buf, int n);
|
||||
YASIO__DECL virtual int perform(transport_handle_t transport, const void* buf, int n, int& error);
|
||||
|
||||
#if !defined(YASIO_DISABLE_OBJECT_POOL)
|
||||
DEFINE_CONCURRENT_OBJECT_POOL_ALLOCATION(io_send_op, 512)
|
||||
|
@ -662,11 +640,11 @@ public:
|
|||
// for udp transport only
|
||||
class YASIO_API io_sendto_op : public io_send_op {
|
||||
public:
|
||||
io_sendto_op(dynamic_buffer_t&& buffer, completion_cb_t&& handler, const ip::endpoint& destination)
|
||||
io_sendto_op(sbyte_buffer&& buffer, completion_cb_t&& handler, const ip::endpoint& destination)
|
||||
: io_send_op(std::move(buffer), std::move(handler)), destination_(destination)
|
||||
{}
|
||||
|
||||
YASIO__DECL int perform(transport_handle_t transport, const void* buf, int n) override;
|
||||
YASIO__DECL int perform(transport_handle_t transport, const void* buf, int n, int& error) override;
|
||||
#if !defined(YASIO_DISABLE_OBJECT_POOL)
|
||||
DEFINE_CONCURRENT_OBJECT_POOL_ALLOCATION(io_sendto_op, 512)
|
||||
#endif
|
||||
|
@ -698,7 +676,7 @@ public:
|
|||
protected:
|
||||
io_service& get_service() const { return ctx_->get_service(); }
|
||||
bool is_open() const { return state_ == state::OPENED && socket_ && socket_->is_open(); }
|
||||
dynamic_buffer_t fetch_packet()
|
||||
sbyte_buffer fetch_packet()
|
||||
{
|
||||
expected_size_ = -1;
|
||||
return std::move(expected_packet_);
|
||||
|
@ -708,16 +686,16 @@ protected:
|
|||
YASIO__DECL const print_fn2_t& __get_cprint() const;
|
||||
|
||||
// Call at user thread
|
||||
YASIO__DECL virtual int write(dynamic_buffer_t&&, completion_cb_t&&);
|
||||
YASIO__DECL virtual int write(sbyte_buffer&&, completion_cb_t&&);
|
||||
|
||||
// Call at user thread
|
||||
virtual int write_to(dynamic_buffer_t&&, const ip::endpoint&, completion_cb_t&&)
|
||||
virtual int write_to(sbyte_buffer&&, const ip::endpoint&, completion_cb_t&&)
|
||||
{
|
||||
YASIO_LOG("[warning] io_transport doesn't support 'write_to' operation!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
YASIO__DECL int call_read(void* data, int size, int& error);
|
||||
YASIO__DECL int call_read(void* data, int size, int revent, int& error);
|
||||
YASIO__DECL int call_write(io_send_op*, int& error);
|
||||
YASIO__DECL void complete_op(io_send_op*, int error);
|
||||
|
||||
|
@ -738,12 +716,12 @@ protected:
|
|||
int offset_ = 0; // recv buffer offset
|
||||
|
||||
int expected_size_ = -1;
|
||||
dynamic_buffer_t expected_packet_;
|
||||
sbyte_buffer expected_packet_;
|
||||
|
||||
io_channel* ctx_;
|
||||
|
||||
std::function<int(const void*, int, const ip::endpoint*)> write_cb_;
|
||||
std::function<int(void*, int)> read_cb_;
|
||||
std::function<int(const void*, int, const ip::endpoint*, int&)> write_cb_;
|
||||
std::function<int(void*, int, int, int&)> read_cb_;
|
||||
|
||||
privacy::concurrent_queue<send_op_ptr> send_queue_;
|
||||
};
|
||||
|
@ -760,10 +738,11 @@ public:
|
|||
YASIO__DECL io_transport_ssl(io_channel* ctx, xxsocket_ptr&& s);
|
||||
YASIO__DECL void set_primitives() override;
|
||||
|
||||
# if defined(YASIO_SSL_BACKEND)
|
||||
YASIO__DECL void do_ssl_shutdown();
|
||||
|
||||
protected:
|
||||
ssl_auto_handle ssl_;
|
||||
# endif
|
||||
YASIO__DECL int do_ssl_handshake(int& error); // always invoke at do_read
|
||||
SSL* ssl_ = nullptr;
|
||||
};
|
||||
#else
|
||||
class io_transport_ssl {};
|
||||
|
@ -781,8 +760,8 @@ protected:
|
|||
YASIO__DECL void connect();
|
||||
YASIO__DECL void disconnect();
|
||||
|
||||
YASIO__DECL int write(dynamic_buffer_t&&, completion_cb_t&&) override;
|
||||
YASIO__DECL int write_to(dynamic_buffer_t&&, const ip::endpoint&, completion_cb_t&&) override;
|
||||
YASIO__DECL int write(sbyte_buffer&&, completion_cb_t&&) override;
|
||||
YASIO__DECL int write_to(sbyte_buffer&&, const ip::endpoint&, completion_cb_t&&) override;
|
||||
|
||||
YASIO__DECL void set_primitives() override;
|
||||
|
||||
|
@ -807,7 +786,7 @@ public:
|
|||
ikcpcb* internal_object() { return kcp_; }
|
||||
|
||||
protected:
|
||||
YASIO__DECL int write(dynamic_buffer_t&&, completion_cb_t&&) override;
|
||||
YASIO__DECL int write(sbyte_buffer&&, completion_cb_t&&) override;
|
||||
|
||||
YASIO__DECL int do_read(int revent, int& error, highp_time_t& wait_duration) override;
|
||||
YASIO__DECL bool do_write(highp_time_t& wait_duration) override;
|
||||
|
@ -816,7 +795,7 @@ protected:
|
|||
|
||||
YASIO__DECL void check_timeout(highp_time_t& wait_duration) const;
|
||||
|
||||
dynamic_buffer_t rawbuf_; // the low level raw buffer
|
||||
sbyte_buffer rawbuf_; // the low level raw buffer
|
||||
ikcpcb* kcp_;
|
||||
std::recursive_mutex send_mtx_;
|
||||
};
|
||||
|
@ -824,7 +803,7 @@ protected:
|
|||
class io_transport_kcp {};
|
||||
#endif
|
||||
|
||||
using io_packet = dynamic_buffer_t;
|
||||
using io_packet = sbyte_buffer;
|
||||
#if !defined(YASIO_USE_SHARED_PACKET)
|
||||
using packet_t = io_packet;
|
||||
inline packet_t wrap_packet(io_packet& raw_packet) { return std::move(raw_packet); }
|
||||
|
@ -959,6 +938,9 @@ class YASIO_API io_service // lgtm [cpp/class-many-fields]
|
|||
friend class io_transport_tcp;
|
||||
friend class io_transport_udp;
|
||||
friend class io_transport_kcp;
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
friend class io_transport_ssl;
|
||||
#endif
|
||||
friend class io_channel;
|
||||
|
||||
public:
|
||||
|
@ -1041,9 +1023,9 @@ public:
|
|||
*/
|
||||
int write(transport_handle_t thandle, const void* buf, size_t len, completion_cb_t completion_handler = nullptr)
|
||||
{
|
||||
return write(thandle, make_dynamic_buffer(buf, len), std::move(completion_handler));
|
||||
return write(thandle, sbyte_buffer{(const char*)buf, (const char*)buf + len, std::true_type{}}, std::move(completion_handler));
|
||||
}
|
||||
YASIO__DECL int write(transport_handle_t thandle, dynamic_buffer_t buffer, completion_cb_t completion_handler = nullptr);
|
||||
YASIO__DECL int write(transport_handle_t thandle, sbyte_buffer buffer, completion_cb_t completion_handler = nullptr);
|
||||
|
||||
/*
|
||||
** Summary: Write data to unconnected UDP transport with specified address.
|
||||
|
@ -1054,9 +1036,9 @@ public:
|
|||
*/
|
||||
int write_to(transport_handle_t thandle, const void* buf, size_t len, const ip::endpoint& to, completion_cb_t completion_handler = nullptr)
|
||||
{
|
||||
return write_to(thandle, make_dynamic_buffer(buf, len), to, std::move(completion_handler));
|
||||
return write_to(thandle, sbyte_buffer{(const char*)buf, (const char*)buf + len, std::true_type{}}, to, std::move(completion_handler));
|
||||
}
|
||||
YASIO__DECL int write_to(transport_handle_t thandle, dynamic_buffer_t buffer, const ip::endpoint& to, completion_cb_t completion_handler = nullptr);
|
||||
YASIO__DECL int write_to(transport_handle_t thandle, sbyte_buffer buffer, const ip::endpoint& to, completion_cb_t completion_handler = nullptr);
|
||||
|
||||
// The highp_timer support, !important, the callback is called on the thread of io_service
|
||||
YASIO__DECL highp_timer_ptr schedule(const std::chrono::microseconds& duration, timer_cb_t);
|
||||
|
@ -1105,17 +1087,16 @@ private:
|
|||
YASIO__DECL void do_connect_completion(io_channel*, fd_set_adapter& fd_set);
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
YASIO__DECL void init_ssl_context();
|
||||
YASIO__DECL void cleanup_ssl_context();
|
||||
YASIO__DECL void do_ssl_handshake(io_channel*);
|
||||
YASIO__DECL SSL_CTX* init_ssl_context(ssl_role role);
|
||||
YASIO__DECL void cleanup_ssl_context(ssl_role role);
|
||||
#endif
|
||||
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
YASIO__DECL static void ares_getaddrinfo_cb(void* arg, int status, int timeouts, ares_addrinfo* answerlist);
|
||||
YASIO__DECL void ares_work_started();
|
||||
YASIO__DECL void ares_work_finished();
|
||||
YASIO__DECL int register_ares_fds(socket_native_type* ares_socks, fd_set_adapter& fd_set);
|
||||
YASIO__DECL void process_ares_requests(socket_native_type* socks, int count, fd_set_adapter& fd_set);
|
||||
YASIO__DECL int do_ares_fds(socket_native_type* socks, fd_set_adapter& fd_set, timeval& waitd_tv);
|
||||
YASIO__DECL void do_ares_process_fds(socket_native_type* socks, int count, fd_set_adapter& fd_set);
|
||||
YASIO__DECL void recreate_ares_channel();
|
||||
YASIO__DECL void config_ares_name_servers();
|
||||
YASIO__DECL void destroy_ares_channel();
|
||||
|
@ -1124,7 +1105,7 @@ private:
|
|||
void handle_connect_succeed(io_channel* ctx, xxsocket_ptr s) { handle_connect_succeed(allocate_transport(ctx, std::move(s))); }
|
||||
YASIO__DECL void handle_connect_succeed(transport_handle_t);
|
||||
YASIO__DECL void handle_connect_failed(io_channel*, int ec);
|
||||
YASIO__DECL void notify_connect_succeed(transport_handle_t);
|
||||
YASIO__DECL void active_transport(transport_handle_t);
|
||||
|
||||
YASIO__DECL transport_handle_t allocate_transport(io_channel*, xxsocket_ptr&&);
|
||||
YASIO__DECL void deallocate_transport(transport_handle_t);
|
||||
|
@ -1166,9 +1147,6 @@ private:
|
|||
YASIO__DECL void clear_transports(); // clear all transports
|
||||
YASIO__DECL bool close_internal(io_channel*);
|
||||
|
||||
// shutdown a tcp-connection if possible
|
||||
YASIO__DECL void shutdown_internal(transport_handle_t);
|
||||
|
||||
// supporting server
|
||||
YASIO__DECL void do_accept(io_channel*);
|
||||
YASIO__DECL void do_accept_completion(io_channel*, fd_set_adapter& fd_set);
|
||||
|
@ -1248,8 +1226,12 @@ private:
|
|||
print_fn2_t print_;
|
||||
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
// The full path cacert(.pem) file for ssl verifaction
|
||||
// SSL client, the full path cacert(.pem) file for ssl verifaction
|
||||
std::string cafile_;
|
||||
|
||||
// SSL server
|
||||
std::string crtfile_;
|
||||
std::string keyfile_;
|
||||
#endif
|
||||
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
|
@ -1262,7 +1244,7 @@ private:
|
|||
// The stop flag to notify all transports needs close
|
||||
uint8_t stop_flag_ = 0;
|
||||
#if defined(YASIO_SSL_BACKEND)
|
||||
SSL_CTX* ssl_ctx_ = nullptr;
|
||||
SSL_CTX* ssl_roles_[2];
|
||||
#endif
|
||||
#if defined(YASIO_HAVE_CARES)
|
||||
ares_channel ares_ = nullptr; // the ares handle for non blocking io dns resolve support
|
||||
|
|
Loading…
Reference in New Issue