commit 4a354f2fcb6d0403fad19c421b6c2839dddfb227 from: Aleksey Ryndin date: Tue Aug 29 20:59:17 2023 UTC Refactoring: transport::accepted_client commit - c966293b4ff0b2a267372fb1fb1229089ecb3145 commit + 4a354f2fcb6d0403fad19c421b6c2839dddfb227 blob - b7a75a85a349403c66a00ae0978b5c7e78d38f4c blob + f0cd56105db826dd94ffb4065683264163df99da --- vostok/transport.cc +++ vostok/transport.cc @@ -3,7 +3,10 @@ #include "error.h" #include "transport.h" +#include +#include + namespace vostok { namespace transport @@ -120,20 +123,27 @@ void create_server(not_null cert_file, not_n } -void accept( - not_nullserver_ctx, - unique_fd &client_socket, // Socket ownership transfer - accepted_context &ctx -) +accepted_client::accepted_client(int server_socket, struct tls *server_ctx) { - struct tls *client_ctx = nullptr; - if (tls_accept_socket(server_ctx, &client_ctx, client_socket.get()) == -1) + struct sockaddr_in addr{}; + socklen_t addrlen = sizeof(addr); + + m_fd.reset(accept(server_socket, (struct sockaddr *)&addr, &addrlen)); + if (!m_fd) { + error::occurred("Accept socket", error::print{}); + return; + } + + struct tls *ctx = nullptr; + if (tls_accept_socket(server_ctx, &ctx, m_fd.get()) == -1) + { error::occurred("TLS accept", error::none{}); - ctx.reset(); return; } - ctx.reset(accepted_context::value{client_socket.release(), client_ctx}); + + m_ctx.reset(ctx); + m_is_accepted = true; } blob - ca021031a6a36547413206e674339b82f4dd03f4 blob + b1c2577de7e8aff3a85580b7e0fa96d2226f98cb --- vostok/transport.h +++ vostok/transport.h @@ -19,55 +19,31 @@ namespace transport typedef std::unique_ptr context_t; -/** Pair: `struct tls *` pointer and file descriptor as smart pointer */ -class accepted_context : non_copiable +/** Per-process initialization */ +bool init(); + + +/* Create new TLS context for gemini server */ +void create_server(not_null cert_file, not_null key_file, context_t &ctx); + + +/** Accept new client */ +class accepted_client { public: - struct value - { - int m_fd; - struct tls *m_ctx; - value(int fd = -1, struct tls *ctx = nullptr) : m_fd{fd}, m_ctx{ctx} {} - }; + accepted_client(int server_socket, struct tls *server_ctx); + bool is_accepted() const { return m_is_accepted; } - accepted_context(int fd = -1, struct tls *ctx = nullptr) { reset(value{fd, ctx}); } - accepted_context(value v) { reset(v); } - struct tls *get_ctx() const { return m_ctx.get(); } int get_fd() const { return m_fd.get(); } - value get() const { return value{m_fd.get(), m_ctx.get()}; } - value release() { return value{m_fd.release(), m_ctx.release()}; } - void reset(value v=value{-1, nullptr}) - { - m_fd.reset(v.m_fd); - m_ctx.reset(v.m_ctx); - assert((m_fd && m_ctx) || (!m_fd && !m_ctx)); - } - operator bool () const { return m_fd && m_ctx; } - private: unique_fd m_fd; context_t m_ctx{nullptr, tls_free}; + bool m_is_accepted{false}; }; -/** Per-process initialization */ -bool init(); - - -/* Create new TLS context for gemini server */ -void create_server(not_null cert_file, not_null key_file, context_t &ctx); - - -/** Accept new client. Socket ownership transfer */ -void accept( - not_nullserver_ctx, - unique_fd &client_socket, // Socket ownership transfer - accepted_context &ctx -); - - /** Read genimi request and return url (empty url - error) */ span read_request(not_null ctx, std::array &buffer); blob - aeb7bca4f490ff9d8be8d2958cef7d6a1063092c blob + 5e4f404de41c1332628cda9dfd8386191e71d32f --- vostok/vostok.cc +++ vostok/vostok.cc @@ -41,16 +41,16 @@ const auto temporary_failure = cut_null(sz_temporary_f } // namespace meta -void client_thread(transport::accepted_context::value raw_value, int directory_fd) +void client_thread(const transport::accepted_client *accepted_client, int directory_fd) { - const transport::accepted_context ctx{raw_value}; - assert(ctx); + assert(accepted_client); + std::unique_ptr accepted_client_deleter{accepted_client}; std::array buffer; - auto url = transport::read_request(ctx.get_ctx(), buffer); + auto url = transport::read_request(accepted_client->get_ctx(), buffer); if (!url.size()) { - transport::send_response(ctx.get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::bad_request); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::bad_request); return; } @@ -60,15 +60,15 @@ void client_thread(transport::accepted_context::value { case url_too_short: error::occurred("parse URL", []{error::g_log << meta::sz_url_too_short << "." << std::endl;}); - transport::send_response(ctx.get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::url_too_short); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_59_BAD_REQUEST, meta::url_too_short); return; case url_non_gemini: error::occurred("parse URL", []{error::g_log << meta::sz_non_gemini << "." << std::endl;}); - transport::send_response(ctx.get_ctx(), gemini::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); return; case url_root_traverse: error::occurred("parse URL", []{error::g_log << meta::sz_root_traverse << "." << std::endl;}); - transport::send_response(ctx.get_ctx(), gemini::STATUS_50_PERMANENT_FAILURE, meta::root_traverse); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_50_PERMANENT_FAILURE, meta::root_traverse); return; case url_ok: @@ -80,10 +80,10 @@ void client_thread(transport::accepted_context::value switch (open_file_result) { case file_not_found: - transport::send_response(ctx.get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_51_NOT_FOUND, meta::not_found); return; case file_opening_error: - transport::send_response(ctx.get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::temporary_failure); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_40_TEMPORARY_FAILURE, meta::temporary_failure); return; case file_opened: @@ -92,7 +92,7 @@ void client_thread(transport::accepted_context::value } // > If is an empty string, the MIME type MUST default to "text/gemini; charset=utf-8". - transport::send_response(ctx.get_ctx(), gemini::STATUS_20_SUCCESS, {}); + transport::send_response(accepted_client->get_ctx(), gemini::STATUS_20_SUCCESS, {}); for (; ; ) { const auto ret = read(opened_file.get(), buffer.data(), buffer.size()); @@ -110,7 +110,7 @@ void client_thread(transport::accepted_context::value const auto readed = static_cast(ret); if (readed) { - if (!transport::send(ctx.get_ctx(), span{buffer.data(), readed})) + if (!transport::send(accepted_client->get_ctx(), span{buffer.data(), readed})) return; } if (readed < buffer.size()) @@ -131,36 +131,28 @@ bool server_loop(int server_socket, not_null accepted_client{ + new transport::accepted_client(server_socket, ctx) + }; + if (accepted_client->is_accepted()) { - error::occurred("Accept socket", error::print{}); - continue; + try + { + std::thread{client_thread, accepted_client.get(), directory_fd}.detach(); + accepted_client.release(); // move ownership to thread + } + catch (const std::system_error &e) + { + error::occurred( + "Create client thread", + [&e] + { + error::g_log << "Error: " << std::dec << e.code() + << ". " << e.what() << std::endl; + } + ); + } } - - transport::accepted_context client_ctx; - transport::accept(ctx, client_socket, client_ctx); - if (!client_ctx) - continue; - - try - { - std::thread{client_thread, client_ctx.get(), directory_fd}.detach(); - client_ctx.release(); // move ownership to thread - } - catch (const std::system_error &e) - { - error::occurred( - "Create client thread", - [&e] - { - error::g_log << "Error: " << std::dec << e.code() - << ". " << e.what() << std::endl; - } - ); - } } return true; }