rcpp_framework/libs/brynet/net/TcpConnection.hpp
2020-11-24 15:41:18 +01:00

1197 lines
36 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <memory>
#include <functional>
#include <deque>
#include <chrono>
#include <cassert>
#include <cstring>
#include <cmath>
#include <type_traits>
#include <brynet/base/Buffer.hpp>
#include <brynet/base/Timer.hpp>
#include <brynet/base/NonCopyable.hpp>
#include <brynet/base/Any.hpp>
#include <brynet/base/Noexcept.hpp>
#include <brynet/base/Packet.hpp>
#include <brynet/net/SocketLibFunction.hpp>
#include <brynet/net/Channel.hpp>
#include <brynet/net/EventLoop.hpp>
#include <brynet/net/Socket.hpp>
#include <brynet/net/SSLHelper.hpp>
#ifdef BRYNET_USE_OPENSSL
#ifdef __cplusplus
extern "C" {
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#ifdef __cplusplus
}
#endif
#endif
namespace brynet { namespace net {
class SendableMsg
{
public:
using Ptr = std::shared_ptr<SendableMsg>;
virtual ~SendableMsg() = default;
virtual const void * data() = 0;
virtual size_t size() = 0;
};
class TcpConnection : public Channel,
public brynet::base::NonCopyable,
public std::enable_shared_from_this<TcpConnection>
{
public:
using Ptr = std::shared_ptr<TcpConnection>;
using EnterCallback = std::function<void(Ptr)>;
using DataCallback = std::function<void(brynet::base::BasePacketReader&)>;
using DisconnectedCallback = std::function<void(Ptr)>;
using PacketSendedCallback = std::function<void(void)>;
public:
Ptr static Create(TcpSocket::Ptr socket,
size_t maxRecvBufferSize,
EnterCallback&& enterCallback,
const EventLoop::Ptr& eventLoop,
const SSLHelper::Ptr& sslHelper = nullptr)
{
class make_shared_enabler : public TcpConnection
{
public:
make_shared_enabler(TcpSocket::Ptr socket,
size_t maxRecvBufferSize,
EnterCallback&& enterCallback,
EventLoop::Ptr eventLoop)
:
TcpConnection(std::move(socket),
maxRecvBufferSize,
std::move(enterCallback),
std::move(eventLoop))
{}
};
const auto isServerSide = socket->isServerSide();
auto session = std::make_shared<make_shared_enabler>(
std::move(socket),
maxRecvBufferSize,
std::move(enterCallback),
eventLoop);
(void)isServerSide;
#ifdef BRYNET_USE_OPENSSL
if(sslHelper != nullptr)
{
if (isServerSide)
{
if (sslHelper->getOpenSSLCTX() == nullptr ||
!session->initAcceptSSL(sslHelper->getOpenSSLCTX()))
{
throw std::runtime_error("init ssl failed");
}
}
else
{
if (!session->initConnectSSL())
{
throw std::runtime_error("init ssl failed");
}
}
}
#else
if (sslHelper != nullptr)
{
throw std::runtime_error("not enable ssl");
}
#endif
eventLoop->runAsyncFunctor([session]()
{
session->onEnterEventLoop();
});
return session;
}
const EventLoop::Ptr& getEventLoop() const
{
return mEventLoop;
}
//TODO::如果所属EventLoop已经没有工作则可能导致内存无限大因为所投递的请求都没有得到处理
void send(
const SendableMsg::Ptr& msg,
PacketSendedCallback&& callback = nullptr
)
{
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis, msg, callback]() mutable
{
const auto len = msg->size();
sharedThis->mSendList.emplace_back(PendingPacket{
std::move(msg),
len,
std::move(callback) });
sharedThis->runAfterFlush();
});
}
void send(
const char* buffer,
size_t len,
PacketSendedCallback&& callback = nullptr)
{
send(std::make_shared<std::string>(buffer, len), std::move(callback));
}
void send(
const std::shared_ptr<std::string>& packet,
PacketSendedCallback&& callback = nullptr)
{
class StringSendMsg : public SendableMsg
{
public:
explicit StringSendMsg(std::shared_ptr<std::string>&& msg)
:
mMsg(std::move(msg))
{}
explicit StringSendMsg(const std::shared_ptr<std::string>& msg)
:
mMsg(msg)
{}
const void* data() override
{
return static_cast<const void*>(mMsg->data());
}
size_t size() override
{
return mMsg->size();
}
private:
std::shared_ptr<std::string> mMsg;
};
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis, packet, callback]() mutable
{
const auto len = packet->size();
sharedThis->mSendList.emplace_back(PendingPacket{
std::make_shared<StringSendMsg>(std::move(packet)),
len,
std::move(callback) });
sharedThis->runAfterFlush();
});
}
// setDataCallback(std::function<void(brynet::base::BasePacketReader&)>
template<typename Callback>
void setDataCallback(Callback&& cb)
{
verifyArgType(cb, &Callback::operator());
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis, cb]() mutable
{
sharedThis->mDataCallback = cb;
sharedThis->processRecvMessage();
});
}
void setDisConnectCallback(DisconnectedCallback&& cb)
{
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis, cb]() mutable
{
sharedThis->mDisConnectCallback = std::move(cb);
});
}
/* if checkTime is zero, will cancel check heartbeat */
void setHeartBeat(std::chrono::nanoseconds checkTime)
{
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis, checkTime]()
{
if (sharedThis->mTimer.lock() != nullptr)
{
sharedThis->mTimer.lock()->cancel();
sharedThis->mTimer.reset();
}
sharedThis->mCheckTime = checkTime;
sharedThis->startPingCheckTimer();
});
}
void postDisConnect()
{
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis]()
{
sharedThis->procCloseInLoop();
});
}
void postShutdown()
{
auto sharedThis = shared_from_this();
mEventLoop->runAsyncFunctor([sharedThis]()
{
sharedThis->mEventLoop->runFunctorAfterLoop([sharedThis]()
{
sharedThis->procShutdownInLoop();
});
});
}
const std::string& getIP() const
{
return mIP;
}
protected:
TcpConnection(TcpSocket::Ptr socket,
size_t maxRecvBufferSize,
EnterCallback&& enterCallback,
EventLoop::Ptr eventLoop) BRYNET_NOEXCEPT
:
#ifdef BRYNET_PLATFORM_WINDOWS
mOvlRecv(port::Win::OverlappedType::OverlappedRecv),
mOvlSend(port::Win::OverlappedType::OverlappedSend),
mPostClose(false),
#endif
mIP(socket->getRemoteIP()),
mSocket(std::move(socket)),
mEventLoop(std::move(eventLoop)),
mAlreadyClose(false),
mMaxRecvBufferSize(maxRecvBufferSize),
mEnterCallback(std::move(enterCallback))
{
mRecvData = false;
mCheckTime = std::chrono::steady_clock::duration::zero();
mIsPostFlush = false;
mCanWrite = true;
#ifdef BRYNET_PLATFORM_WINDOWS
mPostRecvCheck = false;
mPostWriteCheck = false;
#endif
growRecvBuffer();
#ifdef BRYNET_USE_OPENSSL
mSSLCtx = nullptr;
mSSL = nullptr;
mIsHandsharked = false;
#endif
}
~TcpConnection() BRYNET_NOEXCEPT override
{
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr)
{
SSL_free(mSSL);
mSSL = nullptr;
}
if (mSSLCtx != nullptr)
{
SSL_CTX_free(mSSLCtx);
mSSLCtx = nullptr;
}
#endif
if (mTimer.lock())
{
mTimer.lock()->cancel();
}
}
private:
void growRecvBuffer()
{
if (mRecvBuffer == nullptr)
{
mRecvBuffer.reset(brynet::base::buffer_new(std::min<size_t>(16 * 1024, mMaxRecvBufferSize)));
mRecvBuffOriginSize = buffer_getsize(mRecvBuffer.get());
}
else
{
if (buffer_getsize(mRecvBuffer.get()) >= mMaxRecvBufferSize)
{
return;
}
mCurrentTanhXDiff += 0.2;
const auto newTanh = std::tanh(mCurrentTanhXDiff);
const auto maxSizeDiff = mMaxRecvBufferSize - mRecvBuffOriginSize;
const auto NewSize = mRecvBuffOriginSize + (maxSizeDiff * newTanh);
assert(NewSize <= mMaxRecvBufferSize);
std::unique_ptr<struct brynet::base::buffer_s, BufferDeleter> newBuffer(brynet::base::buffer_new(NewSize));
buffer_write(newBuffer.get(),
buffer_getreadptr(mRecvBuffer.get()),
buffer_getreadvalidcount(mRecvBuffer.get()));
mRecvBuffer = std::move(newBuffer);
}
}
/* must called in network thread */
bool onEnterEventLoop()
{
assert(mEventLoop->isInLoopThread());
if (!mEventLoop->isInLoopThread())
{
return false;
}
if (!brynet::net::base::SocketNonblock(mSocket->getFD()) ||
!mEventLoop->linkChannel(mSocket->getFD(), this))
{
return false;
}
const auto findRet = mEventLoop->getTcpConnection(mSocket->getFD());
(void)findRet;
assert(findRet == nullptr);
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr)
{
mEventLoop->addTcpConnection(mSocket->getFD(), shared_from_this());
processSSLHandshake();
return true;
}
#endif
if (!checkRead())
{
return false;
}
mEventLoop->addTcpConnection(mSocket->getFD(), shared_from_this());
causeEnterCallback();
return true;
}
#ifdef BRYNET_USE_OPENSSL
bool initAcceptSSL(SSL_CTX* ctx)
{
if (mSSL != nullptr)
{
return false;
}
mSSL = SSL_new(ctx);
if (SSL_set_fd(mSSL, mSocket->getFD()) != 1)
{
ERR_print_errors_fp(stdout);
::fflush(stdout);
return false;
}
return true;
}
bool initConnectSSL()
{
if (mSSLCtx != nullptr)
{
return false;
}
mSSLCtx = SSL_CTX_new(SSLv23_client_method());
mSSL = SSL_new(mSSLCtx);
if (SSL_set_fd(mSSL, mSocket->getFD()) != 1)
{
ERR_print_errors_fp(stdout);
::fflush(stdout);
return false;
}
return true;
}
#endif
void pingCheck()
{
mTimer.reset();
if (mRecvData)
{
mRecvData = false;
startPingCheckTimer();
}
else
{
procCloseInLoop();
}
}
void startPingCheckTimer()
{
if (!mTimer.lock() &&
mCheckTime != std::chrono::steady_clock::duration::zero())
{
std::weak_ptr<TcpConnection> weakedThis = shared_from_this();
mTimer = mEventLoop->runAfter(mCheckTime, [weakedThis]() {
auto sharedThis = weakedThis.lock();
if (sharedThis != nullptr)
{
sharedThis->pingCheck();
}
});
}
}
void canRecv() override
{
#ifdef BRYNET_PLATFORM_WINDOWS
mPostRecvCheck = false;
if (mPostClose)
{
if (!mPostWriteCheck)
{
onClose();
}
return;
}
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
if (mAlreadyClose)
{
return;
}
#endif
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr
&& !mIsHandsharked
&& (!processSSLHandshake() || !mIsHandsharked))
{
return;
}
#endif
recv();
}
void canSend() override
{
#ifdef BRYNET_PLATFORM_WINDOWS
mPostWriteCheck = false;
if (mPostClose)
{
if (!mPostRecvCheck)
{
onClose();
}
return;
}
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
if (mAlreadyClose)
{
return;
}
#endif
mCanWrite = true;
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr
&& !mIsHandsharked
&& (!processSSLHandshake() || !mIsHandsharked))
{
return;
}
#endif
runAfterFlush();
}
bool checkRead()
{
bool check_ret = true;
#ifdef BRYNET_PLATFORM_WINDOWS
static CHAR temp[] = { 0 };
static WSABUF in_buf = { 0, temp };
if (mPostRecvCheck)
{
return check_ret;
}
DWORD dwBytes = 0;
DWORD flag = 0;
const int ret = WSARecv(mSocket->getFD(),
&in_buf,
1,
&dwBytes,
&flag,
&(mOvlRecv.base),
0);
if (ret == BRYNET_SOCKET_ERROR)
{
check_ret = (BRYNET_ERRNO == WSA_IO_PENDING);
}
if (check_ret)
{
mPostRecvCheck = true;
}
#endif
return check_ret;
}
bool checkWrite()
{
bool check_ret = true;
#ifdef BRYNET_PLATFORM_WINDOWS
static WSABUF wsendbuf[1] = { {NULL, 0} };
if (mPostWriteCheck)
{
return check_ret;
}
DWORD send_len = 0;
const int ret = WSASend(mSocket->getFD(),
wsendbuf,
1,
&send_len,
0,
&(mOvlSend.base),
0);
if (ret == BRYNET_SOCKET_ERROR)
{
check_ret = (BRYNET_ERRNO == WSA_IO_PENDING);
}
if (check_ret)
{
mPostWriteCheck = true;
}
#endif
return check_ret;
}
void recv()
{
bool must_close = false;
#ifdef BRYNET_USE_OPENSSL
const bool notInSSL = (mSSL == nullptr);
#else
const bool notInSSL = false;
#endif
while (true)
{
if (buffer_getwritevalidcount(mRecvBuffer.get()) == 0
|| buffer_getreadvalidcount(mRecvBuffer.get()) == 0)
{
buffer_adjustto_head(mRecvBuffer.get());
}
const auto tryRecvLen = buffer_getwritevalidcount(mRecvBuffer.get());
if (tryRecvLen == 0)
{
#ifdef BRYNET_PLATFORM_WINDOWS
checkRead();
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
//force recheck IN-OUT Event
recheckEvent();
#endif
break;
}
int retlen = 0;
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr)
{
retlen = SSL_read(mSSL,
buffer_getwriteptr(mRecvBuffer.get()), tryRecvLen);
}
else
{
retlen = ::recv(mSocket->getFD(),
buffer_getwriteptr(mRecvBuffer.get()), tryRecvLen, 0);
}
#else
retlen = ::recv(mSocket->getFD(),
buffer_getwriteptr(mRecvBuffer.get()),
static_cast<int>(tryRecvLen),
0);
#endif
if (retlen == 0)
{
must_close = true;
break;
}
else if (retlen < 0)
{
#ifdef BRYNET_USE_OPENSSL
if ((mSSL != nullptr &&
SSL_get_error(mSSL, retlen) == SSL_ERROR_WANT_READ) ||
(BRYNET_ERRNO == BRYNET_EWOULDBLOCK))
{
must_close = !checkRead();
}
else
{
must_close = true;
}
#else
if (BRYNET_ERRNO != BRYNET_EWOULDBLOCK)
{
must_close = true;
}
else
{
must_close = !checkRead();
}
#endif
break;
}
mRecvData = true;
buffer_addwritepos(mRecvBuffer.get(), static_cast<size_t>(retlen));
if (buffer_getreadvalidcount(mRecvBuffer.get())
== buffer_getsize(mRecvBuffer.get()))
{
growRecvBuffer();
}
if (notInSSL && retlen < static_cast<int>(tryRecvLen))
{
must_close = !checkRead();
break;
}
}
processRecvMessage();
if (must_close)
{
procCloseInLoop();
}
}
void flush()
{
#ifdef BRYNET_PLATFORM_WINDOWS
normalFlush();
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr)
{
normalFlush();
}
else
{
quickFlush();
}
#else
quickFlush();
#endif
#endif
}
void normalFlush()
{
#ifdef BRYNET_PLATFORM_WINDOWS
static __declspec(thread) char* threadLocalSendBuf = nullptr;
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
static __thread char* threadLocalSendBuf = nullptr;
#endif
static const int SENDBUF_SIZE = 1024 * 32;
if (threadLocalSendBuf == nullptr)
{
threadLocalSendBuf = static_cast<char*>(malloc(SENDBUF_SIZE));
}
#ifdef BRYNET_USE_OPENSSL
const bool notInSSL = (mSSL == nullptr);
#else
const bool notInSSL = false;
#endif
bool must_close = false;
while (!mSendList.empty() && mCanWrite)
{
auto sendptr = threadLocalSendBuf;
size_t wait_send_size = 0;
for (auto it = mSendList.begin(); it != mSendList.end(); ++it)
{
auto& packet = *it;
auto packetLeftBuf = (char*)(packet.data->data()) + packet.data->size() - packet.left;
const auto packetLeftLen = packet.left;
if ((wait_send_size + packetLeftLen) > SENDBUF_SIZE)
{
if (it == mSendList.begin())
{
sendptr = packetLeftBuf;
wait_send_size = packetLeftLen;
}
break;
}
memcpy(static_cast<void*>(sendptr + wait_send_size), static_cast<void*>(packetLeftBuf), packetLeftLen);
wait_send_size += packetLeftLen;
}
if (wait_send_size == 0)
{
break;
}
int send_retlen = 0;
#ifdef BRYNET_USE_OPENSSL
if (mSSL != nullptr)
{
send_retlen = SSL_write(mSSL, sendptr, wait_send_size);
}
else
{
send_retlen = ::send(mSocket->getFD(), sendptr, wait_send_size, 0);
}
#else
send_retlen = ::send(mSocket->getFD(), sendptr, static_cast<int>(wait_send_size), 0);
#endif
if (send_retlen <= 0)
{
#ifdef BRYNET_USE_OPENSSL
if ((mSSL != nullptr && SSL_get_error(mSSL, send_retlen) == SSL_ERROR_WANT_WRITE) ||
(BRYNET_ERRNO == BRYNET_EWOULDBLOCK))
{
mCanWrite = false;
must_close = !checkWrite();
}
else
{
must_close = true;
}
#else
if (BRYNET_ERRNO == BRYNET_EWOULDBLOCK)
{
mCanWrite = false;
must_close = !checkWrite();
}
else
{
must_close = true;
}
#endif
break;
}
auto tmp_len = static_cast<size_t>(send_retlen);
for (auto it = mSendList.begin(); it != mSendList.end();)
{
auto& packet = *it;
if (packet.left > tmp_len)
{
packet.left -= tmp_len;
break;
}
tmp_len -= packet.left;
if (packet.mCompleteCallback != nullptr)
{
(packet.mCompleteCallback)();
}
it = mSendList.erase(it);
}
if (notInSSL && static_cast<size_t>(send_retlen) != wait_send_size)
{
mCanWrite = false;
must_close = !checkWrite();
break;
}
}
if (must_close)
{
procCloseInLoop();
}
}
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
void quickFlush()
{
#ifndef MAX_IOVEC
constexpr size_t MAX_IOVEC = 1024;
#endif
struct iovec iov[MAX_IOVEC];
bool must_close = false;
while (!mSendList.empty() && mCanWrite)
{
size_t num = 0;
size_t ready_send_len = 0;
for (const auto& p : mSendList)
{
iov[num].iov_base = (void*)(static_cast<const char*>(p.data->data()) + p.data->size() - p.left);
iov[num].iov_len = p.left;
ready_send_len += p.left;
num++;
if (num >= MAX_IOVEC)
{
break;
}
}
if (num == 0)
{
break;
}
const int send_len = writev(mSocket->getFD(), iov, static_cast<int>(num));
if (send_len <= 0)
{
if (BRYNET_ERRNO == BRYNET_EWOULDBLOCK)
{
mCanWrite = false;
must_close = !checkWrite();
}
else
{
must_close = true;
}
break;
}
auto tmp_len = static_cast<size_t>(send_len);
for (auto it = mSendList.begin(); it != mSendList.end();)
{
PendingPacket& b = *it;
if (b.left > tmp_len)
{
b.left -= tmp_len;
break;
}
tmp_len -= b.left;
if (b.mCompleteCallback != nullptr)
{
b.mCompleteCallback();
}
it = mSendList.erase(it);
}
if (static_cast<size_t>(send_len) != ready_send_len)
{
mCanWrite = false;
must_close = !checkWrite();
break;
}
}
if (must_close)
{
procCloseInLoop();
}
}
#endif
void onClose() override
{
if (mAlreadyClose)
{
return;
}
mAlreadyClose = true;
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
unregisterPollerEvent();
#endif
assert(mEnterCallback == nullptr);
auto callBack = mDisConnectCallback;
auto sharedThis = shared_from_this();
auto eventLoop = mEventLoop;
std::shared_ptr<TcpSocket> socket = std::move(const_cast<TcpSocket::Ptr&&>(mSocket));
mEventLoop->runFunctorAfterLoop([callBack,
sharedThis,
eventLoop,
socket]() {
if (callBack != nullptr)
{
callBack(sharedThis);
}
auto tmp = eventLoop->getTcpConnection(socket->getFD());
assert(tmp == sharedThis);
if (tmp == sharedThis)
{
eventLoop->removeTcpConnection(socket->getFD());
}
});
mCanWrite = false;
mDisConnectCallback = nullptr;
mDataCallback = nullptr;
mRecvBuffer = nullptr;
}
void procCloseInLoop()
{
mCanWrite = false;
#ifdef BRYNET_PLATFORM_WINDOWS
if (mPostWriteCheck || mPostRecvCheck)
{
if (mPostClose)
{
return;
}
mPostClose = true;
//windows下立即关闭socket可能导致fd被另外的TcpConnection重用,而导致此对象在IOCP返回相关完成结果时内存已经释放
if (mPostRecvCheck)
{
CancelIoEx(HANDLE(mSocket->getFD()), &mOvlRecv.base);
}
if (mPostWriteCheck)
{
CancelIoEx(HANDLE(mSocket->getFD()), &mOvlSend.base);
}
}
else
{
onClose();
}
#elif defined BRYNET_PLATFORM_LINUX
onClose();
#elif defined BRYNET_PLATFORM_DARWIN
onClose();
#endif
}
void procShutdownInLoop()
{
mCanWrite = false;
if (mSocket != nullptr)
{
#ifdef BRYNET_PLATFORM_WINDOWS
shutdown(mSocket->getFD(), SD_SEND);
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
shutdown(mSocket->getFD(), SHUT_WR);
#endif
}
}
void runAfterFlush()
{
if (!mIsPostFlush && !mSendList.empty() && mCanWrite)
{
auto sharedThis = shared_from_this();
mEventLoop->runFunctorAfterLoop([sharedThis]() {
sharedThis->mIsPostFlush = false;
sharedThis->flush();
});
mIsPostFlush = true;
}
}
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
void recheckEvent()
{
#ifdef BRYNET_PLATFORM_LINUX
struct epoll_event ev = { 0, { nullptr } };
ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP;
ev.data.ptr = (Channel*)(this);
epoll_ctl(mEventLoop->getEpollHandle(), EPOLL_CTL_MOD, mSocket->getFD(), &ev);
#elif defined BRYNET_PLATFORM_DARWIN
struct kevent ev[2];
memset(&ev, 0, sizeof(ev));
int n = 0;
EV_SET(&ev[n++], mSocket->getFD(), EVFILT_READ, EV_ENABLE, 0, 0, (Channel*)(this));
EV_SET(&ev[n++], mSocket->getFD(), EVFILT_WRITE, EV_ENABLE, 0, 0, (Channel*)(this));
struct timespec now = { 0, 0 };
kevent(mEventLoop->getKqueueHandle(), ev, n, NULL, 0, &now);
#endif
}
void unregisterPollerEvent()
{
#ifdef BRYNET_PLATFORM_LINUX
struct epoll_event ev = { 0, { nullptr } };
epoll_ctl(mEventLoop->getEpollHandle(), EPOLL_CTL_DEL, mSocket->getFD(), &ev);
#elif defined BRYNET_PLATFORM_DARWIN
struct kevent ev[2];
memset(&ev, 0, sizeof(ev));
int n = 0;
EV_SET(&ev[n++], mSocket->getFD(), EVFILT_READ, EV_DELETE, 0, 0, NULL);
EV_SET(&ev[n++], mSocket->getFD(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
struct timespec now = { 0, 0 };
kevent(mEventLoop->getKqueueHandle(), ev, n, NULL, 0, &now);
#endif
}
#endif
#ifdef BRYNET_USE_OPENSSL
bool processSSLHandshake()
{
if (mIsHandsharked)
{
return true;
}
bool mustClose = false;
int ret = 0;
if (mSSLCtx != nullptr)
{
ret = SSL_connect(mSSL);
}
else
{
ret = SSL_accept(mSSL);
}
if (ret == 1)
{
mIsHandsharked = true;
if (checkRead())
{
causeEnterCallback();
}
else
{
mustClose = true;
}
}
else if (ret == 0)
{
mustClose = true;
}
else if (ret < 0)
{
int err = SSL_get_error(mSSL, ret);
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ)
{
if (!checkRead())
{
mustClose = true;
}
}
else
{
mustClose = true;
}
}
if (mustClose)
{
causeEnterCallback();
procCloseInLoop();
return false;
}
return true;
}
#endif
void causeEnterCallback()
{
assert(mEventLoop->isInLoopThread());
if (mEventLoop->isInLoopThread() && mEnterCallback != nullptr)
{
auto tmp = mEnterCallback;
mEnterCallback = nullptr;
tmp(shared_from_this());
}
}
void processRecvMessage()
{
if (mDataCallback != nullptr && buffer_getreadvalidcount(mRecvBuffer.get()) > 0)
{
auto reader = brynet::base::BasePacketReader(buffer_getreadptr(mRecvBuffer.get()),
buffer_getreadvalidcount(mRecvBuffer.get()), false);
mDataCallback(reader);
const auto consumedLen = reader.savedPos();
assert(consumedLen <= reader.size());
if (consumedLen <= reader.size())
{
buffer_addreadpos(mRecvBuffer.get(), consumedLen);
}
}
}
template<typename CallbackType, typename Arg>
static void verifyArgType(const CallbackType&, void(CallbackType::*)(Arg&) const)
{
static_assert(std::is_reference<Arg&>::value, "arg must be reference type");
static_assert(!std::is_const<typename std::remove_const<Arg>::type>::value, "arg can't be const type");
}
private:
#ifdef BRYNET_PLATFORM_WINDOWS
struct port::Win::OverlappedExt mOvlRecv;
struct port::Win::OverlappedExt mOvlSend;
bool mPostRecvCheck;
bool mPostWriteCheck;
bool mPostClose;
#endif
const std::string mIP;
const TcpSocket::Ptr mSocket;
const EventLoop::Ptr mEventLoop;
bool mCanWrite;
bool mAlreadyClose;
class BufferDeleter
{
public:
void operator()(struct brynet::base::buffer_s* ptr) const
{
brynet::base::buffer_delete(ptr);
}
};
std::unique_ptr<struct brynet::base::buffer_s, BufferDeleter> mRecvBuffer;
double mCurrentTanhXDiff = 0;
size_t mRecvBuffOriginSize = 0;
const size_t mMaxRecvBufferSize;
struct PendingPacket
{
SendableMsg::Ptr data;
size_t left;
PacketSendedCallback mCompleteCallback;
};
using PacketListType = std::deque<PendingPacket>;
PacketListType mSendList;
EnterCallback mEnterCallback;
DataCallback mDataCallback;
DisconnectedCallback mDisConnectCallback;
bool mIsPostFlush;
#ifdef BRYNET_USE_OPENSSL
SSL_CTX* mSSLCtx;
SSL* mSSL;
bool mIsHandsharked;
#endif
bool mRecvData;
std::chrono::nanoseconds mCheckTime{};
brynet::base::Timer::WeakPtr mTimer;
};
} }