rcpp_framework/core/loops/acceptor.cpp

101 lines
3.1 KiB
C++

// This file is originally from Trantor - Acceptor.cc
// Copyright (c) 2016-2021, Tao An. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Tao An nor the names of other contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "acceptor.h"
#ifndef O_CLOEXEC
#define O_CLOEXEC O_NOINHERIT
#endif
Acceptor::Acceptor(EventLoop *loop,
const InetAddress &addr,
bool reUseAddr,
bool reUsePort)
:
#ifndef _WIN32
idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)),
#endif
sock_(
Socket::createNonblockingSocketOrDie(addr.getSockAddr()->sa_family)),
addr_(addr),
loop_(loop),
acceptChannel_(loop, sock_.fd()) {
sock_.setReuseAddr(reUseAddr);
sock_.setReusePort(reUsePort);
sock_.bindAddress(addr_);
acceptChannel_.setReadCallback(std::bind(&Acceptor::readCallback, this));
if (addr_.toPort() == 0) {
addr_ = InetAddress{ Socket::getLocalAddr(sock_.fd()) };
}
}
Acceptor::~Acceptor() {
acceptChannel_.disableAll();
acceptChannel_.remove();
#ifndef _WIN32
::close(idleFd_);
#endif
}
void Acceptor::listen() {
loop_->assertInLoopThread();
sock_.listen();
acceptChannel_.enableReading();
}
void Acceptor::readCallback() {
InetAddress peer;
int newsock = sock_.accept(&peer);
if (newsock >= 0) {
if (newConnectionCallback_) {
newConnectionCallback_(newsock, peer);
} else {
#ifndef _WIN32
::close(newsock);
#else
closesocket(newsock);
#endif
}
} else {
LOG_SYSERR << "Accpetor::readCallback";
// Read the section named "The special problem of
// accept()ing when you can't" in libev's doc.
// By Marc Lehmann, author of libev.
/// errno is thread safe
#ifndef _WIN32
if (errno == EMFILE) {
::close(idleFd_);
idleFd_ = sock_.accept(&peer);
::close(idleFd_);
idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
}
#endif
}
}