<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#include "../precompiled.hpp"
#include "abstract_accept_socket.hpp"
#include "../static/network_driver.hpp"
#include "../util.hpp"

namespace poseidon {
namespace {

IO_Result
do_translate_syscall_error(const char* func, int err)
  {
    if(err == EINTR)
      return io_result_partial_work;

    if(::rocket::is_any_of(err, { EAGAIN, EWOULDBLOCK }))
      return io_result_would_block;

    POSEIDON_THROW("Failed to accept incoming connection\n"
                   "[`$1()` failed: $2]",
                   func, format_errno(err));
  }

}  // namespace

Abstract_Accept_Socket::
~Abstract_Accept_Socket()
  {
  }

void
Abstract_Accept_Socket::
do_set_common_options()
  {
    // Enable reusing addresses.
    static constexpr int yes[] = { -1 };
    int res = ::setsockopt(this->get_fd(), SOL_SOCKET, SO_REUSEADDR, yes, sizeof(yes));
    ROCKET_ASSERT(res == 0);
  }

IO_Result
Abstract_Accept_Socket::
do_on_async_poll_read(simple_mutex::unique_lock& /*lock*/, char* /*hint*/, size_t /*size*/)
  try {
    // Try accepting a socket.
    Socket_Address::storage addrst;
    ::socklen_t addrlen = sizeof(addrst);
    unique_FD fd(::accept4(this->get_fd(), addrst, &addrlen, SOCK_NONBLOCK));
    if(!fd)
      return do_translate_syscall_error("accept4", errno);

    // Create a new socket object.
    auto sock = this->do_on_async_accept(::std::move(fd));
    if(!sock)
      POSEIDON_THROW("Null pointer returned from `do_on_async_accept()`\n"
                     "[listen socket class `$1`]",
                     typeid(*this).name());

    POSEIDON_LOG_INFO("Accepted incoming connection: local '$1', remote '$2'\n"
                      "[listen socket class `$3`]\n"
                      "[accepted socket class `$4`]",
                      sock->get_local_address(), Socket_Address(addrst, addrlen),
                      typeid(*this).name(), typeid(*sock).name());

    // Register the socket.
    this->do_on_async_register(Network_Driver::insert(::std::move(sock)));

    // Report success.
    return io_result_partial_work;
  }
  catch(exception& stdex) {
    // It is probably bad to let the exception propagate to network driver and kill
    // this server socket... so we catch and ignore this exception.
    POSEIDON_LOG_ERROR("Socket accept error: $1\n"
                       "[socket class `$2`]",
                       stdex, typeid(*this));

    // Accept other connections. The error is considered non-fatal.
    return io_result_partial_work;
  }

size_t
Abstract_Accept_Socket::
do_write_queue_size(simple_mutex::unique_lock& /*lock*/)
  const
  {
    return 0;
  }

IO_Result
Abstract_Accept_Socket::
do_on_async_poll_write(simple_mutex::unique_lock& /*lock*/, char* /*hint*/, size_t /*size*/)
  {
    return io_result_end_of_stream;
  }<commit_msg>socket/abstract_accept_socket: Update logs<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#include "../precompiled.hpp"
#include "abstract_accept_socket.hpp"
#include "../static/network_driver.hpp"
#include "../util.hpp"

namespace poseidon {
namespace {

IO_Result
do_translate_syscall_error(const char* func, int err)
  {
    if(err == EINTR)
      return io_result_partial_work;

    if(::rocket::is_any_of(err, { EAGAIN, EWOULDBLOCK }))
      return io_result_would_block;

    POSEIDON_THROW("Failed to accept incoming connection\n"
                   "[`$1()` failed: $2]",
                   func, format_errno(err));
  }

}  // namespace

Abstract_Accept_Socket::
~Abstract_Accept_Socket()
  {
  }

void
Abstract_Accept_Socket::
do_set_common_options()
  {
    // Enable reusing addresses.
    static constexpr int yes[] = { -1 };
    int res = ::setsockopt(this->get_fd(), SOL_SOCKET, SO_REUSEADDR, yes, sizeof(yes));
    ROCKET_ASSERT(res == 0);
  }

IO_Result
Abstract_Accept_Socket::
do_on_async_poll_read(simple_mutex::unique_lock& /*lock*/, char* /*hint*/, size_t /*size*/)
  try {
    // Try accepting a socket.
    Socket_Address::storage addrst;
    ::socklen_t addrlen = sizeof(addrst);
    unique_FD fd(::accept4(this->get_fd(), addrst, &addrlen, SOCK_NONBLOCK));
    if(!fd)
      return do_translate_syscall_error("accept4", errno);

    // Create a new socket object.
    auto sock = this->do_on_async_accept(::std::move(fd));
    if(!sock)
      POSEIDON_THROW("Null pointer returned from `do_on_async_accept()`\n"
                     "[listen socket class `$1`]",
                     typeid(*this).name());

    // Register the socket.
    POSEIDON_LOG_INFO("Accepted incoming connection from '$1'\n"
                      "[server socket class `$2` listening on '$3']\n"
                      "[accepted socket class `$4`]",
                      Socket_Address(addrst, addrlen),
                      typeid(*this).name(), this->get_local_address(),
                      typeid(*sock).name());

    this->do_on_async_register(Network_Driver::insert(::std::move(sock)));

    // Report success.
    return io_result_partial_work;
  }
  catch(exception& stdex) {
    // It is probably bad to let the exception propagate to network driver and kill
    // this server socket... so we catch and ignore this exception.
    POSEIDON_LOG_ERROR("Socket accept error: $1\n"
                       "[socket class `$2`]",
                       stdex, typeid(*this));

    // Accept other connections. The error is considered non-fatal.
    return io_result_partial_work;
  }

size_t
Abstract_Accept_Socket::
do_write_queue_size(simple_mutex::unique_lock& /*lock*/)
  const
  {
    return 0;
  }

IO_Result
Abstract_Accept_Socket::
do_on_async_poll_write(simple_mutex::unique_lock& /*lock*/, char* /*hint*/, size_t /*size*/)
  {
    return io_result_end_of_stream;
  }
{'fraction_non_alphanumeric': 0.13239339752407153, 'fraction_numerical': 0.006189821182943604, 'mean_word_length': 2.9869773817683343, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2642599', 'n_tokens_mistral': 1923, 'n_tokens_neox': 1829, 'n_words': 419}