diff --git a/base/files/file_util_starboard.cc b/base/files/file_util_starboard.cc index bcec62a16edd..d6e56f205083 100644 --- a/base/files/file_util_starboard.cc +++ b/base/files/file_util_starboard.cc @@ -477,6 +477,17 @@ FilePath MakeAbsoluteFilePath(const FilePath& input) { return input; } +bool SetNonBlocking(int fd) { + const int flags = fcntl(fd, F_GETFL); + if (flags == -1) + return false; + if (flags & O_NONBLOCK) + return true; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + return false; + return true; +} + namespace internal { bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) { diff --git a/base/message_loop/message_pump_io_starboard.cc b/base/message_loop/message_pump_io_starboard.cc index 714012b8c455..2f38614583e0 100644 --- a/base/message_loop/message_pump_io_starboard.cc +++ b/base/message_loop/message_pump_io_starboard.cc @@ -14,6 +14,12 @@ #include "base/message_loop/message_pump_io_starboard.h" +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +#include +#include +#include +#endif + #include "base/auto_reset.h" #include "base/compiler_specific.h" #include "base/logging.h" @@ -28,17 +34,46 @@ namespace base { MessagePumpIOStarboard::SocketWatcher::SocketWatcher(const Location& from_here) : created_from_location_(from_here), interests_(kSbSocketWaiterInterestNone), +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + socket_(-1), +#else socket_(kSbSocketInvalid), +#endif pump_(nullptr), watcher_(nullptr), weak_factory_(this) {} MessagePumpIOStarboard::SocketWatcher::~SocketWatcher() { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + if (socket_ >= 0) { + StopWatchingFileDescriptor(); + } +#else if (SbSocketIsValid(socket_)) { StopWatchingSocket(); } +#endif } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool MessagePumpIOStarboard::SocketWatcher::StopWatchingFileDescriptor() { + watcher_ = nullptr; + interests_ = kSbSocketWaiterInterestNone; + if (socket_ < 0) { + pump_ = nullptr; + // If this watcher is not watching anything, no-op and return success. + return true; + } + int socket = Release(); + bool result = true; + if (socket >= 0) { + DCHECK(pump_); + result = pump_->StopWatchingFileDescriptor(socket); + } + pump_ = nullptr; + return result; +} +#else bool MessagePumpIOStarboard::SocketWatcher::StopWatchingSocket() { watcher_ = nullptr; interests_ = kSbSocketWaiterInterestNone; @@ -64,21 +99,59 @@ bool MessagePumpIOStarboard::SocketWatcher::StopWatchingSocket() { pump_ = nullptr; return result; } +#endif +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +void MessagePumpIOStarboard::SocketWatcher::Init(int socket, + bool persistent) { + DCHECK(socket >= 0); + DCHECK(socket_ < 0); +#else void MessagePumpIOStarboard::SocketWatcher::Init(SbSocket socket, bool persistent) { DCHECK(socket); DCHECK(!socket_); +#endif socket_ = socket; persistent_ = persistent; } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +int MessagePumpIOStarboard::SocketWatcher::Release() { + int socket = socket_; + socket_ = -1; + return socket; +} +#else SbSocket MessagePumpIOStarboard::SocketWatcher::Release() { SbSocket socket = socket_; socket_ = kSbSocketInvalid; return socket; } +#endif + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +void MessagePumpIOStarboard::SocketWatcher::OnFileCanReadWithoutBlocking( + int socket, + MessagePumpIOStarboard* pump) { + if (!watcher_) + return; + pump->WillProcessIOEvent(); + watcher_->OnFileCanReadWithoutBlocking(socket); + pump->DidProcessIOEvent(); +} + +void MessagePumpIOStarboard::SocketWatcher::OnFileCanWriteWithoutBlocking( + int socket, + MessagePumpIOStarboard* pump) { + if (!watcher_) + return; + pump->WillProcessIOEvent(); + watcher_->OnFileCanWriteWithoutBlocking(socket); + pump->DidProcessIOEvent(); +} +#else void MessagePumpIOStarboard::SocketWatcher::OnSocketReadyToRead( SbSocket socket, MessagePumpIOStarboard* pump) { @@ -98,6 +171,7 @@ void MessagePumpIOStarboard::SocketWatcher::OnSocketReadyToWrite( watcher_->OnSocketReadyToWrite(socket); pump->DidProcessIOEvent(); } +#endif MessagePumpIOStarboard::MessagePumpIOStarboard() : keep_running_(true), @@ -109,12 +183,21 @@ MessagePumpIOStarboard::~MessagePumpIOStarboard() { SbSocketWaiterDestroy(waiter_); } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool MessagePumpIOStarboard::WatchFileDescriptor(int socket, + bool persistent, + int mode, + SocketWatcher* controller, + Watcher* delegate) { + DCHECK(socket >= 0); +#else bool MessagePumpIOStarboard::Watch(SbSocket socket, bool persistent, int mode, SocketWatcher* controller, Watcher* delegate) { DCHECK(SbSocketIsValid(socket)); +#endif DCHECK(controller); DCHECK(delegate); DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE); @@ -130,8 +213,13 @@ bool MessagePumpIOStarboard::Watch(SbSocket socket, interests |= kSbSocketWaiterInterestWrite; } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + int old_socket = controller->Release(); + if (old_socket >= 0) { +#else SbSocket old_socket = controller->Release(); if (SbSocketIsValid(old_socket)) { +#endif // It's illegal to use this function to listen on 2 separate fds with the // same |controller|. if (old_socket != socket) { @@ -148,12 +236,24 @@ bool MessagePumpIOStarboard::Watch(SbSocket socket, interests |= old_interest_mask; // Must disarm the event before we can reuse it. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + SbPosixSocketWaiterRemove(waiter_, old_socket); +#else SbSocketWaiterRemove(waiter_, old_socket); +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) } // Set current interest mask and waiter for this event. - if (!SbSocketWaiterAdd(waiter_, socket, controller, - OnSocketWaiterNotification, interests, persistent)) { + bool result = false; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + result = SbPosixSocketWaiterAdd(waiter_, socket, controller, + OnPosixSocketWaiterNotification, interests, persistent); + +#else + result = SbSocketWaiterAdd(waiter_, socket, controller, + OnSocketWaiterNotification, interests, persistent); +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + if (result == false) { return false; } @@ -164,9 +264,15 @@ bool MessagePumpIOStarboard::Watch(SbSocket socket, return true; } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool MessagePumpIOStarboard::StopWatchingFileDescriptor(int socket) { + return SbPosixSocketWaiterRemove(waiter_, socket); +} +#else bool MessagePumpIOStarboard::StopWatching(SbSocket socket) { return SbSocketWaiterRemove(waiter_, socket); } +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) void MessagePumpIOStarboard::AddIOObserver(IOObserver* obs) { io_observers_.AddObserver(obs); @@ -259,6 +365,36 @@ void MessagePumpIOStarboard::DidProcessIOEvent() { } } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +// static +void MessagePumpIOStarboard::OnPosixSocketWaiterNotification(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) { + base::WeakPtr controller = + static_cast(context)->weak_factory_.GetWeakPtr(); + DCHECK(controller.get()); + + MessagePumpIOStarboard* pump = controller->pump(); + pump->processed_io_events_ = true; + + // If not persistent, the watch has been released at this point. + if (!controller->persistent()) { + controller->Release(); + } + + if (ready_interests & kSbSocketWaiterInterestWrite) { + controller->OnFileCanWriteWithoutBlocking(socket, pump); + } + + // Check |controller| in case it's been deleted previously. + if (controller.get() && ready_interests & kSbSocketWaiterInterestRead) { + controller->OnFileCanReadWithoutBlocking(socket, pump); + } +} + +#else // static void MessagePumpIOStarboard::OnSocketWaiterNotification(SbSocketWaiter waiter, SbSocket socket, @@ -286,4 +422,5 @@ void MessagePumpIOStarboard::OnSocketWaiterNotification(SbSocketWaiter waiter, } } +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) } // namespace base diff --git a/base/message_loop/message_pump_io_starboard.h b/base/message_loop/message_pump_io_starboard.h index b7d807dec914..55ce21570e80 100644 --- a/base/message_loop/message_pump_io_starboard.h +++ b/base/message_loop/message_pump_io_starboard.h @@ -15,6 +15,8 @@ #ifndef BASE_MESSAGE_PUMP_IO_STARBOARD_H_ #define BASE_MESSAGE_PUMP_IO_STARBOARD_H_ +#include "starboard/configuration.h" + #include "base/compiler_specific.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_pump.h" @@ -49,8 +51,13 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { public: // These methods are called from MessageLoop::Run when a socket can be // interacted with without blocking. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + virtual void OnFileCanReadWithoutBlocking(int socket) {} + virtual void OnFileCanWriteWithoutBlocking(int socket) {} +#else virtual void OnSocketReadyToRead(SbSocket socket) {} virtual void OnSocketReadyToWrite(SbSocket socket) {} +#endif protected: virtual ~Watcher() {} @@ -70,7 +77,11 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { // Stops watching the socket, always safe to call. No-op if there's nothing // to do. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool StopWatchingFileDescriptor(); +#else bool StopWatchingSocket(); +#endif bool persistent() const { return persistent_; } @@ -79,8 +90,13 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { friend class MessagePumpIOStarboardTest; // Called by MessagePumpIOStarboard. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void Init(int socket, bool persistent); + int Release(); +#else void Init(SbSocket socket, bool persistent); SbSocket Release(); +#endif int interests() const { return interests_; } void set_interests(int interests) { interests_ = interests; } @@ -90,12 +106,21 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { void set_watcher(Watcher* watcher) { watcher_ = watcher; } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanReadWithoutBlocking(int socket, MessagePumpIOStarboard* pump); + void OnFileCanWriteWithoutBlocking(int socket, MessagePumpIOStarboard* pump); +#else void OnSocketReadyToRead(SbSocket socket, MessagePumpIOStarboard* pump); void OnSocketReadyToWrite(SbSocket socket, MessagePumpIOStarboard* pump); +#endif const Location created_from_location_; int interests_; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + int socket_; +#else SbSocket socket_; +#endif bool persistent_; MessagePumpIOStarboard* pump_; Watcher* watcher_; @@ -123,6 +148,16 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { // If an error occurs while calling this method in a cumulative fashion, the // event previously attached to |controller| is aborted. Returns true on // success. Must be called on the same thread the message_pump is running on. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool WatchFileDescriptor(int socket, + bool persistent, + int mode, + SocketWatcher* controller, + Watcher* delegate); + + // Stops watching the socket. + bool StopWatchingFileDescriptor(int socket); +#else bool Watch(SbSocket socket, bool persistent, int mode, @@ -131,6 +166,7 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { // Stops watching the socket. bool StopWatching(SbSocket socket); +#endif void AddIOObserver(IOObserver* obs); void RemoveIOObserver(IOObserver* obs); @@ -149,10 +185,17 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { // Called by SbSocketWaiter to tell us a registered socket can be read and/or // written to. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + static void OnPosixSocketWaiterNotification(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests); +#else static void OnSocketWaiterNotification(SbSocketWaiter waiter, SbSocket socket, void* context, int ready_interests); +#endif bool should_quit() const { return !keep_running_; } diff --git a/base/message_loop/message_pump_io_starboard_unittest.cc b/base/message_loop/message_pump_io_starboard_unittest.cc index c6231f70d882..4b4c7dcac6d9 100644 --- a/base/message_loop/message_pump_io_starboard_unittest.cc +++ b/base/message_loop/message_pump_io_starboard_unittest.cc @@ -18,6 +18,12 @@ #include +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +#include +#include +#include +#endif + #include "base/functional/bind.h" #include "base/run_loop.h" #include "base/synchronization/waitable_event.h" @@ -42,8 +48,12 @@ class MessagePumpIOStarboardTest : public testing::Test { void SetUp() override { Thread::Options options(MessagePumpType::IO, 0); ASSERT_TRUE(io_thread_.StartWithOptions(std::move(options))); +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + socket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +#else socket_ = SbSocketCreate(SbSocketAddressType::kSbSocketAddressTypeIpv4, SbSocketProtocol::kSbSocketProtocolTcp); SbSocketIsValid(socket_); +#endif } void TearDown() override { @@ -52,33 +62,56 @@ class MessagePumpIOStarboardTest : public testing::Test { // pipe. io_thread_.Stop(); +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + close(socket_); +#else SbSocketDestroy(socket_); +#endif } std::unique_ptr CreateMessagePump() { return std::make_unique(); } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + int socket() { + return socket_; + } +#else SbSocket socket() { return socket_; } +#endif scoped_refptr io_runner() const { return io_thread_.task_runner(); } void SimulateIOEvent(MessagePumpIOStarboard::SocketWatcher* controller) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + MessagePumpIOStarboard::OnPosixSocketWaiterNotification(nullptr, + -1, + controller, + (kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite)); + +#else + MessagePumpIOStarboard::OnSocketWaiterNotification(nullptr, nullptr, controller, (kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite)); +#endif } std::unique_ptr task_environment_; private: Thread io_thread_; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + int socket_; +#else SbSocket socket_; +#endif }; namespace { @@ -90,8 +123,13 @@ class StupidWatcher : public MessagePumpIOStarboard::Watcher { ~StupidWatcher() override = default; // MessagePumpIOStarboard::Watcher interface +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanReadWithoutBlocking(int socket) override {} + void OnFileCanWriteWithoutBlocking(int socket) override {} +#else void OnSocketReadyToRead(SbSocket socket) override {} void OnSocketReadyToWrite(SbSocket socket) override {} +#endif }; // Death tests not supported. @@ -106,8 +144,13 @@ class BaseWatcher : public MessagePumpIOStarboard::Watcher { ~BaseWatcher() override = default; // MessagePumpIOStarboard::Watcher interface +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanReadWithoutBlocking(int socket) override { NOTREACHED(); } + void OnFileCanWriteWithoutBlocking(int socket) override { NOTREACHED(); } +#else void OnSocketReadyToRead(SbSocket socket) override { NOTREACHED(); } void OnSocketReadyToWrite(SbSocket socket) override { NOTREACHED(); } +#endif }; class DeleteWatcher : public BaseWatcher { @@ -122,7 +165,11 @@ class DeleteWatcher : public BaseWatcher { return controller_.get(); } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanWriteWithoutBlocking(int socket) override { +#else void OnSocketReadyToWrite(SbSocket socket) override { +#endif DCHECK(controller_); controller_.reset(); } @@ -136,7 +183,11 @@ TEST_F(MessagePumpIOStarboardTest, DISABLED_DeleteWatcher) { DeleteWatcher delegate( std::make_unique(FROM_HERE)); std::unique_ptr pump = CreateMessagePump(); +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + pump->WatchFileDescriptor(socket(), +#else pump->Watch(socket(), +#endif /*persistent=*/false, MessagePumpIOStarboard::WATCH_READ_WRITE, delegate.controller(), @@ -151,9 +202,16 @@ class StopWatcher : public BaseWatcher { ~StopWatcher() override = default; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanWriteWithoutBlocking(int socket) override { + controller_->StopWatchingFileDescriptor(); + } +#else void OnSocketReadyToWrite(SbSocket socket) override { controller_->StopWatchingSocket(); } +#endif + private: raw_ptr controller_ = nullptr; @@ -164,7 +222,11 @@ TEST_F(MessagePumpIOStarboardTest, DISABLED_StopWatcher) { std::unique_ptr pump = CreateMessagePump(); MessagePumpIOStarboard::SocketWatcher controller(FROM_HERE); StopWatcher delegate(&controller); +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + pump->WatchFileDescriptor(socket(), +#else pump->Watch(socket(), +#endif /*persistent=*/false, MessagePumpIOStarboard::WATCH_READ_WRITE, &controller, @@ -186,22 +248,35 @@ class NestedPumpWatcher : public MessagePumpIOStarboard::Watcher { NestedPumpWatcher() = default; ~NestedPumpWatcher() override = default; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanReadWithoutBlocking(int socket) override { +#else void OnSocketReadyToRead(SbSocket socket) override { +#endif RunLoop runloop; SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, BindOnce(&QuitMessageLoopAndStart, runloop.QuitClosure())); runloop.Run(); } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanWriteWithoutBlocking(int socket) override {} +}; +#else void OnSocketReadyToWrite(SbSocket socket) override {} }; +#endif // Fails on some platforms. TEST_F(MessagePumpIOStarboardTest, DISABLED_NestedPumpWatcher) { NestedPumpWatcher delegate; std::unique_ptr pump = CreateMessagePump(); MessagePumpIOStarboard::SocketWatcher controller(FROM_HERE); +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + pump->WatchFileDescriptor(socket(), +#else pump->Watch(socket(), +#endif /*persistent=*/false, MessagePumpIOStarboard::WATCH_READ, &controller, @@ -218,7 +293,11 @@ class QuitWatcher : public BaseWatcher { QuitWatcher(base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + void OnFileCanReadWithoutBlocking(int socket) override { +#else void OnSocketReadyToRead(SbSocket socket) override { +#endif // Post a fatal closure to the MessageLoop before we quit it. SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, BindOnce(&FatalClosure)); @@ -252,7 +331,11 @@ TEST_F(MessagePumpIOStarboardTest, DISABLED_QuitWatcher) { std::unique_ptr watcher(new WaitableEventWatcher); // Tell the pump to watch the pipe. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + pump->WatchFileDescriptor(socket(), +#else pump->Watch(socket(), +#endif /*persistent=*/false, MessagePumpIOStarboard::WATCH_READ, &controller, diff --git a/base/task/current_thread.cc b/base/task/current_thread.cc index 673e2028d4a2..72d61befbf8a 100644 --- a/base/task/current_thread.cc +++ b/base/task/current_thread.cc @@ -212,6 +212,16 @@ MessagePumpForIO* CurrentIOThread::GetMessagePumpForIO() const { #if !BUILDFLAG(IS_NACL) #if defined(STARBOARD) +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool CurrentIOThread::WatchFileDescriptor(int socket, + bool persistent, + int mode, + SocketWatcher* controller, + Watcher* delegate) { + return static_cast(GetMessagePumpForIO()) + ->WatchFileDescriptor(socket, persistent, mode, controller, delegate); +} +#else bool CurrentIOThread::Watch(SbSocket socket, bool persistent, int mode, @@ -220,6 +230,9 @@ bool CurrentIOThread::Watch(SbSocket socket, return static_cast(GetMessagePumpForIO()) ->Watch(socket, persistent, mode, controller, delegate); } +#endif + + #elif BUILDFLAG(IS_WIN) HRESULT CurrentIOThread::RegisterIOHandler( HANDLE file, diff --git a/base/task/current_thread.h b/base/task/current_thread.h index 5106c5e9fd71..5303e2b2abbf 100644 --- a/base/task/current_thread.h +++ b/base/task/current_thread.h @@ -279,11 +279,20 @@ class BASE_EXPORT CurrentIOThread : public CurrentThread { WATCH_WRITE = base::MessagePumpIOStarboard::WATCH_WRITE, WATCH_READ_WRITE = base::MessagePumpIOStarboard::WATCH_READ_WRITE}; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool WatchFileDescriptor(int socket, + bool persistent, + int mode, + SocketWatcher* controller, + Watcher* delegate); +#else bool Watch(SbSocket socket, bool persistent, int mode, SocketWatcher* controller, Watcher* delegate); +#endif + #elif BUILDFLAG(IS_WIN) // Please see MessagePumpWin for definitions of these methods. HRESULT RegisterIOHandler(HANDLE file, MessagePumpForIO::IOHandler* handler); diff --git a/net/BUILD.gn b/net/BUILD.gn index ec5057e993fc..a416fa2c3b94 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -1175,6 +1175,16 @@ component("net") { "socket/tcp_socket_starboard.h", "socket/udp_socket_starboard.cc", "socket/udp_socket_starboard.h", + # Use POSIX socket for SB16 + "base/net_errors_posix.cc", + "base/sockaddr_util_posix.cc", + "base/sockaddr_util_posix.h", + "socket/tcp_socket_posix.cc", + "socket/tcp_socket_posix.h", + "socket/udp_socket_posix.cc", + "socket/udp_socket_posix.h", + "socket/socket_posix.cc", + "socket/socket_posix.h", ] deps += [ "//starboard:starboard_group" ] } diff --git a/net/base/address_family.cc b/net/base/address_family.cc index d6db1ffc3087..835f55801211 100644 --- a/net/base/address_family.cc +++ b/net/base/address_family.cc @@ -20,7 +20,7 @@ AddressFamily GetAddressFamily(const IPAddress& address) { } } -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) SbSocketAddressType ConvertAddressFamily(AddressFamily address_family) { switch (address_family) { case ADDRESS_FAMILY_IPV4: diff --git a/net/base/address_family.h b/net/base/address_family.h index 90f2be5181ff..1f55819c9447 100644 --- a/net/base/address_family.h +++ b/net/base/address_family.h @@ -42,7 +42,7 @@ typedef int HostResolverFlags; // Returns AddressFamily for |address|. NET_EXPORT AddressFamily GetAddressFamily(const IPAddress& address); -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) NET_EXPORT SbSocketAddressType ConvertAddressFamily( AddressFamily address_family); #else diff --git a/net/base/features.cc b/net/base/features.cc index f554886495be..3bc1d079d179 100644 --- a/net/base/features.cc +++ b/net/base/features.cc @@ -212,7 +212,8 @@ BASE_FEATURE(kDocumentReporting, base::FEATURE_ENABLED_BY_DEFAULT); #endif // BUILDFLAG(ENABLE_REPORTING) -#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) BASE_FEATURE(kUdpSocketPosixAlwaysUpdateBytesReceived, "UdpSocketPosixAlwaysUpdateBytesReceived", base::FEATURE_ENABLED_BY_DEFAULT); diff --git a/net/base/features.h b/net/base/features.h index 2c235b37f768..e06f1c4a5c92 100644 --- a/net/base/features.h +++ b/net/base/features.h @@ -261,14 +261,16 @@ NET_EXPORT extern const base::FeatureParam NET_EXPORT BASE_DECLARE_FEATURE(kDocumentReporting); #endif // BUILDFLAG(ENABLE_REPORTING) -#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) // When enabled, UDPSocketPosix increments the global counter of bytes received // every time bytes are received, instead of using a timer to batch updates. // This should reduce the number of wake ups and improve battery consumption. // TODO(https://crbug.com/1189805): Cleanup the feature after verifying that it // doesn't negatively affect performance. NET_EXPORT BASE_DECLARE_FEATURE(kUdpSocketPosixAlwaysUpdateBytesReceived); -#endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || + // (SB_API_VERSION >= 16 && !defined(_MSC_VER)) // When this feature is enabled, redirected requests will be considered // cross-site for the purpose of SameSite cookies if any redirect hop was diff --git a/net/base/net_errors_posix.cc b/net/base/net_errors_posix.cc index df49829735bd..9cc87db6246c 100644 --- a/net/base/net_errors_posix.cc +++ b/net/base/net_errors_posix.cc @@ -15,6 +15,8 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + Error MapSystemError(logging::SystemErrorCode os_error) { if (os_error != 0) DVLOG(2) << "Error " << os_error << ": " @@ -43,7 +45,9 @@ Error MapSystemError(logging::SystemErrorCode os_error) { case ECONNREFUSED: return ERR_CONNECTION_REFUSED; case EHOSTUNREACH: +#if defined(EHOSTDOWN) case EHOSTDOWN: +#endif case ENETUNREACH: case EAFNOSUPPORT: return ERR_ADDRESS_UNREACHABLE; @@ -69,8 +73,10 @@ Error MapSystemError(logging::SystemErrorCode os_error) { return ERR_ABORTED; case EDEADLK: // Resource deadlock avoided. return ERR_INSUFFICIENT_RESOURCES; +#if defined(EDQUOT) case EDQUOT: // Disk quota exceeded. return ERR_FILE_NO_SPACE; +#endif case EEXIST: // File exists. return ERR_FILE_EXISTS; case EFAULT: // Bad address. @@ -107,8 +113,10 @@ Error MapSystemError(logging::SystemErrorCode os_error) { return ERR_ACCESS_DENIED; case ETXTBSY: // Text file busy. return ERR_ACCESS_DENIED; +#if defined(EUSERS) case EUSERS: // Too many users. return ERR_INSUFFICIENT_RESOURCES; +#endif case EMFILE: // Too many open files. return ERR_INSUFFICIENT_RESOURCES; case ENOPROTOOPT: // Protocol option not supported. @@ -124,10 +132,11 @@ Error MapSystemError(logging::SystemErrorCode os_error) { case 0: return OK; default: - LOG(WARNING) << "Unknown error " << base::safe_strerror(os_error) << " (" + LOG(WARNING) << "Unknown error " << " (" << os_error << ") mapped to net::ERR_FAILED"; return ERR_FAILED; } } +#endif // SB_API_VERSION >= 16 && !defined(WIN32) } // namespace net diff --git a/net/base/net_errors_starboard.cc b/net/base/net_errors_starboard.cc index 7ed4aa304caa..ed4dc7f40599 100644 --- a/net/base/net_errors_starboard.cc +++ b/net/base/net_errors_starboard.cc @@ -24,6 +24,8 @@ namespace net { +#if SB_API_VERSION <= 15 || defined(_MSC_VER) + Error MapSystemError(logging::SystemErrorCode error) { if (error != 0) { char error_string[256]; @@ -58,4 +60,6 @@ Error MapSocketError(SbSocketError error) { } } +#endif // SB_API_VERSION <= 15 || defined(_MSC_VER) + } // namespace net diff --git a/net/base/sockaddr_util_posix.cc b/net/base/sockaddr_util_posix.cc index 583b15a23ac7..cb33e47d0867 100644 --- a/net/base/sockaddr_util_posix.cc +++ b/net/base/sockaddr_util_posix.cc @@ -16,6 +16,8 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool FillUnixAddress(const std::string& socket_path, bool use_abstract_namespace, SockaddrStorage* address) { @@ -54,4 +56,6 @@ bool FillUnixAddress(const std::string& socket_path, #endif } +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net diff --git a/net/socket/socket_descriptor.cc b/net/socket/socket_descriptor.cc index 4880f0ee1b57..7a3c18602ce7 100644 --- a/net/socket/socket_descriptor.cc +++ b/net/socket/socket_descriptor.cc @@ -6,13 +6,14 @@ #include "build/build_config.h" -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) #include "starboard/socket.h" #include "base/notreached.h" #elif BUILDFLAG(IS_WIN) #include #include "net/base/winsock_init.h" -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) #include #include #endif @@ -24,7 +25,7 @@ namespace net { SocketDescriptor CreatePlatformSocket(int family, int type, int protocol) { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) NOTREACHED(); return kSbSocketInvalid; #elif BUILDFLAG(IS_WIN) @@ -40,7 +41,8 @@ SocketDescriptor CreatePlatformSocket(int family, int type, int protocol) { } } return result; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) SocketDescriptor result = ::socket(family, type, protocol); #if BUILDFLAG(IS_APPLE) // Disable SIGPIPE on this socket. Although Chromium globally disables diff --git a/net/socket/socket_descriptor.h b/net/socket/socket_descriptor.h index 032cb73d5cb1..c79c0221bd97 100644 --- a/net/socket/socket_descriptor.h +++ b/net/socket/socket_descriptor.h @@ -17,12 +17,13 @@ namespace net { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) typedef SbSocket SocketDescriptor; #elif BUILDFLAG(IS_WIN) typedef UINT_PTR SocketDescriptor; const SocketDescriptor kInvalidSocket = (SocketDescriptor)(~0); -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) typedef int SocketDescriptor; const SocketDescriptor kInvalidSocket = -1; #endif diff --git a/net/socket/socket_options.cc b/net/socket/socket_options.cc index 7f23a600a2da..cb9a327b19fc 100644 --- a/net/socket/socket_options.cc +++ b/net/socket/socket_options.cc @@ -9,12 +9,13 @@ #include "build/build_config.h" #include "net/base/net_errors.h" -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) #include "base/notreached.h" #elif BUILDFLAG(IS_WIN) #include #include -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) #include #include #include @@ -23,12 +24,14 @@ namespace net { int SetTCPNoDelay(SocketDescriptor fd, bool no_delay) { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) return SbSocketSetTcpNoDelay(fd, no_delay) ? OK : ERR_FAILED; #else + #if BUILDFLAG(IS_WIN) BOOL on = no_delay ? TRUE : FALSE; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) int on = no_delay ? 1 : 0; #endif int rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, @@ -38,7 +41,7 @@ int SetTCPNoDelay(SocketDescriptor fd, bool no_delay) { } int SetReuseAddr(SocketDescriptor fd, bool reuse) { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) return SbSocketSetReuseAddress(fd, reuse) ? OK : ERR_FAILED; #else // SO_REUSEADDR is useful for server sockets to bind to a recently unbound @@ -56,7 +59,8 @@ int SetReuseAddr(SocketDescriptor fd, bool reuse) { // SO_REUSEPORT is provided in MacOS X and iOS. #if BUILDFLAG(IS_WIN) BOOL boolean_value = reuse ? TRUE : FALSE; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) int boolean_value = reuse ? 1 : 0; #endif int rv = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, @@ -67,14 +71,15 @@ int SetReuseAddr(SocketDescriptor fd, bool reuse) { } int SetSocketReceiveBufferSize(SocketDescriptor fd, int32_t size) { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) return SbSocketSetReceiveBufferSize(fd, size) ? OK : ERR_FAILED; #else int rv = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&size), sizeof(size)); #if BUILDFLAG(IS_WIN) int os_error = WSAGetLastError(); -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) int os_error = errno; #endif int net_error = (rv == -1) ? MapSystemError(os_error) : OK; @@ -86,14 +91,15 @@ int SetSocketReceiveBufferSize(SocketDescriptor fd, int32_t size) { } int SetSocketSendBufferSize(SocketDescriptor fd, int32_t size) { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) return SbSocketSetSendBufferSize(fd, size) ? OK : ERR_FAILED; #else int rv = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&size), sizeof(size)); #if BUILDFLAG(IS_WIN) int os_error = WSAGetLastError(); -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) int os_error = errno; #endif int net_error = (rv == -1) ? MapSystemError(os_error) : OK; @@ -105,13 +111,14 @@ int SetSocketSendBufferSize(SocketDescriptor fd, int32_t size) { } int SetIPv6Only(SocketDescriptor fd, bool ipv6_only) { -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) NOTREACHED(); return -1; #else #if BUILDFLAG(IS_WIN) DWORD on = ipv6_only ? 1 : 0; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) int on = ipv6_only ? 1 : 0; #endif int rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, diff --git a/net/socket/socket_posix.cc b/net/socket/socket_posix.cc index ea3d794d9858..1155fe7548d4 100644 --- a/net/socket/socket_posix.cc +++ b/net/socket/socket_posix.cc @@ -33,6 +33,7 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) namespace { int MapAcceptError(int os_error) { @@ -70,9 +71,13 @@ int MapConnectError(int os_error) { SocketPosix::SocketPosix() : socket_fd_(kInvalidSocket), +#if defined(STARBOARD) + socket_watcher_(FROM_HERE) {} +#else accept_socket_watcher_(FROM_HERE), read_socket_watcher_(FROM_HERE), write_socket_watcher_(FROM_HERE) {} +#endif SocketPosix::~SocketPosix() { Close(); @@ -179,7 +184,11 @@ int SocketPosix::Accept(std::unique_ptr* socket, if (!base::CurrentIOThread::Get()->WatchFileDescriptor( socket_fd_, true, base::MessagePumpForIO::WATCH_READ, +#if defined(STARBOARD) + &socket_watcher_, this)) { +#else &accept_socket_watcher_, this)) { +#endif PLOG(ERROR) << "WatchFileDescriptor failed on accept"; return MapSystemError(errno); } @@ -204,7 +213,11 @@ int SocketPosix::Connect(const SockaddrStorage& address, if (!base::CurrentIOThread::Get()->WatchFileDescriptor( socket_fd_, true, base::MessagePumpForIO::WATCH_WRITE, +#if defined(STARBOARD) + &socket_watcher_, this)) { +#else &write_socket_watcher_, this)) { +#endif PLOG(ERROR) << "WatchFileDescriptor failed on connect"; return MapSystemError(errno); } @@ -224,7 +237,11 @@ int SocketPosix::Connect(const SockaddrStorage& address, rv = MapConnectError(errno); if (rv != OK && rv != ERR_IO_PENDING) { +#if defined(STARBOARD) + ClearWatcherIfOperationsNotPending(); +#else write_socket_watcher_.StopWatchingFileDescriptor(); +#endif return rv; } @@ -300,7 +317,11 @@ int SocketPosix::ReadIfReady(IOBuffer* buf, if (!base::CurrentIOThread::Get()->WatchFileDescriptor( socket_fd_, true, base::MessagePumpForIO::WATCH_READ, +#if defined(STARBOARD) + &socket_watcher_, this)) { +#else &read_socket_watcher_, this)) { +#endif PLOG(ERROR) << "WatchFileDescriptor failed on read"; return MapSystemError(errno); } @@ -312,7 +333,11 @@ int SocketPosix::ReadIfReady(IOBuffer* buf, int SocketPosix::CancelReadIfReady() { DCHECK(read_if_ready_callback_); +#if defined(STARBOARD) + bool ok = ClearWatcherIfOperationsNotPending(); +#else bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); +#endif DCHECK(ok); read_if_ready_callback_.Reset(); @@ -350,7 +375,11 @@ int SocketPosix::WaitForWrite(IOBuffer* buf, if (!base::CurrentIOThread::Get()->WatchFileDescriptor( socket_fd_, true, base::MessagePumpForIO::WATCH_WRITE, +#if defined(STARBOARD) + &socket_watcher_, this)) { +#else &write_socket_watcher_, this)) { +#endif PLOG(ERROR) << "WatchFileDescriptor failed on write"; return MapSystemError(errno); } @@ -414,8 +443,12 @@ void SocketPosix::OnFileCanReadWithoutBlocking(int fd) { "SocketPosix::OnFileCanReadWithoutBlocking"); if (!accept_callback_.is_null()) { AcceptCompleted(); +#if defined(STARBOARD) + } else if (!read_if_ready_callback_.is_null()) { +#else } else { DCHECK(!read_if_ready_callback_.is_null()); +#endif ReadCompleted(); } } @@ -452,7 +485,11 @@ void SocketPosix::AcceptCompleted() { if (rv == ERR_IO_PENDING) return; +#if defined(STARBOARD) + bool ok = ClearWatcherIfOperationsNotPending(); +#else bool ok = accept_socket_watcher_.StopWatchingFileDescriptor(); +#endif DCHECK(ok); accept_socket_ = nullptr; std::move(accept_callback_).Run(rv); @@ -479,14 +516,22 @@ void SocketPosix::ConnectCompleted() { if (rv == ERR_IO_PENDING) return; +#if defined(STARBOARD) + bool ok = socket_watcher_.StopWatchingFileDescriptor(); +#else bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); +#endif DCHECK(ok); waiting_connect_ = false; std::move(write_callback_).Run(rv); } int SocketPosix::DoRead(IOBuffer* buf, int buf_len) { - int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len)); +#if defined(STARBOARD) + int rv = HANDLE_EINTR(recv(socket_fd_, buf->data(), buf_len, 0)); +#else + int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len, 0)); +#endif return rv >= 0 ? rv : MapSystemError(errno); } @@ -510,18 +555,28 @@ void SocketPosix::RetryRead(int rv) { void SocketPosix::ReadCompleted() { DCHECK(read_if_ready_callback_); +#if defined(STARBOARD) + bool ok = socket_watcher_.StopWatchingFileDescriptor(); +#else bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); +#endif DCHECK(ok); std::move(read_if_ready_callback_).Run(OK); } int SocketPosix::DoWrite(IOBuffer* buf, int buf_len) { -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||\ + defined(STARBOARD) // Disable SIGPIPE for this write. Although Chromium globally disables // SIGPIPE, the net stack may be used in other consumers which do not do // this. MSG_NOSIGNAL is a Linux-only API. On OS X, this is a setsockopt on // socket creation. - int rv = HANDLE_EINTR(send(socket_fd_, buf->data(), buf_len, MSG_NOSIGNAL)); +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif // defined(MSG_NOSIGNAL) + int rv = HANDLE_EINTR(send(socket_fd_, buf->data(), buf_len, kSendFlags)); #else int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len)); #endif @@ -533,20 +588,39 @@ void SocketPosix::WriteCompleted() { if (rv == ERR_IO_PENDING) return; +#if defined(STARBOARD) + bool ok = ClearWatcherIfOperationsNotPending(); +#else bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); +#endif DCHECK(ok); write_buf_.reset(); write_buf_len_ = 0; std::move(write_callback_).Run(rv); } +#if defined(STARBOARD) +bool SocketPosix::ClearWatcherIfOperationsNotPending() { + bool ok = true; + if (!read_pending() && !write_pending() && !accept_pending()) { + ok = socket_watcher_.StopWatchingFileDescriptor(); + } + return ok; +} +#endif + void SocketPosix::StopWatchingAndCleanUp(bool close_socket) { +#if defined(STARBOARD) + bool ok = socket_watcher_.StopWatchingFileDescriptor(); + DCHECK(ok); +#else bool ok = accept_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); ok = read_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); ok = write_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); +#endif // These needs to be done after the StopWatchingFileDescriptor() calls, but // before deleting the write buffer. @@ -581,4 +655,6 @@ void SocketPosix::StopWatchingAndCleanUp(bool close_socket) { peer_address_.reset(); } +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net diff --git a/net/socket/socket_posix.h b/net/socket/socket_posix.h index f7155cab06ec..820043427522 100644 --- a/net/socket/socket_posix.h +++ b/net/socket/socket_posix.h @@ -19,13 +19,19 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + class IOBuffer; struct SockaddrStorage; // Socket class to provide asynchronous read/write operations on top of the // posix socket api. It supports AF_INET, AF_INET6, and AF_UNIX addresses. class NET_EXPORT_PRIVATE SocketPosix +#if defined(STARBOARD) + : public base::MessagePumpForIO::Watcher { +#else : public base::MessagePumpForIO::FdWatcher { +#endif public: SocketPosix(); @@ -124,16 +130,31 @@ class NET_EXPORT_PRIVATE SocketPosix int DoWrite(IOBuffer* buf, int buf_len); void WriteCompleted(); +#if defined(STARBOARD) + bool read_pending() const { return !read_if_ready_callback_.is_null(); } + bool write_pending() const { + return !write_callback_.is_null() && !waiting_connect_; + } + bool accept_pending() const { return !accept_callback_.is_null(); } + + bool ClearWatcherIfOperationsNotPending(); +#endif + // |close_socket| indicates whether the socket should also be closed. void StopWatchingAndCleanUp(bool close_socket); SocketDescriptor socket_fd_; +#if !defined(STARBOARD) base::MessagePumpForIO::FdWatchController accept_socket_watcher_; +#endif + raw_ptr> accept_socket_; CompletionOnceCallback accept_callback_; +#if !defined(STARBOARD) base::MessagePumpForIO::FdWatchController read_socket_watcher_; +#endif // Non-null when a Read() is in progress. scoped_refptr read_buf_; @@ -143,7 +164,11 @@ class NET_EXPORT_PRIVATE SocketPosix // Non-null when a ReadIfReady() is in progress. CompletionOnceCallback read_if_ready_callback_; +#if defined(STARBOARD) + base::MessagePumpForIO::SocketWatcher socket_watcher_; +#else base::MessagePumpForIO::FdWatchController write_socket_watcher_; +#endif scoped_refptr write_buf_; int write_buf_len_ = 0; // External callback; called when write or connect is complete. @@ -158,6 +183,8 @@ class NET_EXPORT_PRIVATE SocketPosix base::ThreadChecker thread_checker_; }; +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net #endif // NET_SOCKET_SOCKET_POSIX_H_ diff --git a/net/socket/tcp_socket.h b/net/socket/tcp_socket.h index 19cfc74ea910..1e0fa1ed662d 100644 --- a/net/socket/tcp_socket.h +++ b/net/socket/tcp_socket.h @@ -9,11 +9,12 @@ #include "net/base/net_export.h" #include "net/socket/socket_descriptor.h" -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) #include "net/socket/tcp_socket_starboard.h" #elif BUILDFLAG(IS_WIN) #include "net/socket/tcp_socket_win.h" -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) #include "net/socket/tcp_socket_posix.h" #endif @@ -25,11 +26,12 @@ namespace net { // class, unless a clear separation of client and server socket functionality is // not suitable for your use case (e.g., a socket needs to be created and bound // before you know whether it is a client or server socket). -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) typedef TCPSocketStarboard TCPSocket; #elif BUILDFLAG(IS_WIN) typedef TCPSocketWin TCPSocket; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) typedef TCPSocketPosix TCPSocket; #endif diff --git a/net/socket/tcp_socket_posix.cc b/net/socket/tcp_socket_posix.cc index 73d002d44281..f25e02cf09df 100644 --- a/net/socket/tcp_socket_posix.cc +++ b/net/socket/tcp_socket_posix.cc @@ -62,6 +62,8 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + namespace { // SetTCPKeepAlive sets SO_KEEPALIVE. @@ -251,9 +253,17 @@ int TCPSocketPosix::Accept(std::unique_ptr* tcp_socket, CompletionOnceCallback callback) { DCHECK(tcp_socket); DCHECK(!callback.is_null()); +#if !defined(STARBOARD) DCHECK(socket_); +#endif DCHECK(!accept_socket_); +#if defined(STARBOARD) + if ((!socket_)) { + return MapSystemError(errno); + } +#endif + net_log_.BeginEvent(NetLogEventType::TCP_ACCEPT); int rv = socket_->Accept( @@ -711,4 +721,6 @@ bool TCPSocketPosix::GetEstimatedRoundTripTime(base::TimeDelta* out_rtt) const { #endif // defined(TCP_INFO) } +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net diff --git a/net/socket/tcp_socket_posix.h b/net/socket/tcp_socket_posix.h index b1798a0494d2..eff66236e27a 100644 --- a/net/socket/tcp_socket_posix.h +++ b/net/socket/tcp_socket_posix.h @@ -26,6 +26,8 @@ class TimeDelta; namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + class AddressList; class IOBuffer; class IPEndPoint; @@ -227,6 +229,8 @@ class NET_EXPORT TCPSocketPosix { SocketTag tag_; }; +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net #endif // NET_SOCKET_TCP_SOCKET_POSIX_H_ diff --git a/net/socket/tcp_socket_starboard.cc b/net/socket/tcp_socket_starboard.cc index 0fdd752ae130..e4ca77ecfb39 100644 --- a/net/socket/tcp_socket_starboard.cc +++ b/net/socket/tcp_socket_starboard.cc @@ -28,6 +28,8 @@ namespace net { +#if SB_API_VERSION <= 15 || defined(COMPILER_MSVC) + TCPSocketStarboard::TCPSocketStarboard( std::unique_ptr socket_performance_watcher, NetLog* net_log, @@ -685,4 +687,6 @@ int TCPSocketStarboard::SetIPv6Only(bool ipv6_only) { return 0; } +#endif // SB_API_VERSION <= 15 || defined(WIN32) + } // namespace net diff --git a/net/socket/tcp_socket_starboard.h b/net/socket/tcp_socket_starboard.h index 876dac02d8a5..5acc64efdb56 100644 --- a/net/socket/tcp_socket_starboard.h +++ b/net/socket/tcp_socket_starboard.h @@ -33,6 +33,8 @@ namespace net { +#if SB_API_VERSION <= 15 || defined(COMPILER_MSVC) + class NET_EXPORT TCPSocketStarboard : public base::MessagePumpIOStarboard::Watcher { public: TCPSocketStarboard( @@ -213,6 +215,8 @@ class NET_EXPORT TCPSocketStarboard : public base::MessagePumpIOStarboard::Watch // DISALLOW_COPY_AND_ASSIGN(TCPSocketStarboard); }; +#endif // SB_API_VERSION <= 15 || defined(WIN32) + } // namespace net #endif // NET_SOCKET_TCP_SOCKET_STARBOARD_H_ diff --git a/net/socket/udp_socket.h b/net/socket/udp_socket.h index e7b897f09ec2..59d87601436b 100644 --- a/net/socket/udp_socket.h +++ b/net/socket/udp_socket.h @@ -7,11 +7,12 @@ #include "build/build_config.h" -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) #include "net/socket/udp_socket_starboard.h" #elif BUILDFLAG(IS_WIN) #include "net/socket/udp_socket_win.h" -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) #include "net/socket/udp_socket_posix.h" #endif @@ -37,11 +38,12 @@ namespace net { // RecvFrom/SendTo // Each read can come from a different client // // Writes need to be directed to a specific // // address. -#if defined(STARBOARD) +#if defined(STARBOARD) && (SB_API_VERSION <= 15 || defined(_MSC_VER)) typedef UDPSocketStarboard UDPSocket; #elif BUILDFLAG(IS_WIN) typedef UDPSocketWin UDPSocket; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || \ + (SB_API_VERSION >= 16 && !defined(_MSC_VER)) typedef UDPSocketPosix UDPSocket; #endif diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc index d7fe60ca6b77..4ceaf668bc84 100644 --- a/net/socket/udp_socket_posix.cc +++ b/net/socket/udp_socket_posix.cc @@ -14,10 +14,8 @@ #include #include -#include #include #include -#include #include #include @@ -66,6 +64,8 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + namespace { const int kBindRetries = 10; @@ -854,7 +854,15 @@ int UDPSocketPosix::SetMulticastOptions() { if (rv < 0) return MapSystemError(errno); } +#if defined(STARBOARD) +#if defined(IP_DEFAULT_MULTICAST_TTL) + if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { +#elif defined(IP_MULTICAST_TTL) + if (multicast_time_to_live_ != IP_MULTICAST_TTL) { +#endif +#else if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { +#endif int rv; if (addr_family_ == AF_INET) { u_char ttl = multicast_time_to_live_; @@ -1096,4 +1104,6 @@ int UDPSocketPosix::SetIOSNetworkServiceType(int ios_network_service_type) { return OK; } +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net diff --git a/net/socket/udp_socket_posix.h b/net/socket/udp_socket_posix.h index ed9c7549c1fc..a36895326872 100644 --- a/net/socket/udp_socket_posix.h +++ b/net/socket/udp_socket_posix.h @@ -33,6 +33,8 @@ namespace net { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + class IPAddress; class NetLog; struct NetLogSource; @@ -285,7 +287,11 @@ class NET_EXPORT UDPSocketPosix { SOCKET_OPTION_MULTICAST_LOOP = 1 << 0 }; +#if defined(STARBOARD) + class ReadWatcher : public base::MessagePumpForIO::Watcher { +#else class ReadWatcher : public base::MessagePumpForIO::FdWatcher { +#endif public: explicit ReadWatcher(UDPSocketPosix* socket) : socket_(socket) {} @@ -302,7 +308,11 @@ class NET_EXPORT UDPSocketPosix { const raw_ptr socket_; }; +#if defined(STARBOARD) + class WriteWatcher : public base::MessagePumpForIO::Watcher { +#else class WriteWatcher : public base::MessagePumpForIO::FdWatcher { +#endif public: explicit WriteWatcher(UDPSocketPosix* socket) : socket_(socket) {} @@ -410,8 +420,13 @@ class NET_EXPORT UDPSocketPosix { mutable std::unique_ptr remote_address_; // The socket's posix wrappers +#if defined(STARBOARD) + base::MessagePumpForIO::SocketWatcher read_socket_watcher_; + base::MessagePumpForIO::SocketWatcher write_socket_watcher_; +#else base::MessagePumpForIO::FdWatchController read_socket_watcher_; base::MessagePumpForIO::FdWatchController write_socket_watcher_; +#endif // The corresponding watchers for reads and writes. ReadWatcher read_watcher_; @@ -465,6 +480,8 @@ class NET_EXPORT UDPSocketPosix { THREAD_CHECKER(thread_checker_); }; +#endif // SB_API_VERSION >= 16 && !defined(WIN32) + } // namespace net #endif // NET_SOCKET_UDP_SOCKET_POSIX_H_ diff --git a/net/socket/udp_socket_starboard.cc b/net/socket/udp_socket_starboard.cc index c13eb2c8a737..dd29e938b2f3 100644 --- a/net/socket/udp_socket_starboard.cc +++ b/net/socket/udp_socket_starboard.cc @@ -35,6 +35,8 @@ namespace net { +#if SB_API_VERSION <= 15 || defined(COMPILER_MSVC) + UDPSocketStarboard::UDPSocketStarboard(DatagramSocket::BindType bind_type, net::NetLog* net_log, const net::NetLogSource& source) @@ -917,4 +919,6 @@ int UDPSocketStarboard::ResetWrittenBytes() { return bytes; } +#endif // SB_API_VERSION <= 15 || defined(WIN32) + } // namespace net diff --git a/net/socket/udp_socket_starboard.h b/net/socket/udp_socket_starboard.h index 905964eccc67..0b3707fe0c01 100644 --- a/net/socket/udp_socket_starboard.h +++ b/net/socket/udp_socket_starboard.h @@ -42,6 +42,8 @@ namespace net { +#if SB_API_VERSION <= 15 || defined(COMPILER_MSVC) + // Sendresult is inspired by sendmmsg, but unlike sendmmsg it is not // convenient to require that a positive |write_count| and a negative // error code are mutually exclusive. @@ -491,6 +493,8 @@ class NET_EXPORT UDPSocketStarboard // DISALLOW_COPY_AND_ASSIGN(UDPSocketStarboard); }; +#endif // SB_API_VERSION <= 15 || defined(WIN32) + } // namespace net #endif // NET_SOCKET_UDP_SOCKET_STARBOARD_H_ diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index 05bcf69e84d5..1259ba049276 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -336,6 +336,10 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(SbSocketWaiterWait); REGISTER_SYMBOL(SbSocketWaiterWaitTimed); REGISTER_SYMBOL(SbSocketWaiterWakeUp); +#if SB_API_VERSION >= 16 + REGISTER_SYMBOL(SbPosixSocketWaiterAdd); + REGISTER_SYMBOL(SbPosixSocketWaiterRemove); +#endif // SB_API_VERSION >= 16 REGISTER_SYMBOL(SbSpeechSynthesisCancel); REGISTER_SYMBOL(SbSpeechSynthesisIsSupported); REGISTER_SYMBOL(SbSpeechSynthesisSpeak); @@ -469,7 +473,11 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(freeifaddrs); REGISTER_SYMBOL(fsync); REGISTER_SYMBOL(ftruncate); + REGISTER_SYMBOL(getaddrinfo); + REGISTER_SYMBOL(getifaddrs); + REGISTER_SYMBOL(getpeername); REGISTER_SYMBOL(getsockname); + REGISTER_SYMBOL(getsockopt); REGISTER_SYMBOL(listen); REGISTER_SYMBOL(malloc); REGISTER_SYMBOL(mkdir); @@ -483,6 +491,7 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(recv); REGISTER_SYMBOL(send); REGISTER_SYMBOL(recvfrom); + REGISTER_SYMBOL(recvmsg); REGISTER_SYMBOL(rmdir); REGISTER_SYMBOL(sched_yield); REGISTER_SYMBOL(sendto); diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn index 33997e67e144..6d6f6001979d 100644 --- a/starboard/nplb/BUILD.gn +++ b/starboard/nplb/BUILD.gn @@ -189,6 +189,10 @@ target(gtest_target_type, "nplb") { "posix_compliance/posix_socket_send_test.cc", "posix_compliance/posix_socket_sendto_test.cc", "posix_compliance/posix_socket_set_options_test.cc", + "posix_compliance/posix_socket_waiter_add_test.cc", + "posix_compliance/posix_socket_waiter_remove_test.cc", + "posix_compliance/posix_socket_waiter_wait_test.cc", + "posix_compliance/posix_socket_waiter_wait_timed_test.cc", "posix_compliance/posix_string_compare_no_case_n_test.cc", "posix_compliance/posix_string_compare_no_case_test.cc", "posix_compliance/posix_string_format_test.cc", diff --git a/starboard/nplb/posix_compliance/posix_socket_helpers.cc b/starboard/nplb/posix_compliance/posix_socket_helpers.cc index ef1a59dd56d7..15770f5d61aa 100644 --- a/starboard/nplb/posix_compliance/posix_socket_helpers.cc +++ b/starboard/nplb/posix_compliance/posix_socket_helpers.cc @@ -191,5 +191,60 @@ int PosixGetLocalAddressIPv6(sockaddr* address_ptr) { } #endif +bool PosixWriteBySpinning(int socket, + const char* data, + int data_size, + int64_t timeout) { + int64_t start = CurrentMonotonicTime(); + int total = 0; + while (total < data_size) { + int sent = send(socket, data + total, data_size - total, kSendFlags); + if (sent >= 0) { + total += sent; + continue; + } + + if (errno != EINPROGRESS || errno != EAGAIN || errno != EWOULDBLOCK) { + return false; + } + + if (CurrentMonotonicTime() - start >= timeout) { + return false; + } + + sched_yield(); + } + + return true; +} + +bool PosixReadBySpinning(int socket, + char* out_data, + int data_size, + int64_t timeout) { + int64_t start = CurrentMonotonicTime(); + int total = 0; + while (total < data_size) { + int received = + recvfrom(socket, out_data + total, data_size - total, 0, NULL, 0); + if (received >= 0) { + total += received; + continue; + } + + if (errno != EINPROGRESS || errno != EAGAIN || errno != EWOULDBLOCK) { + return false; + } + + if (CurrentMonotonicTime() - start >= timeout) { + return false; + } + + sched_yield(); + } + + return true; +} + } // namespace nplb } // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_socket_helpers.h b/starboard/nplb/posix_compliance/posix_socket_helpers.h index 56b48b638698..eb2d39097a0a 100644 --- a/starboard/nplb/posix_compliance/posix_socket_helpers.h +++ b/starboard/nplb/posix_compliance/posix_socket_helpers.h @@ -63,6 +63,26 @@ const int kSendFlags = MSG_NOSIGNAL; const int kSendFlags = 0; #endif +// Thread entry point to continuously write to a socket that is expected to +// be closed on another thread. +struct trio_socket_fd { + int* listen_socket_fd_ptr; + int* client_socket_fd_ptr; + int* server_socket_fd_ptr; +}; + +// Writes the given data to socket, spinning until success or error. +bool PosixWriteBySpinning(int socket, + const char* data, + int data_size, + int64_t timeout); + +// Reads the given amount of data from socket, spinning until success or error. +bool PosixReadBySpinning(int socket, + char* out_data, + int data_size, + int64_t timeout); + } // namespace nplb } // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_socket_send_test.cc b/starboard/nplb/posix_compliance/posix_socket_send_test.cc index b057d22a3f1f..1869f83b036b 100644 --- a/starboard/nplb/posix_compliance/posix_socket_send_test.cc +++ b/starboard/nplb/posix_compliance/posix_socket_send_test.cc @@ -26,14 +26,6 @@ namespace starboard { namespace nplb { namespace { -// Thread entry point to continuously write to a socket that is expected to -// be closed on another thread. -struct trio_socket_fd { - int* listen_socket_fd_ptr; - int* client_socket_fd_ptr; - int* server_socket_fd_ptr; -}; - void* PosixSocketSendToServerSocketEntryPoint(void* trio_as_void_ptr) { // The contents of this buffer are inconsequential. struct trio_socket_fd* trio_ptr = diff --git a/starboard/nplb/posix_compliance/posix_socket_sendto_test.cc b/starboard/nplb/posix_compliance/posix_socket_sendto_test.cc index 762352383166..08d3ce279b45 100644 --- a/starboard/nplb/posix_compliance/posix_socket_sendto_test.cc +++ b/starboard/nplb/posix_compliance/posix_socket_sendto_test.cc @@ -27,14 +27,6 @@ namespace starboard { namespace nplb { namespace { -// Thread entry point to continuously write to a socket that is expected to -// be closed on another thread. -struct trio_socket_fd { - int* listen_socket_fd_ptr; - int* client_socket_fd_ptr; - int* server_socket_fd_ptr; -}; - void* PosixSocketSendToServerSocketEntryPoint(void* trio_as_void_ptr) { // The contents of this buffer are inconsequential. struct trio_socket_fd* trio_ptr = diff --git a/starboard/nplb/posix_compliance/posix_socket_waiter_add_test.cc b/starboard/nplb/posix_compliance/posix_socket_waiter_add_test.cc new file mode 100644 index 000000000000..c7f7f92a3b68 --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_socket_waiter_add_test.cc @@ -0,0 +1,182 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "starboard/common/socket.h" +#include "starboard/configuration_constants.h" +#include "starboard/nplb/socket_helpers.h" +#include "starboard/socket_waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +class SbPosixSocketWaiterAddTest : public ::testing::TestWithParam { + public: + int GetAddressType() { return GetParam(); } +}; + +// Type of SbPosixSocketWaiterCallback +void NoOpSocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) {} + +TEST(SbPosixSocketWaiterAddTest, SunnyDay) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterAddTest, SunnyDayPersistent) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, true)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterAddTest, SunnyDayMany) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + const int kMany = kSbFileMaxOpen; + std::vector sockets(kMany, 0); + + for (int i = 0; i < kMany; ++i) { + sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(sockets[i] >= 0); + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, sockets[i], NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + } + + for (int i = 0; i < kMany; ++i) { + EXPECT_TRUE(close(sockets[i]) == 0); + } + + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterAddTest, RainyDayAddToSameWaiter) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + // First add should succeed. + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + // Second add should fail. + EXPECT_FALSE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + // Remove should succeed. + EXPECT_TRUE(SbPosixSocketWaiterRemove(waiter, socket)); + + // Add after remove should succeed. + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + // Second add after remove should fail. + EXPECT_FALSE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterAddTest, RainyDayInvalidSocket) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + EXPECT_FALSE(SbPosixSocketWaiterAdd( + waiter, -1, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterAddTest, RainyDayInvalidWaiter) { + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_FALSE(SbPosixSocketWaiterAdd( + kSbSocketWaiterInvalid, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + EXPECT_TRUE(close(socket) == 0); +} + +TEST(SbPosixSocketWaiterAddTest, RainyDayNoCallback) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_FALSE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, NULL, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterAddTest, RainyDayNoInterest) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_FALSE(SbPosixSocketWaiterAdd(waiter, socket, NULL, + &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestNone, false)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + +} // namespace +} // namespace nplb +} // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_socket_waiter_remove_test.cc b/starboard/nplb/posix_compliance/posix_socket_waiter_remove_test.cc new file mode 100644 index 000000000000..2d72536d27ea --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_socket_waiter_remove_test.cc @@ -0,0 +1,85 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "starboard/common/socket.h" +#include "starboard/nplb/socket_helpers.h" +#include "starboard/socket_waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +void NoOpSocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) {} + +TEST(SbPosixSocketWaiterRemoveTest, RainyDayInvalidSocket) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + EXPECT_FALSE(SbPosixSocketWaiterRemove(waiter, -1)); + + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterRemoveTest, RainyDayInvalidWaiter) { + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_FALSE(SbPosixSocketWaiterRemove(kSbSocketWaiterInvalid, socket)); + + EXPECT_TRUE(close(socket) == 0); +} + +TEST(SbPosixSocketWaiterRemoveTest, RainyDayNotAdded) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + + EXPECT_FALSE(SbPosixSocketWaiterRemove(waiter, socket)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbPosixSocketWaiterRemoveTest, RainyDayAlreadyRemoved) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ASSERT_TRUE(socket >= 0); + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + EXPECT_TRUE(SbPosixSocketWaiterRemove(waiter, socket)); + EXPECT_FALSE(SbPosixSocketWaiterRemove(waiter, socket)); + + EXPECT_TRUE(close(socket) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + +} // namespace +} // namespace nplb +} // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_socket_waiter_wait_test.cc b/starboard/nplb/posix_compliance/posix_socket_waiter_wait_test.cc new file mode 100644 index 000000000000..f3e9aab891c6 --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_socket_waiter_wait_test.cc @@ -0,0 +1,266 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "starboard/common/log.h" +#include "starboard/common/semaphore.h" +#include "starboard/common/socket.h" +#include "starboard/nplb/posix_compliance/posix_socket_helpers.h" +#include "starboard/nplb/posix_compliance/posix_thread_helpers.h" +#include "starboard/nplb/socket_helpers.h" +#include "starboard/socket_waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SbPosixSocketWaiterWaitTest); + +struct CallbackValues { + int count; + SbSocketWaiter waiter; + int socket; + void* context; + int ready_interests; +}; + +void TestSocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) { + CallbackValues* values = reinterpret_cast(context); + if (values) { + ++values->count; + values->waiter = waiter; + values->socket = socket; + values->context = context; + values->ready_interests = ready_interests; + } + SbSocketWaiterWakeUp(waiter); +} + +void FailSocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) { + ADD_FAILURE() << __FUNCTION__ << " was called."; +} + +TEST(SbPosixSocketWaiterWaitTest, SunnyDay) { + const int kBufSize = 1024; + + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1; + int result = PosixSocketCreateAndConnect( + AF_INET, AF_INET, htons(GetPortNumberForTests()), kSocketTimeout, + &listen_socket_fd, &client_socket_fd, &server_socket_fd); + ASSERT_TRUE(result == 0); + ASSERT_TRUE(server_socket_fd >= 0); + + struct trio_socket_fd trio = {&listen_socket_fd, &client_socket_fd, + &server_socket_fd}; + + // The client socket should be ready to write right away, but not read until + // it gets some data. + CallbackValues values = {0}; + + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, *trio.client_socket_fd_ptr, &values, &TestSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + // This add should do nothing, since it is already registered. Testing here + // because we can see if it fires a write to the proper callback, then it + // properly ignored this second set of parameters. + EXPECT_FALSE(SbPosixSocketWaiterAdd(waiter, *trio.client_socket_fd_ptr, + &values, &FailSocketWaiterCallback, + kSbSocketWaiterInterestRead, false)); + + WaitShouldNotBlock(waiter); + + EXPECT_EQ(1, values.count); // Check that the callback was called once. + EXPECT_EQ(waiter, values.waiter); + EXPECT_EQ(*trio.client_socket_fd_ptr, values.socket); + EXPECT_EQ(&values, values.context); + EXPECT_EQ(kSbSocketWaiterInterestWrite, values.ready_interests); + + // Close and reopen sockets, this bug is tracked at b/348992515 + EXPECT_TRUE(close(*trio.server_socket_fd_ptr) == 0); + EXPECT_TRUE(close(*trio.client_socket_fd_ptr) == 0); + EXPECT_TRUE(close(*trio.listen_socket_fd_ptr) == 0); + result = PosixSocketCreateAndConnect( + AF_INET, AF_INET, htons(GetPortNumberForTests()), kSocketTimeout, + &listen_socket_fd, &client_socket_fd, &server_socket_fd); + ASSERT_TRUE(result == 0); + ASSERT_TRUE(server_socket_fd >= 0); + + // Try again to make sure writable sockets are still writable + values.count = 0; + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, *trio.client_socket_fd_ptr, &values, &TestSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + WaitShouldNotBlock(waiter); + + EXPECT_EQ(1, values.count); // Check that the callback was called once. + EXPECT_EQ(waiter, values.waiter); + EXPECT_EQ(*trio.client_socket_fd_ptr, values.socket); + EXPECT_EQ(&values, values.context); + EXPECT_EQ(kSbSocketWaiterInterestWrite, values.ready_interests); + + // The client socket should become ready to read after we write some data to + // it. + values.count = 0; + EXPECT_TRUE(SbPosixSocketWaiterAdd(waiter, *trio.client_socket_fd_ptr, + &values, &TestSocketWaiterCallback, + kSbSocketWaiterInterestRead, false)); + + // Now we can send something to trigger readability. + char* send_buf = new char[kBufSize]; + int bytes_sent = + send(*trio.server_socket_fd_ptr, send_buf, kBufSize, kSendFlags); + delete[] send_buf; + EXPECT_LT(0, bytes_sent); + + WaitShouldNotBlock(waiter); + + EXPECT_EQ(1, values.count); + EXPECT_EQ(waiter, values.waiter); + EXPECT_EQ(*trio.client_socket_fd_ptr, values.socket); + EXPECT_EQ(&values, values.context); + EXPECT_EQ(kSbSocketWaiterInterestRead, values.ready_interests); + + EXPECT_TRUE(close(*trio.server_socket_fd_ptr) == 0); + EXPECT_TRUE(close(*trio.client_socket_fd_ptr) == 0); + EXPECT_TRUE(close(*trio.listen_socket_fd_ptr) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +struct AlreadyReadyContext { + AlreadyReadyContext() + : waiter(kSbSocketWaiterInvalid), + a_write_result(false), + a_read_result(false), + b_result(false) {} + ~AlreadyReadyContext() { EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); } + + SbSocketWaiter waiter; + struct trio_socket_fd trio; + Semaphore wrote_a_signal; + bool a_write_result; + bool a_read_result; + Semaphore write_b_signal; + bool b_result; + Semaphore wrote_b_signal; +}; + +const char kAData[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; +const char kBData[] = "bb"; + +void* AlreadyReadyEntryPoint(void* param) { + AlreadyReadyContext* context = reinterpret_cast(param); + + context->a_write_result = + PosixWriteBySpinning(*context->trio.server_socket_fd_ptr, kAData, + SB_ARRAY_SIZE_INT(kAData), kSocketTimeout); + context->wrote_a_signal.Put(); + + context->write_b_signal.Take(); + context->b_result = + PosixWriteBySpinning(*context->trio.server_socket_fd_ptr, kBData, + SB_ARRAY_SIZE_INT(kBData), kSocketTimeout); + context->wrote_b_signal.Put(); + return NULL; +} + +void WakeUpSocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* param, + int ready_interests) { + SbSocketWaiterWakeUp(waiter); +} + +void AlreadyReadySocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* param, + int ready_interests) { + AlreadyReadyContext* context = reinterpret_cast(param); + // Read in the A data. + char buffer[SB_ARRAY_SIZE_INT(kAData)]; + context->a_read_result = + PosixReadBySpinning(*context->trio.client_socket_fd_ptr, buffer, + SB_ARRAY_SIZE_INT(buffer), kSocketTimeout); + + // Tell the thread to write the B data now. + context->write_b_signal.Put(); + + // Wait until it thinks it has finished. + context->wrote_b_signal.Take(); + + // Now add the second read callback, and hope that it gets called. + EXPECT_TRUE(SbPosixSocketWaiterAdd(waiter, socket, context, + &WakeUpSocketWaiterCallback, + kSbSocketWaiterInterestRead, false)); +} + +// This test ensures that if the socket gets written to while it is not being +// waited on, and inside a callback, it will become ready immediately the next +// time it is waited on. +TEST(SbPosixSocketWaiterWaitTest, SunnyDayAlreadyReady) { + AlreadyReadyContext context; + context.waiter = SbSocketWaiterCreate(); + ASSERT_TRUE(SbSocketWaiterIsValid(context.waiter)); + + int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1; + int result = PosixSocketCreateAndConnect( + AF_INET, AF_INET, htons(GetPortNumberForTests()), kSocketTimeout, + &listen_socket_fd, &client_socket_fd, &server_socket_fd); + ASSERT_TRUE(result == 0); + ASSERT_TRUE(server_socket_fd >= 0); + + context.trio.listen_socket_fd_ptr = &listen_socket_fd; + context.trio.client_socket_fd_ptr = &client_socket_fd; + context.trio.server_socket_fd_ptr = &server_socket_fd; + + EXPECT_TRUE(SbPosixSocketWaiterAdd( + context.waiter, *context.trio.client_socket_fd_ptr, &context, + &AlreadyReadySocketWaiterCallback, kSbSocketWaiterInterestRead, false)); + + pthread_t thread = 0; + pthread_create(&thread, nullptr, AlreadyReadyEntryPoint, &context); + EXPECT_TRUE(thread != 0); + context.wrote_a_signal.Take(); + + WaitShouldNotBlock(context.waiter); + + EXPECT_EQ(pthread_join(thread, NULL), 0); + EXPECT_TRUE(close(listen_socket_fd) == 0); + EXPECT_TRUE(close(client_socket_fd) == 0); + EXPECT_TRUE(close(server_socket_fd) == 0); +} + +TEST(SbPosixSocketWaiterWaitTest, RainyDayInvalidWaiter) { + WaitShouldNotBlock(kSbSocketWaiterInvalid); +} + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + +} // namespace +} // namespace nplb +} // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_socket_waiter_wait_timed_test.cc b/starboard/nplb/posix_compliance/posix_socket_waiter_wait_timed_test.cc new file mode 100644 index 000000000000..2fa1f76b4084 --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_socket_waiter_wait_timed_test.cc @@ -0,0 +1,128 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "starboard/common/log.h" +#include "starboard/common/socket.h" +#include "starboard/nplb/posix_compliance/posix_socket_helpers.h" +#include "starboard/nplb/socket_helpers.h" +#include "starboard/socket_waiter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SbPosixSocketWaiterWaitTimedTest); + +struct CallbackValues { + int count; + SbSocketWaiter waiter; + int socket; + void* context; + int ready_interests; +}; + +void TestSocketWaiterCallback(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) { + CallbackValues* values = reinterpret_cast(context); + if (values) { + ++values->count; + values->waiter = waiter; + values->socket = socket; + values->context = context; + values->ready_interests = ready_interests; + } + SbSocketWaiterWakeUp(waiter); +} + +TEST(SbPosixSocketWaiterWaitTimedTest, SunnyDay) { + const int kBufSize = 1024; + + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + + int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1; + int result = PosixSocketCreateAndConnect( + AF_INET, AF_INET, htons(GetPortNumberForTests()), kSocketTimeout, + &listen_socket_fd, &client_socket_fd, &server_socket_fd); + ASSERT_TRUE(result == 0); + ASSERT_TRUE(server_socket_fd >= 0); + + struct trio_socket_fd trio = {&listen_socket_fd, &client_socket_fd, + &server_socket_fd}; + + // The client socket should be ready to write right away, but not read until + // it gets some data. + CallbackValues values = {0}; + EXPECT_TRUE(SbPosixSocketWaiterAdd( + waiter, *trio.client_socket_fd_ptr, &values, &TestSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + + TimedWaitShouldNotBlock(waiter, kSocketTimeout); + + // Even though we waited for no time, we should have gotten this callback. + EXPECT_EQ(1, values.count); // Check that the callback was called once. + EXPECT_EQ(waiter, values.waiter); + EXPECT_EQ(*trio.client_socket_fd_ptr, values.socket); + EXPECT_EQ(&values, values.context); + EXPECT_EQ(kSbSocketWaiterInterestWrite, values.ready_interests); + + // While we haven't written anything, we should block indefinitely, and + // receive no read callbacks. + values.count = 0; + EXPECT_TRUE(SbPosixSocketWaiterAdd(waiter, *trio.client_socket_fd_ptr, + &values, &TestSocketWaiterCallback, + kSbSocketWaiterInterestRead, false)); + + TimedWaitShouldBlock(waiter, kSocketTimeout); + + EXPECT_EQ(0, values.count); + + // The client socket should become ready to read after we write some data to + // it. + char* send_buf = new char[kBufSize]; + int bytes_sent = + send(*trio.server_socket_fd_ptr, send_buf, kBufSize, kSendFlags); + delete[] send_buf; + EXPECT_LT(0, bytes_sent); + + TimedWaitShouldNotBlock(waiter, kSocketTimeout); + + EXPECT_EQ(1, values.count); + EXPECT_EQ(waiter, values.waiter); + EXPECT_EQ(*trio.client_socket_fd_ptr, values.socket); + EXPECT_EQ(&values, values.context); + EXPECT_EQ(kSbSocketWaiterInterestRead, values.ready_interests); + + EXPECT_TRUE(close(listen_socket_fd) == 0); + EXPECT_TRUE(close(client_socket_fd) == 0); + EXPECT_TRUE(close(server_socket_fd) == 0); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + +TEST(SbSocketWaiterWaitTimedTest, RainyDayInvalidWaiter) { + TimedWaitShouldNotBlock(kSbSocketWaiterInvalid, kSocketTimeout); +} + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + +} // namespace +} // namespace nplb +} // namespace starboard diff --git a/starboard/nplb/socket_waiter_remove_test.cc b/starboard/nplb/socket_waiter_remove_test.cc index 12c3627ec057..824329e740b8 100644 --- a/starboard/nplb/socket_waiter_remove_test.cc +++ b/starboard/nplb/socket_waiter_remove_test.cc @@ -41,6 +41,22 @@ TEST_F(SbSocketWaiterRemoveTest, RainyDayInvalidSocket) { EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); } +TEST_F(SbSocketWaiterRemoveTest, SunnyDayAddAndRemove) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + EXPECT_TRUE(SbSocketWaiterIsValid(waiter)); + SbSocket socket = + SbSocketCreate(kSbSocketAddressTypeIpv4, kSbSocketProtocolTcp); + ASSERT_TRUE(SbSocketIsValid(socket)); + + EXPECT_TRUE(SbSocketWaiterAdd( + waiter, socket, NULL, &NoOpSocketWaiterCallback, + kSbSocketWaiterInterestRead | kSbSocketWaiterInterestWrite, false)); + EXPECT_TRUE(SbSocketWaiterRemove(waiter, socket)); + + EXPECT_TRUE(SbSocketDestroy(socket)); + EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); +} + TEST_P(SbSocketWaiterRemoveTest, RainyDayInvalidWaiter) { SbSocket socket = SbSocketCreate(GetAddressType(), kSbSocketProtocolTcp); ASSERT_TRUE(SbSocketIsValid(socket)); diff --git a/starboard/nplb/socket_waiter_wait_timed_test.cc b/starboard/nplb/socket_waiter_wait_timed_test.cc index 1d7926ca4506..32681b0bb588 100644 --- a/starboard/nplb/socket_waiter_wait_timed_test.cc +++ b/starboard/nplb/socket_waiter_wait_timed_test.cc @@ -121,7 +121,7 @@ TEST_P(PairSbSocketWaiterWaitTimedTest, SunnyDay) { EXPECT_TRUE(SbSocketWaiterDestroy(waiter)); } -TEST_F(SbSocketWaiterWaitTimedTest, RainyDayInvalidWaiter) { +TEST(SbSocketWaiterWaitTimedTest, RainyDayInvalidWaiter) { TimedWaitShouldNotBlock(kSbSocketWaiterInvalid, kSocketTimeout); } diff --git a/starboard/shared/libevent/socket_waiter_add.cc b/starboard/shared/libevent/socket_waiter_add.cc index bb22ef70fe55..607b96dd4e7d 100644 --- a/starboard/shared/libevent/socket_waiter_add.cc +++ b/starboard/shared/libevent/socket_waiter_add.cc @@ -16,6 +16,7 @@ #include "starboard/common/log.h" #include "starboard/shared/libevent/socket_waiter_internal.h" +#include "starboard/socket.h" bool SbSocketWaiterAdd(SbSocketWaiter waiter, SbSocket socket, @@ -45,3 +46,35 @@ bool SbSocketWaiterAdd(SbSocketWaiter waiter, return waiter->Add(socket, context, callback, interests, persistent); } + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +bool SbPosixSocketWaiterAdd(SbSocketWaiter waiter, + int socket, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) { + if (!SbSocketWaiterIsValid(waiter)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Waiter (" << waiter << ") is invalid."; + return false; + } + + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (!callback) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No callback provided."; + return false; + } + + if (!interests) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No interests provided."; + return false; + } + + return waiter->Add(socket, waiter, context, callback, interests, persistent); +} +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) diff --git a/starboard/shared/libevent/socket_waiter_internal.cc b/starboard/shared/libevent/socket_waiter_internal.cc index 1a815513ccdc..8ccfa2e96c2c 100644 --- a/starboard/shared/libevent/socket_waiter_internal.cc +++ b/starboard/shared/libevent/socket_waiter_internal.cc @@ -153,11 +153,20 @@ SbSocketWaiterPrivate::SbSocketWaiterPrivate() } SbSocketWaiterPrivate::~SbSocketWaiterPrivate() { - WaiteesMap::iterator it = waitees_.begin(); - while (it != waitees_.end()) { +#if SB_API_VERSION >= 16 + i_WaiteesMap::iterator it = i_waitees_.begin(); + while (it != i_waitees_.end()) { Waitee* waitee = it->second; ++it; // Increment before removal. - Remove(waitee->socket); + Remove(waitee->i_socket, waitee->waiter); + } +#endif // SB_API_VERSION >= 16 + + sb_WaiteesMap::iterator it2 = sb_waitees_.begin(); + while (it2 != sb_waitees_.end()) { + Waitee* waitee = it2->second; + ++it2; // Increment before removal. + Remove(waitee->sb_socket, waitee->waiter); } event_del(&wakeup_event_); @@ -172,6 +181,105 @@ SbSocketWaiterPrivate::~SbSocketWaiterPrivate() { #endif } +#if SB_API_VERSION >= 16 +bool SbSocketWaiterPrivate::Add(int socket, + SbSocketWaiter waiter, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) { + SB_DCHECK(pthread_equal(pthread_self(), thread_)); + + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (!interests) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No interests provided."; + return false; + } + + // The policy is not to add a socket to a waiter if it is registered with + // another waiter. + + // TODO: Since integer based socket fd doesn't have waiter information, + // need to find a way to keep track whether this socket has been + // registered with a waiter already. + // At this moment, at least we can test if this specific socket + // is already registered to this incoming waiter. + if (waiter->CheckSocketRegistered(socket)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket already has this waiter (" + << this << ")."; + return false; + } + + Waitee* waitee = + new Waitee(this, socket, context, callback, interests, persistent); + AddWaitee(waitee); + + int16_t events = 0; + if (interests & kSbSocketWaiterInterestRead) { + events |= EV_READ; + } + + if (interests & kSbSocketWaiterInterestWrite) { + events |= EV_WRITE; + } + + if (persistent) { + events |= EV_PERSIST; + } + + event_set(&waitee->event, socket, events, + &SbSocketWaiterPrivate::LibeventSocketCallback, waitee); + event_base_set(base_, &waitee->event); + waiter = this; + event_add(&waitee->event, NULL); + return true; +} + +bool SbSocketWaiterPrivate::Remove(int socket, SbSocketWaiter waiter) { + SB_DCHECK(pthread_equal(pthread_self(), thread_)); + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (waiter != this) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") " + << "is watched by Waiter (" << waiter << "), " + << "not this Waiter (" << this << ")."; + SB_DSTACK(ERROR); + return false; + } + + Waitee* waitee = RemoveWaitee(socket); + if (!waitee) { + return false; + } + + event_del(&waitee->event); + waiter = kSbSocketWaiterInvalid; + + delete waitee; + return true; +} + +bool SbSocketWaiterPrivate::CheckSocketRegistered(int socket) { + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (GetWaitee(socket) == NULL) { + return false; + } + + return true; +} +#endif // SB_API_VERSION >= 16 + bool SbSocketWaiterPrivate::Add(SbSocket socket, void* context, SbSocketWaiterCallback callback, @@ -233,7 +341,7 @@ bool SbSocketWaiterPrivate::Add(SbSocket socket, return true; } -bool SbSocketWaiterPrivate::Remove(SbSocket socket) { +bool SbSocketWaiterPrivate::Remove(SbSocket socket, SbSocketWaiter waiter) { SB_DCHECK(pthread_equal(pthread_self(), thread_)); if (!SbSocketIsValid(socket)) { SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; @@ -260,6 +368,18 @@ bool SbSocketWaiterPrivate::Remove(SbSocket socket) { return true; } +bool SbSocketWaiterPrivate::CheckSocketRegistered(SbSocket socket) { + if (!SbSocketIsValid(socket)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + if (GetWaitee(socket) == NULL) { + return false; + } + + return true; +} + void SbSocketWaiterPrivate::Wait() { SB_DCHECK(pthread_equal(pthread_self(), thread_)); @@ -353,14 +473,25 @@ void SbSocketWaiterPrivate::HandleSignal(Waitee* waitee, // Remove the non-persistent waitee before calling the callback, so that we // can add another waitee in the callback if we need to. This is also why we // copy all the fields we need out of waitee. - SbSocket socket = waitee->socket; - void* context = waitee->context; - SbSocketWaiterCallback callback = waitee->callback; - if (!waitee->persistent) { - Remove(waitee->socket); + if (waitee->use_int_socket == 1) { +#if SB_API_VERSION >= 16 + int socket = waitee->i_socket; + void* context = waitee->context; + SbPosixSocketWaiterCallback callback = waitee->i_callback; + if (!waitee->persistent) { + Remove(waitee->i_socket, waitee->waiter); + } + callback(this, socket, context, interests); +#endif // SB_API_VERSION >= 16 + } else { + SbSocket socket = waitee->sb_socket; + void* context = waitee->context; + SbSocketWaiterCallback callback = waitee->sb_callback; + if (!waitee->persistent) { + Remove(waitee->sb_socket, waitee->waiter); + } + callback(this, socket, context, interests); } - - callback(this, socket, context, interests); } void SbSocketWaiterPrivate::HandleWakeUpRead() { @@ -375,28 +506,52 @@ void SbSocketWaiterPrivate::HandleWakeUpRead() { } void SbSocketWaiterPrivate::AddWaitee(Waitee* waitee) { - waitees_.insert(std::make_pair(waitee->socket, waitee)); + if (waitee->use_int_socket == 1) { + i_waitees_.insert(std::make_pair(waitee->i_socket, waitee)); + } else { + sb_waitees_.insert(std::make_pair(waitee->sb_socket, waitee)); + } +} + +SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::GetWaitee(int socket) { + i_WaiteesMap::iterator it = i_waitees_.find(socket); + if (it == i_waitees_.end()) { + return NULL; + } + + return it->second; } SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::GetWaitee( SbSocket socket) { - WaiteesMap::iterator it = waitees_.find(socket); - if (it == waitees_.end()) { + sb_WaiteesMap::iterator it = sb_waitees_.find(socket); + if (it == sb_waitees_.end()) { return NULL; } return it->second; } +SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::RemoveWaitee(int socket) { + i_WaiteesMap::iterator it = i_waitees_.find(socket); + if (it == i_waitees_.end()) { + return NULL; + } + + Waitee* result = it->second; + i_waitees_.erase(it); + return result; +} + SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::RemoveWaitee( SbSocket socket) { - WaiteesMap::iterator it = waitees_.find(socket); - if (it == waitees_.end()) { + sb_WaiteesMap::iterator it = sb_waitees_.find(socket); + if (it == sb_waitees_.end()) { return NULL; } Waitee* result = it->second; - waitees_.erase(it); + sb_waitees_.erase(it); return result; } diff --git a/starboard/shared/libevent/socket_waiter_internal.h b/starboard/shared/libevent/socket_waiter_internal.h index f5c8c49deb95..2c9d486fee01 100644 --- a/starboard/shared/libevent/socket_waiter_internal.h +++ b/starboard/shared/libevent/socket_waiter_internal.h @@ -32,19 +32,52 @@ struct SbSocketWaiterPrivate { // These methods implement the SbSocketWaiter API defined in socket_waiter.h. + // The Add/Remove pair for integer based socket +#if SB_API_VERSION >= 16 + bool Add(int socket, + SbSocketWaiter waiter, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent); + bool Remove(int socket, SbSocketWaiter waiter); + bool CheckSocketRegistered(int socket); +#endif // SB_API_VERSION >= 16 + + // The Add/Remove pair for SbSocket based socket bool Add(SbSocket socket, void* context, SbSocketWaiterCallback callback, int interests, bool persistent); - bool Remove(SbSocket socket); + bool Remove(SbSocket socket, SbSocketWaiter waiter); + bool CheckSocketRegistered(SbSocket socket); + void Wait(); SbSocketWaiterResult WaitTimed(int64_t duration_usec); void WakeUp(bool timeout); + int use_int_socket; + private: // A registration of a socket with a socket waiter. struct Waitee { +#if SB_API_VERSION >= 16 + Waitee(SbSocketWaiter waiter, + int socket, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) + : waiter(waiter), + i_socket(socket), + context(context), + i_callback(callback), + interests(interests), + persistent(persistent) { + use_int_socket = 1; + } +#endif // SB_API_VERSION >= 16 Waitee(SbSocketWaiter waiter, SbSocket socket, void* context, @@ -52,24 +85,31 @@ struct SbSocketWaiterPrivate { int interests, bool persistent) : waiter(waiter), - socket(socket), + sb_socket(socket), context(context), - callback(callback), + sb_callback(callback), interests(interests), - persistent(persistent) {} + persistent(persistent) { + use_int_socket = 0; + } + + // The socket registered with the waiter. + int i_socket; + SbSocket sb_socket; + int use_int_socket; + + // The callback to call when one or more registered interests become ready. +#if SB_API_VERSION >= 16 + SbPosixSocketWaiterCallback i_callback; +#endif // SB_API_VERSION >= 16 + SbSocketWaiterCallback sb_callback; // The waiter this event is registered with. SbSocketWaiter waiter; - // The socket registered with the waiter. - SbSocket socket; - // A context value that will be passed to the callback. void* context; - // The callback to call when one or more registered interests become ready. - SbSocketWaiterCallback callback; - // The set of interests registered with the waiter. int interests; @@ -84,7 +124,8 @@ struct SbSocketWaiterPrivate { // // NOTE: This is a (tree) map because we don't have base::hash_map here. We // should keep an eye out for whether this is a performance issue. - typedef std::map WaiteesMap; + typedef std::map i_WaiteesMap; + typedef std::map sb_WaiteesMap; // The libevent callback function, which in turn calls the registered callback // function for the Waitee. @@ -107,6 +148,13 @@ struct SbSocketWaiterPrivate { // Adds |waitee| to the waitee registry. void AddWaitee(Waitee* waitee); + // Gets the Waitee associated with the given socket, or NULL. + Waitee* GetWaitee(int socket); + + // Gets the Waitee associated with the given socket, removing it from the + // registry, or NULL. + Waitee* RemoveWaitee(int socket) SB_WARN_UNUSED_RESULT; + // Gets the Waitee associated with the given socket, or NULL. Waitee* GetWaitee(SbSocket socket); @@ -134,7 +182,8 @@ struct SbSocketWaiterPrivate { struct event wakeup_event_; // The registry of currently registered Waitees. - WaiteesMap waitees_; + i_WaiteesMap i_waitees_; + sb_WaiteesMap sb_waitees_; // Whether or not the waiter was woken up. bool woken_up_; diff --git a/starboard/shared/libevent/socket_waiter_remove.cc b/starboard/shared/libevent/socket_waiter_remove.cc index db82ff93837b..9361501f961c 100644 --- a/starboard/shared/libevent/socket_waiter_remove.cc +++ b/starboard/shared/libevent/socket_waiter_remove.cc @@ -12,14 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/socket_waiter.h" - #include "starboard/shared/libevent/socket_waiter_internal.h" +#include "starboard/socket.h" +#include "starboard/socket_waiter.h" bool SbSocketWaiterRemove(SbSocketWaiter waiter, SbSocket socket) { if (!SbSocketWaiterIsValid(waiter)) { return false; } + return waiter->Remove(socket, waiter); +} + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + +bool SbPosixSocketWaiterRemove(SbSocketWaiter waiter, int socket) { + if (!SbSocketWaiterIsValid(waiter)) { + return false; + } - return waiter->Remove(socket); + return waiter->Remove(socket, waiter); } + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) diff --git a/starboard/shared/stub/socket_waiter_add.cc b/starboard/shared/stub/socket_waiter_add.cc index 20949e969d6a..2529e2c03342 100644 --- a/starboard/shared/stub/socket_waiter_add.cc +++ b/starboard/shared/stub/socket_waiter_add.cc @@ -22,3 +22,14 @@ bool SbSocketWaiterAdd(SbSocketWaiter waiter, bool persistent) { return false; } + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool SbPosixSocketWaiterAdd(SbSocketWaiter waiter, + int socket, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) { + return false; +} +#endif diff --git a/starboard/shared/stub/socket_waiter_remove.cc b/starboard/shared/stub/socket_waiter_remove.cc index 4a8406ea3f33..26b925ae9bc0 100644 --- a/starboard/shared/stub/socket_waiter_remove.cc +++ b/starboard/shared/stub/socket_waiter_remove.cc @@ -17,3 +17,9 @@ bool SbSocketWaiterRemove(SbSocketWaiter waiter, SbSocket socket) { return false; } + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool SbPosixSocketWaiterRemove(SbSocketWaiter waiter, int socket) { + return false; +} +#endif diff --git a/starboard/shared/win32/posix_emu/include/sys/socket.h b/starboard/shared/win32/posix_emu/include/sys/socket.h index 39c7e5390c6c..ca8206e03c1c 100644 --- a/starboard/shared/win32/posix_emu/include/sys/socket.h +++ b/starboard/shared/win32/posix_emu/include/sys/socket.h @@ -37,7 +37,7 @@ int sb_listen(int socket, int backlog); int sb_accept(int socket, sockaddr* addr, int* addrlen); #define accept sb_accept -int sb_connect(int socket, sockaddr* name, int namelen); +int sb_connect(int socket, const sockaddr* name, int namelen); #define connect sb_connect int sb_send(int sockfd, const void* buf, size_t len, int flags); @@ -69,6 +69,9 @@ int sb_setsockopt(int socket, int option_len); #define setsockopt sb_setsockopt +int posix_socket_get_fd_from_handle(SOCKET socket); +SOCKET posix_socket_get_handle_from_fd(int socket); + #ifdef __cplusplus } #endif diff --git a/starboard/shared/win32/posix_emu/include/sys/un.h b/starboard/shared/win32/posix_emu/include/sys/un.h new file mode 100644 index 000000000000..29038769d31c --- /dev/null +++ b/starboard/shared/win32/posix_emu/include/sys/un.h @@ -0,0 +1,33 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_UN_H_ +#define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_UN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int sa_family_t; + +struct sockaddr_un { + sa_family_t sun_family; /* AF_UNIX */ + char sun_path[108]; /* Pathname */ +}; + +#ifdef __cplusplus +} +#endif + +#endif // STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_UN_H_ diff --git a/starboard/shared/win32/posix_emu/socket.cc b/starboard/shared/win32/posix_emu/socket.cc index ca2539b096bc..12d5937d5e1f 100644 --- a/starboard/shared/win32/posix_emu/socket.cc +++ b/starboard/shared/win32/posix_emu/socket.cc @@ -98,6 +98,23 @@ static FileOrSocket handle_db_get(int fd, bool erase) { return handle; } +static int handle_db_get_fd(SOCKET handle) { + int fd = -1; + if (handle == INVALID_SOCKET) { + return fd; + } + + EnterCriticalSection(&g_critical_section.critical_section_); + for (auto i : *g_map_addr) { + if (i.second.is_file == false && i.second.socket == handle) { + fd = i.first; + break; + } + } + LeaveCriticalSection(&g_critical_section.critical_section_); + return fd; +} + // WSAGetLastError should be called immediately to retrieve the extended error // code for the failing function call. // https://learn.microsoft.com/en-us/windows/win32/winsock/error-codes-errno-h-errno-and-wsagetlasterror-2 @@ -383,7 +400,7 @@ int sb_accept(int socket, sockaddr* addr, int* addrlen) { return handle_db_put(handle); } -int sb_connect(int socket, sockaddr* name, int namelen) { +int sb_connect(int socket, const sockaddr* name, int namelen) { SOCKET socket_handle = handle_db_get(socket, false).socket; if (socket_handle == INVALID_SOCKET) { return -1; @@ -500,4 +517,17 @@ int sb_fcntl(int fd, int cmd, ... /*arg*/) { } return 0; } + +int posix_socket_get_fd_from_handle(SOCKET socket) { + return handle_db_get_fd(socket); +} + +SOCKET posix_socket_get_handle_from_fd(int socket) { + FileOrSocket handle = handle_db_get(socket, false); + if (handle.is_file || handle.socket == INVALID_SOCKET) { + return INVALID_SOCKET; + } + return handle.socket; +} + } // extern "C" diff --git a/starboard/shared/win32/socket_waiter_add.cc b/starboard/shared/win32/socket_waiter_add.cc index 33cdf60a6094..35ff11b8f028 100644 --- a/starboard/shared/win32/socket_waiter_add.cc +++ b/starboard/shared/win32/socket_waiter_add.cc @@ -17,6 +17,37 @@ #include "starboard/common/log.h" #include "starboard/shared/win32/socket_waiter_internal.h" +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool SbPosixSocketWaiterAdd(SbSocketWaiter waiter, + int socket, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) { + if (!SbSocketWaiterIsValid(waiter)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Waiter (" << waiter << ") is invalid."; + return false; + } + + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (!callback) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No callback provided."; + return false; + } + + if (!interests) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No interests provided."; + return false; + } + + return waiter->Add(socket, waiter, context, callback, interests, persistent); +} +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool SbSocketWaiterAdd(SbSocketWaiter waiter, SbSocket socket, void* context, diff --git a/starboard/shared/win32/socket_waiter_internal.cc b/starboard/shared/win32/socket_waiter_internal.cc index f745689092f7..78ec46fe1f14 100644 --- a/starboard/shared/win32/socket_waiter_internal.cc +++ b/starboard/shared/win32/socket_waiter_internal.cc @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/shared/win32/socket_waiter_internal.h" +#include +#undef socket #include @@ -24,6 +25,7 @@ #include "starboard/common/time.h" #include "starboard/shared/win32/error_utils.h" #include "starboard/shared/win32/socket_internal.h" +#include "starboard/shared/win32/socket_waiter_internal.h" #include "starboard/shared/win32/thread_private.h" #include "starboard/shared/win32/time_utils.h" #include "starboard/thread.h" @@ -142,11 +144,125 @@ SbSocketWaiterPrivate::SbSocketWaiterPrivate() SbSocketWaiterPrivate::~SbSocketWaiterPrivate() { for (auto& it : waitees_.GetWaitees()) { if (it) { - SB_DCHECK(CheckSocketWaiterIsThis(it->socket)); + if (it->use_posix_socket == 1) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + SB_DCHECK(CheckSocketWaiterIsThis(it->posix_socket, it->waiter)); +#endif + } else { + SB_DCHECK(CheckSocketWaiterIsThis(it->socket)); + } } } } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool SbSocketWaiterPrivate::Add(int socket, + SbSocketWaiter waiter, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) { + SB_DCHECK(pthread_equal(pthread_self(), thread_)); + + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (!interests) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No interests provided."; + return false; + } + + // The policy is not to add a socket to a waiter if it is registered with + // another waiter. + + // TODO: Since integer based socket fd doesn't have waiter information, + // need to find a way to keep track whether this socket has been + // registered with a waiter already. + // At this moment, at least we can test if this specific socket + // is already registered to this incoming waiter. + if (waiter->CheckSocketRegistered(socket)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket already has this waiter (" + << this << ")."; + return false; + } + + int network_event_interests = 0; + if (interests & kSbSocketWaiterInterestRead) { + network_event_interests |= FD_READ | FD_ACCEPT | FD_CLOSE; + } + + if (interests & kSbSocketWaiterInterestWrite) { + network_event_interests |= FD_CONNECT | FD_WRITE; + } + + const BOOL manual_reset = !persistent; + + // Without SbSocket->socket_event, we need a standalone socket_event and store + // it inside the waitee. + sbwin32::AutoEventHandle* socket_event_ptr = + new sbwin32::AutoEventHandle(WSA_INVALID_EVENT); + + socket_event_ptr->Reset(CreateEvent(nullptr, manual_reset, false, nullptr)); + if (socket_event_ptr->GetEvent() == WSA_INVALID_EVENT) { + int last_error = WSAGetLastError(); + SB_DLOG(ERROR) << "Error calling WSACreateEvent() last_error = " + << sbwin32::Win32ErrorCode(last_error); + return false; + } + + // Note that WSAEnumNetworkEvents used elsewhere only works with + // WSAEventSelect. + // Please consider that before changing this code. + int return_value = + WSAEventSelect(posix_socket_get_handle_from_fd(socket), + socket_event_ptr->GetEvent(), network_event_interests); + + if (return_value == SOCKET_ERROR) { + int last_error = WSAGetLastError(); + SB_DLOG(ERROR) << "Error calling WSAEventSelect() last_error = " + << sbwin32::Win32ErrorCode(last_error); + return false; + } + + if (waitees_.GetHandleArraySize() >= MAXIMUM_WAIT_OBJECTS) { + SB_DLOG(ERROR) << "Reached maxed number of socket events (" + << MAXIMUM_WAIT_OBJECTS << ")"; + return false; + } + + std::unique_ptr waitee(new Waitee(this, socket, socket_event_ptr, + context, callback, interests, + persistent)); + + waitees_.AddSocketEventAndWaitee(socket_event_ptr->GetEvent(), + std::move(waitee)); + waiter = this; + + return true; +} + +bool SbSocketWaiterPrivate::Remove(int socket, SbSocketWaiter waiter) { + SB_DCHECK(pthread_equal(pthread_self(), thread_)); + + if (!CheckSocketWaiterIsThis(socket, waiter)) { + return false; + } + + waiter = kSbSocketWaiterInvalid; + + Waitee* waitee_ptr = waitees_.GetWaitee(socket); + if (waitee_ptr != nullptr && waitee_ptr->socket_event_ptr != nullptr) { + delete waitee_ptr->socket_event_ptr; + waitee_ptr->socket_event_ptr = nullptr; + } + + return waitees_.RemoveSocket(socket); +} + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool SbSocketWaiterPrivate::Add(SbSocket socket, void* context, SbSocketWaiterCallback callback, @@ -263,6 +379,36 @@ void SbSocketWaiterPrivate::ResetWakeupEvent() { WSAResetEvent(wakeup_event_.GetEvent()); } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool SbSocketWaiterPrivate::CheckSocketWaiterIsThis(int socket, + SbSocketWaiter waiter) { + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (waiter != this) { + return false; + } + + return true; +} + +bool SbSocketWaiterPrivate::CheckSocketRegistered(int socket) { + if (socket < 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + + if (waitees_.GetIndex(socket) == starboard::nullopt) { + return false; + } + + return true; +} + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool SbSocketWaiterPrivate::CheckSocketWaiterIsThis(SbSocket socket) { if (!SbSocketIsValid(socket)) { SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; @@ -276,6 +422,18 @@ bool SbSocketWaiterPrivate::CheckSocketWaiterIsThis(SbSocket socket) { return true; } +bool SbSocketWaiterPrivate::CheckSocketRegistered(SbSocket socket) { + if (!SbSocketIsValid(socket)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": Socket (" << socket << ") is invalid."; + return false; + } + if (waitees_.GetIndex(socket) == starboard::nullopt) { + return false; + } + + return true; +} + void SbSocketWaiterPrivate::Wait() { SB_DCHECK(pthread_equal(pthread_self(), thread_)); @@ -308,33 +466,65 @@ SbSocketWaiterResult SbSocketWaiterPrivate::WaitTimed(int64_t duration_usec) { } } - // There should always be a wakeup event. - SB_DCHECK(number_events > 0); - - SbSocket maybe_writable_socket = kSbSocketInvalid; + // Check existing waitees to find out which type of socket is used + // This check applies to SB16 and above only because of the POSIX APIs. + int use_posix_socket = 0; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) for (auto& it : waitees_.GetWaitees()) { if (!it) { continue; } - if ((it->interests & kSbSocketWaiterInterestWrite) == 0) { - continue; - } - if (it->socket->writable.load()) { - maybe_writable_socket = it->socket; + if (it->use_posix_socket == 1) { + use_posix_socket = 1; break; } } +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + + // There should always be a wakeup event. + SB_DCHECK(number_events > 0); + bool has_writable = 0; +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + int posix_maybe_writable_socket = -1; +#endif + SbSocket maybe_writable_socket = kSbSocketInvalid; + + if (use_posix_socket == 1) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + has_writable = (posix_maybe_writable_socket != -1); +#endif + } else { + for (auto& it : waitees_.GetWaitees()) { + if (!it) { + continue; + } + if ((it->interests & kSbSocketWaiterInterestWrite) == 0) { + continue; + } + if (it->socket->writable.load()) { + maybe_writable_socket = it->socket; + break; + } + } + + has_writable = (maybe_writable_socket != kSbSocketInvalid); + } - bool has_writable = (maybe_writable_socket != kSbSocketInvalid); DWORD return_value = WSAWaitForMultipleEvents(number_events, waitees_.GetHandleArray(), false, has_writable ? 0 : millis, false); if (has_writable || ((return_value >= WSA_WAIT_EVENT_0) && (return_value < (WSA_WAIT_EVENT_0 + number_events)))) { - int64_t socket_index; + int64_t socket_index = 0; if (has_writable) { - socket_index = waitees_.GetIndex(maybe_writable_socket).value(); + if (use_posix_socket == 1) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + socket_index = waitees_.GetIndex(posix_maybe_writable_socket).value(); +#endif + } else { + socket_index = waitees_.GetIndex(maybe_writable_socket).value(); + } } else { socket_index = static_cast(return_value) - static_cast(WSA_WAIT_EVENT_0); @@ -363,26 +553,47 @@ SbSocketWaiterResult SbSocketWaiterPrivate::WaitTimed(int64_t duration_usec) { // Remove the non-persistent waitee before calling the callback, so // that we can add another waitee in the callback if we need to. This // is also why we copy all the fields we need out of waitee. - const SbSocket socket = waitee->socket; - const SbSocketWaiterCallback callback = waitee->callback; - void* context = waitee->context; - - // Note: this should also go before Remove(). - SbSocketWaiterInterest interests = - DiscoverNetworkEventInterests(socket->socket_handle); - - if ((waitee->interests & kSbSocketWaiterInterestWrite) && - socket->writable.load()) { - interests = CombineInterests(interests, kSbSocketWaiterInterestWrite); - } else if (interests & kSbSocketWaiterInterestWrite) { - socket->writable.store(true); + if (use_posix_socket == 1) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + const int posix_socket = waitee->posix_socket; + const SbPosixSocketWaiterCallback posix_callback = + waitee->posix_callback; + + void* context = waitee->context; + + // Note: this should also go before Remove(). + SbSocketWaiterInterest interests = DiscoverNetworkEventInterests( + posix_socket_get_handle_from_fd(posix_socket)); + + // TODO: implement "writable" + if (!waitee->persistent) { + Remove(waitee->posix_socket, waitee->waiter); + } + posix_callback(this, posix_socket, context, interests); +#endif + } else { + const SbSocket socket = waitee->socket; + const SbSocketWaiterCallback callback = waitee->callback; + + void* context = waitee->context; + + // Note: this should also go before Remove(). + SbSocketWaiterInterest interests = + DiscoverNetworkEventInterests(socket->socket_handle); + + if ((waitee->interests & kSbSocketWaiterInterestWrite) && + socket->writable.load()) { + interests = + CombineInterests(interests, kSbSocketWaiterInterestWrite); + } else if (interests & kSbSocketWaiterInterestWrite) { + socket->writable.store(true); + } + + if (!waitee->persistent) { + Remove(waitee->socket); + } + callback(this, socket, context, interests); } - - if (!waitee->persistent) { - Remove(waitee->socket); - } - - callback(this, socket, context, interests); } } else if (return_value == WSA_WAIT_FAILED) { SB_DLOG(ERROR) << "Wait failed -- " @@ -419,6 +630,55 @@ void SbSocketWaiterPrivate::WakeUp() { SignalWakeupEvent(); } +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::WaiteeRegistry::GetWaitee( + int socket) { + starboard::optional token = GetIndex(socket); + if (!token) { + return nullptr; + } + return waitees_[token.value()].get(); +} + +starboard::optional SbSocketWaiterPrivate::WaiteeRegistry::GetIndex( + int socket) { + auto iterator = posix_socket_to_index_map_.find(socket); + if (iterator == posix_socket_to_index_map_.end()) { + return starboard::nullopt; + } + + return iterator->second; +} + +bool SbSocketWaiterPrivate::WaiteeRegistry::RemoveSocket(int socket) { + auto iterator = posix_socket_to_index_map_.find(socket); + if (iterator == posix_socket_to_index_map_.end()) { + return false; + } + + const std::size_t current_size = socket_events_.size(); + SB_DCHECK(current_size == waitees_.size()); + + const std::size_t socket_index = iterator->second; + int socket_to_swap = waitees_[current_size - 1]->posix_socket; + // Since |EraseIndexFromVector| will swap the last socket and the socket + // at current index, |socket_to_index_| will need to be updated. + posix_socket_to_index_map_[socket_to_swap] = socket_index; + + // Note that |EraseIndexFromVector| only touches the last element and the + // element to remove. + EraseIndexFromVector(&socket_events_, socket_index); + EraseIndexFromVector(&waitees_, socket_index); + + posix_socket_to_index_map_.erase(socket); + + SB_DCHECK(socket_events_.size() == waitees_.size()); + SB_DCHECK(socket_events_.size() == posix_socket_to_index_map_.size()); + return true; +} + +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) + SbSocketWaiterPrivate::Waitee* SbSocketWaiterPrivate::WaiteeRegistry::GetWaitee( SbSocket socket) { starboard::optional token = GetIndex(socket); @@ -443,11 +703,23 @@ SbSocketWaiterPrivate::WaiteeRegistry::AddSocketEventAndWaitee( std::unique_ptr waitee) { SB_DCHECK(socket_event != WSA_INVALID_EVENT); SB_DCHECK(socket_events_.size() == waitees_.size()); - SbSocket socket = kSbSocketInvalid; - if (waitee) { - socket = waitee->socket; + + if (!waitee) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + posix_socket_to_index_map_.emplace(-1, socket_events_.size()); +#endif + socket_to_index_map_.emplace(kSbSocketInvalid, socket_events_.size()); + } else { + if (waitee->use_posix_socket == 1) { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + posix_socket_to_index_map_.emplace(waitee->posix_socket, + socket_events_.size()); +#endif + } else { + socket_to_index_map_.emplace(waitee->socket, socket_events_.size()); + } } - socket_to_index_map_.emplace(socket, socket_events_.size()); + socket_events_.emplace_back(socket_event); waitees_.emplace_back(std::move(waitee)); diff --git a/starboard/shared/win32/socket_waiter_internal.h b/starboard/shared/win32/socket_waiter_internal.h index 28bd02e78b38..6b7fb9d06805 100644 --- a/starboard/shared/win32/socket_waiter_internal.h +++ b/starboard/shared/win32/socket_waiter_internal.h @@ -48,6 +48,16 @@ class SbSocketWaiterPrivate { ~SbSocketWaiterPrivate(); // These methods implement the SbSocketWaiter API defined in socket_waiter.h. +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool Add(int socket, + SbSocketWaiter waiter, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent); + bool Remove(int socket, SbSocketWaiter waiter); + bool CheckSocketRegistered(int socket); +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) bool Add(SbSocket socket, void* context, SbSocketWaiterCallback callback, @@ -58,10 +68,37 @@ class SbSocketWaiterPrivate { SbSocketWaiterResult WaitTimed(int64_t duration_usec); void WakeUp(); void HandleWakeUpRead(); + bool CheckSocketRegistered(SbSocket socket); private: // A registration of a socket with a socket waiter. struct Waitee { +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + Waitee(SbSocketWaiter waiter, + int socket, + sbwin32::AutoEventHandle* socket_event_ptr, + void* context, + SbPosixSocketWaiterCallback callback, + int interests, + bool persistent) + : waiter(waiter), + posix_socket(socket), + socket_event_ptr(socket_event_ptr), + context(context), + posix_callback(callback), + interests(interests), + persistent(persistent) { + use_posix_socket = 1; + } + // The socket registered with the waiter. + int posix_socket; + + // The callback to call when one or more registered interests become ready. + SbPosixSocketWaiterCallback posix_callback; + + // The event related to the socket_handle. Used for SbSocketWaiter. + sbwin32::AutoEventHandle* socket_event_ptr; +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) Waitee(SbSocketWaiter waiter, SbSocket socket, void* context, @@ -73,19 +110,24 @@ class SbSocketWaiterPrivate { context(context), callback(callback), interests(interests), - persistent(persistent) {} - // The waiter this event is registered with. - SbSocketWaiter waiter; + persistent(persistent) { + use_posix_socket = 0; + } + + int use_posix_socket; // The socket registered with the waiter. SbSocket socket; - // A context value that will be passed to the callback. - void* context; - // The callback to call when one or more registered interests become ready. SbSocketWaiterCallback callback; + // The waiter this event is registered with. + SbSocketWaiter waiter; + + // A context value that will be passed to the callback. + void* context; + // The set of interests registered with the waiter. int interests; @@ -97,29 +139,47 @@ class SbSocketWaiterPrivate { public: typedef int64_t LookupToken; typedef std::deque> Waitees; +#if SB_API_VERSION >= 16 + typedef std::unordered_map posix_SocketToIndex; +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) typedef std::unordered_map SocketToIndex; WSAEVENT* GetHandleArray() { return socket_events_.data(); } std::size_t GetHandleArraySize() { return socket_events_.size(); } const Waitees& GetWaitees() const { return waitees_; } +#if SB_API_VERSION >= 16 + // Gets the Waitee associated with the given socket, or nullptr. + Waitee* GetWaitee(int socket); + + // Gets the index by socket + starboard::optional GetIndex(int socket); + + // Returns true if socket was found, and removed. + bool RemoveSocket(int socket); +#endif // SB_API_VERSION >= 16 && !defined(_MSC_VER) // Gets the Waitee associated with the given socket, or nullptr. Waitee* GetWaitee(SbSocket socket); // Gets the index by socket starboard::optional GetIndex(SbSocket socket); + // Returns true if socket was found, and removed. + bool RemoveSocket(SbSocket socket); + // Gets the Waitee by index. Waitee* GetWaiteeByIndex(LookupToken socket_index); // Returns the index of the event. LookupToken AddSocketEventAndWaitee(WSAEVENT socket_event, std::unique_ptr waitee); - // Returns true if socket was found, and removed. - bool RemoveSocket(SbSocket socket); private: +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + posix_SocketToIndex posix_socket_to_index_map_; +#endif // SB_API_VERSION >= 16 SocketToIndex socket_to_index_map_; + std::vector socket_events_; std::deque> waitees_; }; @@ -127,6 +187,9 @@ class SbSocketWaiterPrivate { void SignalWakeupEvent(); void ResetWakeupEvent(); +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) + bool CheckSocketWaiterIsThis(int socket, SbSocketWaiter waiter); +#endif // SB_API_VERSION >= 16 bool CheckSocketWaiterIsThis(SbSocket socket); // The thread this waiter was created on. Immutable, so accessible from any diff --git a/starboard/shared/win32/socket_waiter_remove.cc b/starboard/shared/win32/socket_waiter_remove.cc index 5f8e2fad0b8f..e52195449edb 100644 --- a/starboard/shared/win32/socket_waiter_remove.cc +++ b/starboard/shared/win32/socket_waiter_remove.cc @@ -23,3 +23,13 @@ bool SbSocketWaiterRemove(SbSocketWaiter waiter, SbSocket socket) { return waiter->Remove(socket); } + +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) +bool SbPosixSocketWaiterRemove(SbSocketWaiter waiter, int socket) { + if (!SbSocketWaiterIsValid(waiter)) { + return false; + } + + return waiter->Remove(socket, waiter); +} +#endif diff --git a/starboard/socket_waiter.h b/starboard/socket_waiter.h index 7b5e02fce28b..ab2627a15778 100644 --- a/starboard/socket_waiter.h +++ b/starboard/socket_waiter.h @@ -149,7 +149,7 @@ SB_EXPORT bool SbSocketWaiterAdd(SbSocketWaiter waiter, int interests, bool persistent); -#if SB_API_VERSION >= 16 +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) SB_EXPORT bool SbPosixSocketWaiterAdd(SbSocketWaiter waiter, int socket, void* context, @@ -171,7 +171,7 @@ SB_EXPORT bool SbPosixSocketWaiterAdd(SbSocketWaiter waiter, // |socket|: The socket to remove from the waiter. SB_EXPORT bool SbSocketWaiterRemove(SbSocketWaiter waiter, SbSocket socket); -#if SB_API_VERSION >= 16 +#if SB_API_VERSION >= 16 && !defined(_MSC_VER) SB_EXPORT bool SbPosixSocketWaiterRemove(SbSocketWaiter waiter, int socket); #endif diff --git a/starboard/tools/api_leak_detector/api_leak_detector.py b/starboard/tools/api_leak_detector/api_leak_detector.py index ab667b620b77..21ab10073876 100755 --- a/starboard/tools/api_leak_detector/api_leak_detector.py +++ b/starboard/tools/api_leak_detector/api_leak_detector.py @@ -94,6 +94,7 @@ 'connect', 'clock_gettime', 'close', + 'fcntl', 'free', 'freeifaddrs', 'freeaddrinfo', @@ -103,6 +104,9 @@ 'gettimeofday', 'getifaddrs', 'getaddrinfo', + 'getpeername', + 'getsockname', + 'getsockopt', 'gmtime_r', 'inet_ntop', 'listen', @@ -111,6 +115,7 @@ 'posix_memalign', 'recv', 'recvfrom', + 'recvmsg', 'realloc', 'rmdir', 'setsockopt',