Skip to content

Commit

Permalink
From address (#540)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Mar 27, 2024
1 parent d6f60e0 commit 68e290e
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 20 deletions.
6 changes: 1 addition & 5 deletions cmake/develop.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ int main()
endmacro()

# Enable address sanitizer
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
option(ENABLE_SANITIZER "Enable sanitizer(Debug+Gcc/Clang/AppleClang)" OFF)
else()
option(ENABLE_SANITIZER "Enable sanitizer(Debug+Gcc/Clang/AppleClang)" ON)
endif()
option(ENABLE_SANITIZER "Enable sanitizer(Debug+Gcc/Clang/AppleClang)" ON)
if(ENABLE_SANITIZER AND NOT MSVC)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
check_asan(HAS_ASAN)
Expand Down
3 changes: 2 additions & 1 deletion example/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ using namespace cinatra;
using namespace std::chrono_literals;

int main() {
coro_http_server server(std::thread::hardware_concurrency(), 8090, true);
coro_http_server server(std::thread::hardware_concurrency(), 8090,
"127.0.0.1", true);
server.set_http_handler<GET>(
"/plaintext", [](coro_http_request& req, coro_http_response& resp) {
resp.get_conn()->set_multi_buf(false);
Expand Down
95 changes: 81 additions & 14 deletions include/cinatra/coro_http_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,37 @@ enum class file_resp_format_type {
};
class coro_http_server {
public:
coro_http_server(asio::io_context &ctx, unsigned short port)
: out_ctx_(&ctx), port_(port), acceptor_(ctx), check_timer_(ctx) {}
coro_http_server(asio::io_context &ctx, unsigned short port,
std::string address = "0.0.0.0")
: out_ctx_(&ctx), port_(port), acceptor_(ctx), check_timer_(ctx) {
init_address(std::move(address));
}

coro_http_server(asio::io_context &ctx,
std::string address /* = "0.0.0.0:9001" */)
: out_ctx_(&ctx), acceptor_(ctx), check_timer_(ctx) {
init_address(std::move(address));
}

coro_http_server(size_t thread_num, unsigned short port,
bool cpu_affinity = false)
std::string address = "0.0.0.0", bool cpu_affinity = false)
: pool_(std::make_unique<coro_io::io_context_pool>(thread_num,
cpu_affinity)),
port_(port),
acceptor_(pool_->get_executor()->get_asio_executor()),
check_timer_(pool_->get_executor()->get_asio_executor()) {}
check_timer_(pool_->get_executor()->get_asio_executor()) {
init_address(std::move(address));
}

coro_http_server(size_t thread_num,
std::string address /* = "0.0.0.0:9001" */,
bool cpu_affinity = false)
: pool_(std::make_unique<coro_io::io_context_pool>(thread_num,
cpu_affinity)),
acceptor_(pool_->get_executor()->get_asio_executor()),
check_timer_(pool_->get_executor()->get_asio_executor()) {
init_address(std::move(address));
}

~coro_http_server() {
CINATRA_LOG_INFO << "coro_http_server will quit";
Expand Down Expand Up @@ -64,29 +85,30 @@ class coro_http_server {

// only call once, not thread safe.
async_simple::Future<std::errc> async_start() {
auto ec = listen();
errc_ = listen();

async_simple::Promise<std::errc> promise;
auto future = promise.getFuture();

if (ec == std::errc{}) {
if (errc_ == std::errc{}) {
if (out_ctx_ == nullptr) {
thd_ = std::thread([this] {
pool_->run();
});
}

accept().start([p = std::move(promise)](auto &&res) mutable {
accept().start([p = std::move(promise), this](auto &&res) mutable {
if (res.hasError()) {
p.setValue(std::errc::io_error);
errc_ = std::errc::io_error;
p.setValue(errc_);
}
else {
p.setValue(res.value());
}
});
}
else {
promise.setValue(ec);
promise.setValue(errc_);
}

return future;
Expand Down Expand Up @@ -488,16 +510,31 @@ class coro_http_server {
return connections_.size();
}

std::string_view address() { return address_; }
std::errc get_errc() { return errc_; }

private:
std::errc listen() {
CINATRA_LOG_INFO << "begin to listen";
using asio::ip::tcp;
auto endpoint = tcp::endpoint(tcp::v4(), port_);
acceptor_.open(endpoint.protocol());
asio::error_code ec;
auto addr = asio::ip::address::from_string(address_, ec);
if (ec) {
CINATRA_LOG_ERROR << "bad address: " << address_
<< " error: " << ec.message();
return std::errc::bad_address;
}

auto endpoint = tcp::endpoint(addr, port_);
acceptor_.open(endpoint.protocol(), ec);
if (ec) {
CINATRA_LOG_ERROR << "acceptor open failed"
<< " error: " << ec.message();
return std::errc::io_error;
}
#ifdef __GNUC__
acceptor_.set_option(tcp::acceptor::reuse_address(true));
acceptor_.set_option(tcp::acceptor::reuse_address(true), ec);
#endif
asio::error_code ec;
acceptor_.bind(endpoint, ec);
if (ec) {
CINATRA_LOG_ERROR << "bind port: " << port_ << " error: " << ec.message();
Expand All @@ -508,7 +545,12 @@ class coro_http_server {
#ifdef _MSC_VER
acceptor_.set_option(tcp::acceptor::reuse_address(true));
#endif
acceptor_.listen();
acceptor_.listen(asio::socket_base::max_listen_connections, ec);
if (ec) {
CINATRA_LOG_ERROR << "get local endpoint port: " << port_
<< " listen error: " << ec.message();
return std::errc::io_error;
}

auto end_point = acceptor_.local_endpoint(ec);
if (ec) {
Expand Down Expand Up @@ -749,11 +791,36 @@ class coro_http_server {
response.set_delay(true);
}

void init_address(std::string address) {
if (size_t pos = address.find(':'); pos != std::string::npos) {
auto port_sv = std::string_view(address).substr(pos + 1);

uint16_t port;
auto [ptr, ec] = std::from_chars(
port_sv.data(), port_sv.data() + port_sv.size(), port, 10);
if (ec != std::errc{}) {
address_ = std::move(address);
return;
}

port_ = port;
address = address.substr(0, pos);
}

if (iequal0(address, "localhost")) {
address = "127.0.0.1";
}

address_ = std::move(address);
}

private:
std::unique_ptr<coro_io::io_context_pool> pool_;
asio::io_context *out_ctx_ = nullptr;
std::unique_ptr<coro_io::ExecutorWrapper<>> out_executor_ = nullptr;
uint16_t port_;
std::string address_;
std::errc errc_ = {};
asio::ip::tcp::acceptor acceptor_;
std::thread thd_;
std::promise<void> acceptor_close_waiter_;
Expand Down
58 changes: 58 additions & 0 deletions tests/test_cinatra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,64 @@ TEST_CASE("test select coro channel") {
CHECK(val == 42);
}

TEST_CASE("test bad address") {
{
coro_http_server server(1, 9001, "127.0.0.1");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}
{
coro_http_server server(1, 9001, "localhost");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}
{
coro_http_server server(1, 9001, "0.0.0.0");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}
{
coro_http_server server(1, 9001);
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}
{
coro_http_server server(1, "0.0.0.0:9001");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}
{
coro_http_server server(1, "127.0.0.1:9001");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}
{
coro_http_server server(1, "localhost:9001");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc{});
}

{
coro_http_server server(1, 9001, "x.x.x");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc::bad_address);
}
{
coro_http_server server(1, "localhost:aaa");
server.async_start();
auto ec = server.get_errc();
CHECK(ec == std::errc::bad_address);
}
}

async_simple::coro::Lazy<void> test_collect_all() {
asio::io_context ioc;
std::thread thd([&] {
Expand Down

0 comments on commit 68e290e

Please sign in to comment.