diff --git a/Tests/LibCore/TestLibCoreStream.cpp b/Tests/LibCore/TestLibCoreStream.cpp index 395b0dfa28..ebfc49c176 100644 --- a/Tests/LibCore/TestLibCoreStream.cpp +++ b/Tests/LibCore/TestLibCoreStream.cpp @@ -148,9 +148,11 @@ TEST_CASE(tcp_socket_read) // Core::EventLoop through Core::Notifier. Core::EventLoop event_loop; - auto tcp_server = Core::TCPServer::construct(); - EXPECT(tcp_server->listen({ 127, 0, 0, 1 }, 9090)); - tcp_server->set_blocking(true); + auto maybe_tcp_server = Core::TCPServer::try_create(); + EXPECT(!maybe_tcp_server.is_error()); + auto tcp_server = maybe_tcp_server.release_value(); + EXPECT(!tcp_server->listen({ 127, 0, 0, 1 }, 9090).is_error()); + EXPECT(!tcp_server->set_blocking(true).is_error()); auto maybe_client_socket = Core::Stream::TCPSocket::connect({ { 127, 0, 0, 1 }, 9090 }); EXPECT(!maybe_client_socket.is_error()); @@ -181,9 +183,11 @@ TEST_CASE(tcp_socket_write) { Core::EventLoop event_loop; - auto tcp_server = Core::TCPServer::construct(); - EXPECT(tcp_server->listen({ 127, 0, 0, 1 }, 9090)); - tcp_server->set_blocking(true); + auto maybe_tcp_server = Core::TCPServer::try_create(); + EXPECT(!maybe_tcp_server.is_error()); + auto tcp_server = maybe_tcp_server.release_value(); + EXPECT(!tcp_server->listen({ 127, 0, 0, 1 }, 9090).is_error()); + EXPECT(!tcp_server->set_blocking(true).is_error()); auto maybe_client_socket = Core::Stream::TCPSocket::connect({ { 127, 0, 0, 1 }, 9090 }); EXPECT(!maybe_client_socket.is_error()); @@ -210,9 +214,11 @@ TEST_CASE(tcp_socket_eof) { Core::EventLoop event_loop; - auto tcp_server = Core::TCPServer::construct(); - EXPECT(tcp_server->listen({ 127, 0, 0, 1 }, 9090)); - tcp_server->set_blocking(true); + auto maybe_tcp_server = Core::TCPServer::try_create(); + EXPECT(!maybe_tcp_server.is_error()); + auto tcp_server = maybe_tcp_server.release_value(); + EXPECT(!tcp_server->listen({ 127, 0, 0, 1 }, 9090).is_error()); + EXPECT(!tcp_server->set_blocking(true).is_error()); auto maybe_client_socket = Core::Stream::TCPSocket::connect({ { 127, 0, 0, 1 }, 9090 }); EXPECT(!maybe_client_socket.is_error()); @@ -404,9 +410,11 @@ TEST_CASE(buffered_tcp_socket_read) { Core::EventLoop event_loop; - auto tcp_server = Core::TCPServer::construct(); - EXPECT(tcp_server->listen({ 127, 0, 0, 1 }, 9090)); - tcp_server->set_blocking(true); + auto maybe_tcp_server = Core::TCPServer::try_create(); + EXPECT(!maybe_tcp_server.is_error()); + auto tcp_server = maybe_tcp_server.release_value(); + EXPECT(!tcp_server->listen({ 127, 0, 0, 1 }, 9090).is_error()); + EXPECT(!tcp_server->set_blocking(true).is_error()); auto maybe_client_socket = Core::Stream::TCPSocket::connect({ { 127, 0, 0, 1 }, 9090 }); EXPECT(!maybe_client_socket.is_error()); diff --git a/Userland/Libraries/LibCore/TCPServer.cpp b/Userland/Libraries/LibCore/TCPServer.cpp index 7ef5b0bcba..52119000d6 100644 --- a/Userland/Libraries/LibCore/TCPServer.cpp +++ b/Userland/Libraries/LibCore/TCPServer.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,53 +8,47 @@ #include #include #include +#include #include #include -#include -#include -#include -#include -#ifndef SOCK_NONBLOCK -# include -#endif namespace Core { -TCPServer::TCPServer(Object* parent) - : Object(parent) +ErrorOr> TCPServer::try_create(Object* parent) { #ifdef SOCK_NONBLOCK - m_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + int fd = TRY(Core::System::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); #else - m_fd = socket(AF_INET, SOCK_STREAM, 0); + int fd = TRY(Core::System::socket(AF_INET, SOCK_STREAM, 0)); int option = 1; - ioctl(m_fd, FIONBIO, &option); - fcntl(m_fd, F_SETFD, FD_CLOEXEC); + TRY(Core::System::ioctl(fd, FIONBIO, &option)); + TRY(Core::System::fcntl(fd, F_SETFD, FD_CLOEXEC)); #endif + + return adopt_nonnull_ref_or_enomem(new (nothrow) TCPServer(fd, parent)); +} + +TCPServer::TCPServer(int fd, Object* parent) + : Object(parent) + , m_fd(fd) +{ VERIFY(m_fd >= 0); } TCPServer::~TCPServer() { - ::close(m_fd); + MUST(Core::System::close(m_fd)); } -bool TCPServer::listen(const IPv4Address& address, u16 port) +ErrorOr TCPServer::listen(IPv4Address const& address, u16 port) { if (m_listening) - return false; + return Error::from_errno(EADDRINUSE); auto socket_address = SocketAddress(address, port); auto in = socket_address.to_sockaddr_in(); - if (::bind(m_fd, (const sockaddr*)&in, sizeof(in)) < 0) { - perror("TCPServer::listen: bind"); - return false; - } - - if (::listen(m_fd, 5) < 0) { - perror("TCPServer::listen: listen"); - return false; - } + TRY(Core::System::bind(m_fd, (sockaddr const*)&in, sizeof(in))); + TRY(Core::System::listen(m_fd, 5)); m_listening = true; m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this); @@ -61,18 +56,17 @@ bool TCPServer::listen(const IPv4Address& address, u16 port) if (on_ready_to_accept) on_ready_to_accept(); }; - return true; + return {}; } -void TCPServer::set_blocking(bool blocking) +ErrorOr TCPServer::set_blocking(bool blocking) { - int flags = fcntl(m_fd, F_GETFL, 0); - VERIFY(flags >= 0); + int flags = TRY(Core::System::fcntl(m_fd, F_GETFL, 0)); if (blocking) - flags = fcntl(m_fd, F_SETFL, flags & ~O_NONBLOCK); + TRY(Core::System::fcntl(m_fd, F_SETFL, flags & ~O_NONBLOCK)); else - flags = fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); - VERIFY(flags == 0); + TRY(Core::System::fcntl(m_fd, F_SETFL, flags | O_NONBLOCK)); + return {}; } ErrorOr TCPServer::accept() @@ -81,15 +75,11 @@ ErrorOr TCPServer::accept() sockaddr_in in; socklen_t in_size = sizeof(in); #ifndef AK_OS_MACOS - int accepted_fd = ::accept4(m_fd, (sockaddr*)&in, &in_size, SOCK_NONBLOCK | SOCK_CLOEXEC); + int accepted_fd = TRY(Core::System::accept4(m_fd, (sockaddr*)&in, &in_size, SOCK_NONBLOCK | SOCK_CLOEXEC)); #else - int accepted_fd = ::accept(m_fd, (sockaddr*)&in, &in_size); + int accepted_fd = TRY(Core::System::accept(m_fd, (sockaddr*)&in, &in_size)); #endif - if (accepted_fd < 0) { - return Error::from_errno(errno); - } - auto socket = TRY(Stream::TCPSocket::adopt_fd(accepted_fd)); #ifdef AK_OS_MACOS diff --git a/Userland/Libraries/LibCore/TCPServer.h b/Userland/Libraries/LibCore/TCPServer.h index 0c058a9df2..33d0cf3648 100644 --- a/Userland/Libraries/LibCore/TCPServer.h +++ b/Userland/Libraries/LibCore/TCPServer.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -14,13 +15,14 @@ namespace Core { class TCPServer : public Object { - C_OBJECT(TCPServer) + C_OBJECT_ABSTRACT(TCPServer) public: + static ErrorOr> try_create(Object* parent = nullptr); virtual ~TCPServer() override; bool is_listening() const { return m_listening; } - bool listen(const IPv4Address& address, u16 port); - void set_blocking(bool blocking); + ErrorOr listen(IPv4Address const& address, u16 port); + ErrorOr set_blocking(bool blocking); ErrorOr accept(); @@ -30,7 +32,7 @@ public: Function on_ready_to_accept; private: - explicit TCPServer(Object* parent = nullptr); + explicit TCPServer(int fd, Object* parent = nullptr); int m_fd { -1 }; bool m_listening { false }; diff --git a/Userland/Services/EchoServer/main.cpp b/Userland/Services/EchoServer/main.cpp index 5a7db00aa5..50eb7fa948 100644 --- a/Userland/Services/EchoServer/main.cpp +++ b/Userland/Services/EchoServer/main.cpp @@ -31,12 +31,8 @@ ErrorOr serenity_main(Main::Arguments arguments) Core::EventLoop event_loop; - auto server = Core::TCPServer::construct(); - - if (!server->listen({}, port)) { - warnln("Listening on 0.0.0.0:{} failed", port); - exit(1); - } + auto server = TRY(Core::TCPServer::try_create()); + TRY(server->listen({}, port)); HashMap> clients; int next_id = 0; diff --git a/Userland/Services/TelnetServer/main.cpp b/Userland/Services/TelnetServer/main.cpp index 7d274c98a2..3859d27297 100644 --- a/Userland/Services/TelnetServer/main.cpp +++ b/Userland/Services/TelnetServer/main.cpp @@ -97,12 +97,8 @@ ErrorOr serenity_main(Main::Arguments arguments) } Core::EventLoop event_loop; - auto server = Core::TCPServer::construct(); - - if (!server->listen({}, port)) { - warnln("Listening on 0.0.0.0:{} failed", port); - exit(1); - } + auto server = TRY(Core::TCPServer::try_create()); + TRY(server->listen({}, port)); HashMap> clients; int next_id = 0; diff --git a/Userland/Services/WebServer/main.cpp b/Userland/Services/WebServer/main.cpp index d78aef0fbb..51e805d1dd 100644 --- a/Userland/Services/WebServer/main.cpp +++ b/Userland/Services/WebServer/main.cpp @@ -89,10 +89,7 @@ ErrorOr serenity_main(Main::Arguments arguments) client->start(); }; - if (!server->listen(ipv4_address.value(), port)) { - warnln("Failed to listen on {}:{}", ipv4_address.value(), port); - return 1; - } + TRY(server->listen(ipv4_address.value(), port)); outln("Listening on {}:{}", ipv4_address.value(), port);