diff --git a/base/message_loop/message_pump_io_starboard.cc b/base/message_loop/message_pump_io_starboard.cc index d9ce934a2046..af0ad19cc771 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 +#include +#include +#include +#endif + #include "base/auto_reset.h" #include "base/compiler_specific.h" #include "base/logging.h" @@ -23,18 +29,28 @@ #include "starboard/common/socket.h" #include "starboard/socket_waiter.h" + + namespace base { MessagePumpIOStarboard::SocketWatcher::SocketWatcher(const Location& from_here) : created_from_location_(from_here), interests_(kSbSocketWaiterInterestNone), +#if SB_API_VERSION >= 16 + socket_(-1), +#else socket_(kSbSocketInvalid), +#endif pump_(nullptr), watcher_(nullptr), weak_factory_(this) {} MessagePumpIOStarboard::SocketWatcher::~SocketWatcher() { +#if SB_API_VERSION >= 16 + if (socket_ >= 0) { +#else if (SbSocketIsValid(socket_)) { +#endif StopWatchingSocket(); } } @@ -42,15 +58,25 @@ MessagePumpIOStarboard::SocketWatcher::~SocketWatcher() { bool MessagePumpIOStarboard::SocketWatcher::StopWatchingSocket() { watcher_ = nullptr; interests_ = kSbSocketWaiterInterestNone; +#if SB_API_VERSION >= 16 + if (socket_ < 0) { +#else if (!SbSocketIsValid(socket_)) { +#endif pump_ = nullptr; // If this watcher is not watching anything, no-op and return success. return true; } +#if SB_API_VERSION >= 16 + int socket = Release(); + bool result = true; + if (socket >= 0) { +#else SbSocket socket = Release(); bool result = true; if (SbSocketIsValid(socket)) { +#endif DCHECK(pump_); result = pump_->StopWatching(socket); } @@ -58,22 +84,42 @@ bool MessagePumpIOStarboard::SocketWatcher::StopWatchingSocket() { return result; } +#if SB_API_VERSION >= 16 +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 +int MessagePumpIOStarboard::SocketWatcher::Release() { + int socket = socket_; + socket_ = -1; + return socket; +} +#else SbSocket MessagePumpIOStarboard::SocketWatcher::Release() { SbSocket socket = socket_; socket_ = kSbSocketInvalid; return socket; } +#endif void MessagePumpIOStarboard::SocketWatcher::OnSocketReadyToRead( +#if SB_API_VERSION >= 16 + int socket, +#else SbSocket socket, +#endif MessagePumpIOStarboard* pump) { if (!watcher_) return; @@ -83,7 +129,11 @@ void MessagePumpIOStarboard::SocketWatcher::OnSocketReadyToRead( } void MessagePumpIOStarboard::SocketWatcher::OnSocketReadyToWrite( +#if SB_API_VERSION >= 16 + int socket, +#else SbSocket socket, +#endif MessagePumpIOStarboard* pump) { if (!watcher_) return; @@ -102,12 +152,21 @@ MessagePumpIOStarboard::~MessagePumpIOStarboard() { SbSocketWaiterDestroy(waiter_); } +#if SB_API_VERSION >= 16 +bool MessagePumpIOStarboard::Watch(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); @@ -123,8 +182,14 @@ bool MessagePumpIOStarboard::Watch(SbSocket socket, interests |= kSbSocketWaiterInterestWrite; } +#if SB_API_VERSION >= 16 + int old_socket = controller->Release(); + if (old_socket >= 0) +#else SbSocket old_socket = controller->Release(); - if (SbSocketIsValid(old_socket)) { + 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) { @@ -141,14 +206,25 @@ bool MessagePumpIOStarboard::Watch(SbSocket socket, interests |= old_interest_mask; // Must disarm the event before we can reuse it. +#if SB_API_VERSION >= 16 + SbPosixSocketWaiterRemove(waiter_, old_socket); +#else SbSocketWaiterRemove(waiter_, old_socket); +#endif // SB_API_VERSION >= 16 } // Set current interest mask and waiter for this event. +#if SB_API_VERSION >= 16 + if (!SbPosixSocketWaiterAdd(waiter_, socket, controller, + OnPosixSocketWaiterNotification, interests, persistent)){ + return false; + } +#else if (!SbSocketWaiterAdd(waiter_, socket, controller, OnSocketWaiterNotification, interests, persistent)) { return false; } +#endif // SB_API_VERSION >= 16 controller->Init(socket, persistent); controller->set_watcher(delegate); @@ -157,9 +233,15 @@ bool MessagePumpIOStarboard::Watch(SbSocket socket, return true; } +#if SB_API_VERSION >= 16 +bool MessagePumpIOStarboard::StopWatching(int socket) { + return SbPosixSocketWaiterRemove(waiter_, socket); +} +#else bool MessagePumpIOStarboard::StopWatching(SbSocket socket) { return SbSocketWaiterRemove(waiter_, socket); } +#endif // SB_API_VERSION >= 16 void MessagePumpIOStarboard::AddIOObserver(IOObserver* obs) { io_observers_.AddObserver(obs); @@ -252,6 +334,36 @@ void MessagePumpIOStarboard::DidProcessIOEvent() { } } +#if SB_API_VERSION >= 16 + +// 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->OnSocketReadyToWrite(socket, pump); + } + + // Check |controller| in case it's been deleted previously. + if (controller.get() && ready_interests & kSbSocketWaiterInterestRead) { + controller->OnSocketReadyToRead(socket, pump); + } +} + +#else // static void MessagePumpIOStarboard::OnSocketWaiterNotification(SbSocketWaiter waiter, SbSocket socket, @@ -279,4 +391,5 @@ void MessagePumpIOStarboard::OnSocketWaiterNotification(SbSocketWaiter waiter, } } +#endif // SB_API_VERSION >= 16 } // namespace base diff --git a/base/message_loop/message_pump_io_starboard.h b/base/message_loop/message_pump_io_starboard.h index b7d807dec914..5c952e615913 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 + virtual void OnSocketReadyToRead(int socket) {} + virtual void OnSocketReadyToWrite(int socket) {} +#else virtual void OnSocketReadyToRead(SbSocket socket) {} virtual void OnSocketReadyToWrite(SbSocket socket) {} +#endif protected: virtual ~Watcher() {} @@ -79,8 +86,13 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { friend class MessagePumpIOStarboardTest; // Called by MessagePumpIOStarboard. +#if SB_API_VERSION >= 16 + 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 +102,21 @@ class BASE_EXPORT MessagePumpIOStarboard : public MessagePump { void set_watcher(Watcher* watcher) { watcher_ = watcher; } +#if SB_API_VERSION >= 16 + void OnSocketReadyToRead(int socket, MessagePumpIOStarboard* pump); + void OnSocketReadyToWrite(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 + int socket_; +#else SbSocket socket_; +#endif bool persistent_; MessagePumpIOStarboard* pump_; Watcher* watcher_; @@ -123,6 +144,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 + bool Watch(int socket, + bool persistent, + int mode, + SocketWatcher* controller, + Watcher* delegate); + + // Stops watching the socket. + bool StopWatching(int socket); +#else bool Watch(SbSocket socket, bool persistent, int mode, @@ -131,6 +162,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 +181,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 + 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..f9a31c74054c 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 +#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 + 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 + close(socket_); +#else SbSocketDestroy(socket_); +#endif } std::unique_ptr CreateMessagePump() { return std::make_unique(); } +#if SB_API_VERSION >= 16 + 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 + 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 + 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 + void OnSocketReadyToRead(int socket) override {} + void OnSocketReadyToWrite(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 + void OnSocketReadyToRead(int socket) override { NOTREACHED(); } + void OnSocketReadyToWrite(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 + void OnSocketReadyToWrite(int socket) override { +#else void OnSocketReadyToWrite(SbSocket socket) override { +#endif DCHECK(controller_); controller_.reset(); } @@ -151,7 +198,11 @@ class StopWatcher : public BaseWatcher { ~StopWatcher() override = default; +#if SB_API_VERSION >= 16 + void OnSocketReadyToWrite(int socket) override { +#else void OnSocketReadyToWrite(SbSocket socket) override { +#endif controller_->StopWatchingSocket(); } @@ -186,15 +237,24 @@ class NestedPumpWatcher : public MessagePumpIOStarboard::Watcher { NestedPumpWatcher() = default; ~NestedPumpWatcher() override = default; +#if SB_API_VERSION >= 16 + void OnSocketReadyToRead(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 + void OnSocketReadyToWrite(int socket) override {} +}; +#else void OnSocketReadyToWrite(SbSocket socket) override {} }; +#endif // Fails on some platforms. TEST_F(MessagePumpIOStarboardTest, DISABLED_NestedPumpWatcher) { @@ -218,7 +278,11 @@ class QuitWatcher : public BaseWatcher { QuitWatcher(base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} +#if SB_API_VERSION >= 16 + void OnSocketReadyToRead(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)); diff --git a/base/task/current_thread.cc b/base/task/current_thread.cc index 673e2028d4a2..0b80e7ff4c14 100644 --- a/base/task/current_thread.cc +++ b/base/task/current_thread.cc @@ -212,11 +212,19 @@ MessagePumpForIO* CurrentIOThread::GetMessagePumpForIO() const { #if !BUILDFLAG(IS_NACL) #if defined(STARBOARD) +#if SB_API_VERSION >= 16 +bool CurrentIOThread::Watch(int socket, + bool persistent, + int mode, + SocketWatcher* controller, + Watcher* delegate) { +#else bool CurrentIOThread::Watch(SbSocket socket, bool persistent, int mode, SocketWatcher* controller, Watcher* delegate) { +#endif return static_cast(GetMessagePumpForIO()) ->Watch(socket, persistent, mode, controller, delegate); } diff --git a/base/task/current_thread.h b/base/task/current_thread.h index 5106c5e9fd71..47719a35c652 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 + bool Watch(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..3fdf1d63642a 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -1175,6 +1175,8 @@ component("net") { "socket/tcp_socket_starboard.h", "socket/udp_socket_starboard.cc", "socket/udp_socket_starboard.h", + + "base/net_errors_posix.cc", ] deps += [ "//starboard:starboard_group" ] } diff --git a/net/base/net_errors_posix.cc b/net/base/net_errors_posix.cc index df49829735bd..e3145c787b51 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 + 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,12 @@ 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 + } // namespace net diff --git a/net/base/net_errors_starboard.cc b/net/base/net_errors_starboard.cc index 7ed4aa304caa..329ec117d82a 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 + 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 + } // namespace net diff --git a/net/socket/socket_descriptor.cc b/net/socket/socket_descriptor.cc index 4880f0ee1b57..d51d8a5c5e88 100644 --- a/net/socket/socket_descriptor.cc +++ b/net/socket/socket_descriptor.cc @@ -26,7 +26,12 @@ namespace net { SocketDescriptor CreatePlatformSocket(int family, int type, int protocol) { #if defined(STARBOARD) NOTREACHED(); +#if SB_API_VERSION >= 16 + return -1; +#else return kSbSocketInvalid; +#endif + #elif BUILDFLAG(IS_WIN) EnsureWinsockInit(); SocketDescriptor result = ::WSASocket(family, type, protocol, nullptr, 0, diff --git a/net/socket/socket_descriptor.h b/net/socket/socket_descriptor.h index 032cb73d5cb1..e01c6e22bfac 100644 --- a/net/socket/socket_descriptor.h +++ b/net/socket/socket_descriptor.h @@ -18,7 +18,13 @@ namespace net { #if defined(STARBOARD) + +#if SB_API_VERSION >= 16 +typedef int SocketDescriptor; +#else typedef SbSocket SocketDescriptor; +#endif // SB_API_VERSION >= 16 + #elif BUILDFLAG(IS_WIN) typedef UINT_PTR SocketDescriptor; const SocketDescriptor kInvalidSocket = (SocketDescriptor)(~0); diff --git a/net/socket/socket_options.cc b/net/socket/socket_options.cc index 7f23a600a2da..818aca3a3523 100644 --- a/net/socket/socket_options.cc +++ b/net/socket/socket_options.cc @@ -11,6 +11,9 @@ #if defined(STARBOARD) #include "base/notreached.h" +#include +#include +#include #elif BUILDFLAG(IS_WIN) #include #include @@ -24,8 +27,18 @@ namespace net { int SetTCPNoDelay(SocketDescriptor fd, bool no_delay) { #if defined(STARBOARD) + +#if SB_API_VERSION >= 16 + int on = no_delay ? 1 : 0; + int rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&on), sizeof(on)); + return rv == -1 ? MapSystemError(errno) : OK; +#else return SbSocketSetTcpNoDelay(fd, no_delay) ? OK : ERR_FAILED; +#endif // SB_API_VERSION >= 16 + #else + #if BUILDFLAG(IS_WIN) BOOL on = no_delay ? TRUE : FALSE; #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) @@ -39,7 +52,17 @@ int SetTCPNoDelay(SocketDescriptor fd, bool no_delay) { int SetReuseAddr(SocketDescriptor fd, bool reuse) { #if defined(STARBOARD) + +#if SB_API_VERSION >= 16 + int boolean_value = reuse ? 1 : 0; + int rv = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&boolean_value), + sizeof(boolean_value)); + return rv == -1 ? MapSystemError(errno) : OK; +#else return SbSocketSetReuseAddress(fd, reuse) ? OK : ERR_FAILED; +#endif // SB_API_VERSION >= 16 + #else // SO_REUSEADDR is useful for server sockets to bind to a recently unbound // port. When a socket is closed, the end point changes its state to TIME_WAIT @@ -68,7 +91,19 @@ int SetReuseAddr(SocketDescriptor fd, bool reuse) { int SetSocketReceiveBufferSize(SocketDescriptor fd, int32_t size) { #if defined(STARBOARD) + +#if SB_API_VERSION >= 16 + int rv = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, + reinterpret_cast(&size), sizeof(size)); + int net_error = (rv == -1) ? MapSystemError(errno) : OK; + if (net_error != OK) { + DLOG(ERROR) << "Could not set socket receive buffer size: " << net_error; + } + return net_error; +#else return SbSocketSetReceiveBufferSize(fd, size) ? OK : ERR_FAILED; +#endif // SB_API_VERSION >= 16 + #else int rv = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&size), sizeof(size)); @@ -87,7 +122,19 @@ int SetSocketReceiveBufferSize(SocketDescriptor fd, int32_t size) { int SetSocketSendBufferSize(SocketDescriptor fd, int32_t size) { #if defined(STARBOARD) + +#if SB_API_VERSION >= 16 + int rv = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, + reinterpret_cast(&size), sizeof(size)); + int net_error = (rv == -1) ? MapSystemError(errno) : OK; + if (net_error != OK) { + DLOG(ERROR) << "Could not set socket send buffer size: " << net_error; + } + return net_error; +#else return SbSocketSetSendBufferSize(fd, size) ? OK : ERR_FAILED; +#endif // SB_API_VERSION >= 16 + #else int rv = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&size), sizeof(size)); diff --git a/net/socket/tcp_socket_starboard.cc b/net/socket/tcp_socket_starboard.cc index e87f81520d6a..f7d666a9f23b 100644 --- a/net/socket/tcp_socket_starboard.cc +++ b/net/socket/tcp_socket_starboard.cc @@ -17,6 +17,13 @@ #include #include +#if SB_API_VERSION >= 16 +#include +#include +#include +#include +#endif + #include "base/functional/callback_helpers.h" #include "base/message_loop/message_pump_for_io.h" #include "base/task/current_thread.h" @@ -33,7 +40,11 @@ TCPSocketStarboard::TCPSocketStarboard( NetLog* net_log, const NetLogSource& source) : socket_performance_watcher_(std::move(socket_performance_watcher)), +#if SB_API_VERSION >= 16 + socket_(-1), +#else socket_(kSbSocketInvalid), +#endif socket_watcher_(FROM_HERE), family_(ADDRESS_FAMILY_UNSPECIFIED), logging_multiple_connect_attempts_(false), @@ -50,11 +61,50 @@ TCPSocketStarboard::~TCPSocketStarboard() { int TCPSocketStarboard::Open(AddressFamily family) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + + DCHECK(socket_ < 0); + + int socket_family; + switch(family) { + case ADDRESS_FAMILY_IPV4: + socket_family = AF_INET; + break; + case ADDRESS_FAMILY_IPV6: + socket_family = AF_INET6; + break; + case ADDRESS_FAMILY_UNSPECIFIED: + default: + socket_family = AF_UNSPEC; + break; + } + + socket_ = socket(socket_family, SOCK_STREAM, IPPROTO_TCP); + if (socket_ < 0) { + return errno; + } + + // All Starboard sockets are non-blocking, so let's ensure it. + + int flags = fcntl(socket_, F_GETFL, 0); + if(fcntl(socket_, F_SETFL, flags | O_NONBLOCK) < 0){ + close(socket_); + return -1; + } +#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE) + // Use SO_NOSIGPIPE to mute SIGPIPE on darwin systems. + int optval_set = 1; + setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, + reinterpret_cast(&optval_set), sizeof(int)); +#endif + +#else DCHECK(!SbSocketIsValid(socket_)); socket_ = SbSocketCreate(ConvertAddressFamily(family), kSbSocketProtocolTcp); if (!SbSocketIsValid(socket_)) { return MapLastSystemError(); } +#endif family_ = family; return OK; @@ -63,7 +113,11 @@ int TCPSocketStarboard::Open(AddressFamily family) { int TCPSocketStarboard::AdoptConnectedSocket(SocketDescriptor socket, const IPEndPoint& peer_address) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ < 0); +#else DCHECK(!SbSocketIsValid(socket_)); +#endif SbSocketAddress storage; if (!peer_address.ToSbSocketAddress(&storage) && @@ -78,7 +132,11 @@ int TCPSocketStarboard::AdoptConnectedSocket(SocketDescriptor socket, int TCPSocketStarboard::AdoptUnconnectedSocket(SocketDescriptor socket) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ < 0); +#else DCHECK(!SbSocketIsValid(socket_)); +#endif socket_ = socket; return OK; @@ -86,7 +144,32 @@ int TCPSocketStarboard::AdoptUnconnectedSocket(SocketDescriptor socket) { int TCPSocketStarboard::Bind(const IPEndPoint& address) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + printf(" -- [Bind]\n"); + +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + + // Must have already called Open() on this socket with the same address + // family as is being passed in here. + DCHECK_EQ(family_, address.GetFamily()); + + struct sockaddr_in6 storage; + socklen_t address_length = sizeof(storage); + if (!address.ToSockAddr(reinterpret_cast(&storage), &address_length)) { + + return ERR_ADDRESS_INVALID; + } + + int error = bind(socket_, reinterpret_cast(&storage), address_length); + + if (error != 0) { + DLOG(ERROR) << "Socket bind() returned an error"; + return errno; + } +#else DCHECK(SbSocketIsValid(socket_)); + // Must have already called Open() on this socket with the same address // family as is being passed in here. DCHECK_EQ(family_, address.GetFamily()); @@ -101,6 +184,7 @@ int TCPSocketStarboard::Bind(const IPEndPoint& address) { DLOG(ERROR) << "SbSocketBind() returned an error"; return MapLastSocketError(socket_); } +#endif // SB_API_VERSION >= 16 local_address_.reset(new IPEndPoint(address)); @@ -110,9 +194,22 @@ int TCPSocketStarboard::Bind(const IPEndPoint& address) { int TCPSocketStarboard::Listen(int backlog) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_GT(backlog, 0); - DCHECK(SbSocketIsValid(socket_)); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); DCHECK(local_address_) << "Must have previously called Bind()."; + printf(" -- [Listen]\n"); + + int error = listen(socket_, backlog); + if (error != 0) { + DLOG(ERROR) << "Socket listen() returned an error"; + int rv = errno; + Close(); + return rv; + } +#else + DCHECK(SbSocketIsValid(socket_)); + DCHECK(local_address_) << "Must have previously called Bind()."; SbSocketError error = SbSocketListen(socket_); if (error != kSbSocketOk) { DLOG(ERROR) << "SbSocketListen() returned an error"; @@ -120,6 +217,7 @@ int TCPSocketStarboard::Listen(int backlog) { Close(); return rv; } +#endif listening_ = true; @@ -134,6 +232,8 @@ int TCPSocketStarboard::Accept(std::unique_ptr* socket, DCHECK(!callback.is_null()); DCHECK(accept_callback_.is_null()); + printf(" -- [Accept]\n"); + net_log_.BeginEvent(NetLogEventType::TCP_ACCEPT); int result = AcceptInternal(socket, address); @@ -143,7 +243,11 @@ int TCPSocketStarboard::Accept(std::unique_ptr* socket, socket_, true, base::MessagePumpIOStarboard::WATCH_READ, &socket_watcher_, this)) { DLOG(ERROR) << "WatchSocket failed on read"; +#if SB_API_VERSION >= 16 + return errno; +#else return MapLastSocketError(socket_); +#endif } accept_socket_ = socket; @@ -155,40 +259,95 @@ int TCPSocketStarboard::Accept(std::unique_ptr* socket, } int TCPSocketStarboard::SetDefaultOptionsForServer() { +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + const int on = 1; + if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) { + return errno; + } +#else DCHECK(SbSocketIsValid(socket_)); if (!SbSocketSetReuseAddress(socket_, true)) { return MapLastSocketError(socket_); } +#endif + return OK; } void TCPSocketStarboard::SetDefaultOptionsForClient() { +#if SB_API_VERSION >= 16 + bool on = true; + // SbSocketSetTcpNoDelay + setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&on), sizeof(on)); +#else SbSocketSetTcpNoDelay(socket_, true); +#endif const int64_t kTCPKeepAliveDurationUsec = 45 * base::Time::kMicrosecondsPerSecond; - SbSocketSetTcpKeepAlive(socket_, true, kTCPKeepAliveDurationUsec); +#if SB_API_VERSION >= 16 + // SbSocketSetTcpKeepAlive + setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); +#if defined(__APPLE__) + // In tvOS, TCP_KEEPIDLE and SOL_TCP are not available. + // For reference: + // https://stackoverflow.com/questions/15860127/how-to-configure-tcp-keepalive-under-mac-os-x + result |= setsockopt(socket_, IPPROTO_TCP, TCP_KEEPALIVE, &kTCPKeepAliveDurationUsec, + sizeof(kTCPKeepAliveDurationUsec)); +#elif !defined(_WIN32) + // In Windows, the SOL_TCP and TCP_KEEPIDLE options are not available. + // For reference: + // https://stackoverflow.com/questions/8176821/how-to-set-the-keep-alive-interval-for-winsock + setsockopt(socket_, SOL_TCP, TCP_KEEPIDLE, &kTCPKeepAliveDurationUsec, + sizeof(kTCPKeepAliveDurationUsec)); + setsockopt(socket_, SOL_TCP, TCP_KEEPINTVL, &kTCPKeepAliveDurationUsec, + sizeof(kTCPKeepAliveDurationUsec)); +#endif + // SbSocketSetTcpWindowScaling - This API is not supported in standard POSIX. + + // SbSocketSetReceiveBufferSize + if (kSbNetworkReceiveBufferSize != 0) { + setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, "SO_RCVBUF", kSbNetworkReceiveBufferSize); + } +#else + SbSocketSetTcpKeepAlive(socket_, true, kTCPKeepAliveDurationUsec); SbSocketSetTcpWindowScaling(socket_, true); - if (kSbNetworkReceiveBufferSize != 0) { SbSocketSetReceiveBufferSize(socket_, kSbNetworkReceiveBufferSize); } +#endif // SB_API_VERSION >= 16 + } int TCPSocketStarboard::AcceptInternal( std::unique_ptr* socket, IPEndPoint* address) { + +#if SB_API_VERSION >= 16 + int new_socket = accept(socket_, nullptr, nullptr); + if (new_socket < 0) { + int net_error = errno; +#else SbSocket new_socket = SbSocketAccept(socket_); if (!SbSocketIsValid(new_socket)) { int net_error = MapLastSocketError(socket_); +#endif // SB_API_VERSION >= 16 + if (net_error != ERR_IO_PENDING) { net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT, net_error); } return net_error; } - SbSocketAddress sb_address; char unused_byte; +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr; + socklen_t length = sizeof(saddr); + int result = getpeername(new_socket, reinterpret_cast(&saddr), &length); +#else + SbSocketAddress sb_address; // We use ReceiveFrom to get peer address of the newly connected socket. int received = SbSocketReceiveFrom(new_socket, &unused_byte, 0, &sb_address); if (received != 0) { @@ -207,10 +366,17 @@ int TCPSocketStarboard::AcceptInternal( DVLOG(1) << "Could not get peer address for the server socket."; } } +#endif // SB_API_VERSION >= 16 + IPEndPoint ip_end_point; +#if SB_API_VERSION >= 16 + if (!ip_end_point.FromSockAddr(reinterpret_cast(&saddr), length)) { + close(new_socket); +#else if (!ip_end_point.FromSbSocketAddress(&sb_address)) { SbSocketDestroy(new_socket); +#endif // SB_API_VERSION >= 16 int net_error = ERR_ADDRESS_INVALID; net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT, net_error); return net_error; @@ -220,9 +386,15 @@ int TCPSocketStarboard::AcceptInternal( new TCPSocketStarboard(nullptr, net_log_.net_log(), net_log_.source())); int adopt_result = tcp_socket->AdoptConnectedSocket(new_socket, ip_end_point); if (adopt_result != OK) { +#if SB_API_VERSION >= 16 + if (!close(new_socket)) { + DPLOG(ERROR) << "Socket close()"; + } +#else if (!SbSocketDestroy(new_socket)) { DPLOG(ERROR) << "SbSocketDestroy"; } +#endif net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT, adopt_result); return adopt_result; @@ -237,6 +409,19 @@ int TCPSocketStarboard::AcceptInternal( void TCPSocketStarboard::Close() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + printf(" -- [Close]\n"); + +#if SB_API_VERSION >= 16 + if (socket_ >= 0) { + StopWatchingAndCleanUp(); + net_log_.AddEvent(NetLogEventType::SOCKET_CLOSED); + + if (!close(socket_)) { + DPLOG(ERROR) << "Socket close()"; + } + socket_ = -1; + } +#else if (SbSocketIsValid(socket_)) { StopWatchingAndCleanUp(); @@ -247,6 +432,7 @@ void TCPSocketStarboard::Close() { } socket_ = kSbSocketInvalid; } +#endif listening_ = false; } @@ -279,7 +465,11 @@ void TCPSocketStarboard::StopWatchingAndCleanUp() { peer_address_.reset(); } +#if SB_API_VERSION >= 16 +void TCPSocketStarboard::OnSocketReadyToRead(int socket) { +#else void TCPSocketStarboard::OnSocketReadyToRead(SbSocket socket) { +#endif DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (accept_pending()) { @@ -295,7 +485,11 @@ void TCPSocketStarboard::OnSocketReadyToRead(SbSocket socket) { } } +#if SB_API_VERSION >= 16 +void TCPSocketStarboard::OnSocketReadyToWrite(int socket) { +#else void TCPSocketStarboard::OnSocketReadyToWrite(SbSocket socket) { +#endif DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (listening_) { @@ -312,8 +506,14 @@ void TCPSocketStarboard::OnSocketReadyToWrite(SbSocket socket) { int TCPSocketStarboard::Connect(const IPEndPoint& address, CompletionOnceCallback callback) { + + printf(" -- [Connect]\n"); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(!peer_address_); DCHECK(!connect_pending()); @@ -324,6 +524,25 @@ int TCPSocketStarboard::Connect(const IPEndPoint& address, net_log_.BeginEvent(NetLogEventType::TCP_CONNECT_ATTEMPT, [&] { return CreateNetLogIPEndPointParams(&address); }); +#if SB_API_VERSION >= 16 + struct sockaddr_in6 storage; + socklen_t length = sizeof(storage); + if (!address.ToSockAddr(reinterpret_cast(&storage), &length)) { + printf(" -- [Connect] ToSockAddr\n"); + return ERR_ADDRESS_INVALID; + } + + peer_address_.reset(new IPEndPoint(address)); + int result = connect(socket_, reinterpret_cast(&storage), length); + int rv = 0; + if (result != 0 && errno == EINPROGRESS) { + rv = kSbSocketPending; + } else if (result != 0) { + rv = kSbSocketErrorFailed; + } else { + rv = kSbSocketOk; + } +#else SbSocketAddress storage; if (!address.ToSbSocketAddress(&storage)) { return ERR_ADDRESS_INVALID; @@ -334,6 +553,8 @@ int TCPSocketStarboard::Connect(const IPEndPoint& address, SbSocketError result = SbSocketConnect(socket_, &storage); int rv = MapLastSocketError(socket_); +#endif + if (rv != ERR_IO_PENDING) { return HandleConnectCompleted(rv); } @@ -367,7 +588,22 @@ int TCPSocketStarboard::HandleConnectCompleted(int rv) { void TCPSocketStarboard::DidCompleteConnect() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + int rv = false; + if (socket_ < 0) { + rv = false; + } else { + char c; + int result = recv(socket_, &c, 1, MSG_PEEK); + if (result <= 0) { + rv = false; + }else { + rv = errno == EAGAIN || errno == EWOULDBLOCK; + } + } +#else int rv = SbSocketIsConnected(socket_) ? OK : ERR_FAILED; +#endif waiting_connect_ = false; CompletionOnceCallback callback = std::move(write_callback_); @@ -388,14 +624,25 @@ void TCPSocketStarboard::StartLoggingMultipleConnectAttempts( bool TCPSocketStarboard::IsConnected() const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - +#if SB_API_VERSION >= 16 + return socket_ >= 0; +#else return SbSocketIsConnected(socket_); +#endif } bool TCPSocketStarboard::IsConnectedAndIdle() const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - +#if SB_API_VERSION >= 16 + if (socket_ < 0) + return false; // not connected + char c; + if (recv(socket_, &c, 1, MSG_PEEK) >= 0) + return false; // not idle + return (errno == EAGAIN || errno == EWOULDBLOCK); +#else return SbSocketIsConnectedAndIdle(socket_); +#endif } void TCPSocketStarboard::EndLoggingMultipleConnectAttempts(int net_error) { @@ -425,7 +672,11 @@ int TCPSocketStarboard::Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(!connect_pending()); DCHECK_GT(buf_len, 0); @@ -448,7 +699,11 @@ int TCPSocketStarboard::ReadIfReady(IOBuffer* buf, int buf_len, CompletionOnceCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(read_if_ready_callback_.is_null()); int rv = DoRead(buf, buf_len); @@ -493,7 +748,12 @@ void TCPSocketStarboard::RetryRead(int rv) { } int TCPSocketStarboard::DoRead(IOBuffer* buf, int buf_len) { +#if SB_API_VERSION >= 16 + const int kRecvFlag = 0; + int bytes_read = recv(socket_, buf->data(), buf_len, kRecvFlag); +#else int bytes_read = SbSocketReceiveFrom(socket_, buf->data(), buf_len, NULL); +#endif if (bytes_read >= 0) { net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, @@ -503,6 +763,12 @@ int TCPSocketStarboard::DoRead(IOBuffer* buf, int buf_len) { return bytes_read; } else { // If |bytes_read| < 0, some kind of error occurred. +#if SB_API_VERSION >= 16 + int rv = errno; + if (rv != 0) { + DLOG(ERROR) << __FUNCTION__ << "[" << this << "]: Error: " << rv; + } +#else SbSocketError starboard_error = SbSocketGetLastError(socket_); int rv = MapSocketError(starboard_error); if (rv != ERR_IO_PENDING) { @@ -510,6 +776,8 @@ int TCPSocketStarboard::DoRead(IOBuffer* buf, int buf_len) { starboard_error); DLOG(ERROR) << __FUNCTION__ << "[" << this << "]: Error: " << rv; } +#endif + return rv; } } @@ -530,7 +798,11 @@ int TCPSocketStarboard::Write( CompletionOnceCallback callback, const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(!connect_pending()); DCHECK(!write_pending()); DCHECK_GT(buf_len, 0); @@ -551,7 +823,16 @@ int TCPSocketStarboard::Write( } int TCPSocketStarboard::DoWrite(IOBuffer* buf, int buf_len) { +#if SB_API_VERSION >= 16 +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif + int bytes_sent = send(socket_, buf->data(), buf_len, kSendFlags); +#else int bytes_sent = SbSocketSendTo(socket_, buf->data(), buf_len, NULL); +#endif if (bytes_sent >= 0) { net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, @@ -559,10 +840,14 @@ int TCPSocketStarboard::DoWrite(IOBuffer* buf, int buf_len) { return bytes_sent; } else { +#if SB_API_VERSION >= 16 + int rv = errno; +#else SbSocketError starboard_error = SbSocketGetLastError(socket_); int rv = MapSocketError(starboard_error); NetLogSocketError(net_log_, NetLogEventType::SOCKET_WRITE_ERROR, rv, starboard_error); +#endif if (rv != ERR_IO_PENDING) { DLOG(ERROR) << __FUNCTION__ << "[" << this << "]: Error: " << rv; } @@ -599,7 +884,34 @@ bool TCPSocketStarboard::SetSendBufferSize(int32_t size) { bool TCPSocketStarboard::SetKeepAlive(bool enable, int delay) { int delay_second = delay * base::Time::kMicrosecondsPerSecond; + +#if SB_API_VERSION >= 16 + int on = enable? 1:0; + int result = 0; + result |= setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); + +#if defined(__APPLE__) + // In tvOS, TCP_KEEPIDLE and SOL_TCP are not available. + // For reference: + // https://stackoverflow.com/questions/15860127/how-to-configure-tcp-keepalive-under-mac-os-x + result |= setsockopt(socket_, IPPROTO_TCP, TCP_KEEPALIVE, &delay_second, + sizeof(delay_second)); +#elif !defined(_WIN32) + // In Windows, the SOL_TCP and TCP_KEEPIDLE options are not available. + // For reference: + // https://stackoverflow.com/questions/8176821/how-to-set-the-keep-alive-interval-for-winsock + result |= setsockopt(socket_, SOL_TCP, TCP_KEEPIDLE, &delay_second, + sizeof(delay_second)); + + result |= setsockopt(socket_, SOL_TCP, TCP_KEEPINTVL, &delay_second, + sizeof(delay_second)); +#endif + + + return result == 0; +#else return SbSocketSetTcpKeepAlive(socket_, enable, delay_second); +#endif } bool TCPSocketStarboard::SetNoDelay(bool no_delay) { @@ -620,16 +932,30 @@ bool TCPSocketStarboard::GetEstimatedRoundTripTime( int TCPSocketStarboard::GetLocalAddress(IPEndPoint* address) const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(address); + printf(" -- [GetLocalAddress]\n"); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + struct sockaddr_in6 saddr = {0}; + socklen_t socklen = sizeof(saddr); + int result = getsockname(socket_, reinterpret_cast(&saddr), &socklen); + if (0 != result){ + return errno; + } + if (!address->FromSockAddr(reinterpret_cast(&saddr), socklen)) { + return ERR_ADDRESS_INVALID; + } +#else + DCHECK(SbSocketIsValid(socket_)); SbSocketAddress sb_address; if (!SbSocketGetLocalAddress(socket_, &sb_address)) { SbSocketError starboard_error = SbSocketGetLastError(socket_); return MapSocketError(starboard_error); } - if (!address->FromSbSocketAddress(&sb_address)) { return ERR_ADDRESS_INVALID; } +#endif return OK; } @@ -649,7 +975,11 @@ void TCPSocketStarboard::DetachFromThread() { SocketDescriptor TCPSocketStarboard::ReleaseSocketDescriptorForTesting() { SocketDescriptor socket_descriptor = socket_; +#if SB_API_VERSION >= 16 + socket_ = -1; +#else socket_ = kSbSocketInvalid; +#endif Close(); return socket_descriptor; } @@ -659,8 +989,14 @@ SocketDescriptor TCPSocketStarboard::SocketDescriptorForTesting() const { } void TCPSocketStarboard::ApplySocketTag(const SocketTag& tag) { - if (SbSocketIsValid(socket_) && tag != tag_) { - tag.Apply(socket_); +#if SB_API_VERSION >= 16 + if (socket_ >= 0) { +#else + if (SbSocketIsValid(socket_)) { +#endif + if (tag != tag_) { + tag.Apply(socket_); + } } tag_ = tag; } diff --git a/net/socket/tcp_socket_starboard.h b/net/socket/tcp_socket_starboard.h index 876dac02d8a5..a30bdf8bd194 100644 --- a/net/socket/tcp_socket_starboard.h +++ b/net/socket/tcp_socket_starboard.h @@ -96,7 +96,13 @@ class NET_EXPORT TCPSocketStarboard : public base::MessagePumpIOStarboard::Watch // NOOP since TCP FastOpen is not implemented in Windows. void EnableTCPFastOpenIfSupported() {} - bool IsValid() const { return SbSocketIsValid(socket_); } + bool IsValid() const { +#if SB_API_VERSION >= 16 + return socket_ >= 0; +#else + return SbSocketIsValid(socket_); +#endif + } // Detachs from the current thread, to allow the socket to be transferred to // a new thread. Should only be called when the object is no longer used by @@ -138,8 +144,13 @@ class NET_EXPORT TCPSocketStarboard : public base::MessagePumpIOStarboard::Watch int BindToNetwork(handles::NetworkHandle network); // MessagePumpIOStarboard::Watcher implementation. +#if SB_API_VERSION >= 16 + void OnSocketReadyToRead(int socket) override; + void OnSocketReadyToWrite(int socket) override; +#else void OnSocketReadyToRead(SbSocket socket) override; void OnSocketReadyToWrite(SbSocket socket) override; +#endif private: void RetryRead(int rv); @@ -169,7 +180,11 @@ class NET_EXPORT TCPSocketStarboard : public base::MessagePumpIOStarboard::Watch std::unique_ptr socket_performance_watcher_; +#if SB_API_VERSION >= 16 + int socket_; +#else SbSocket socket_; +#endif base::MessagePumpIOStarboard::SocketWatcher socket_watcher_; diff --git a/net/socket/udp_socket_starboard.cc b/net/socket/udp_socket_starboard.cc index 7e51b873276a..5fa8beecebcc 100644 --- a/net/socket/udp_socket_starboard.cc +++ b/net/socket/udp_socket_starboard.cc @@ -16,6 +16,11 @@ #include "net/socket/udp_socket_starboard.h" +#include +#include +#include +#include + #include "base/logging.h" #include "base/rand_util.h" #include "base/task/current_thread.h" @@ -40,7 +45,11 @@ UDPSocketStarboard::UDPSocketStarboard(DatagramSocket::BindType bind_type, const net::NetLogSource& source) : write_async_watcher_(std::make_unique(this)), sender_(new UDPSocketStarboardSender()), +#if SB_API_VERSION >= 16 + socket_(-1), +#else socket_(kSbSocketInvalid), +#endif socket_options_(0), bind_type_(bind_type), socket_watcher_(FROM_HERE), @@ -61,14 +70,52 @@ UDPSocketStarboard::~UDPSocketStarboard() { int UDPSocketStarboard::Open(AddressFamily address_family) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ < 0); +#else DCHECK(!SbSocketIsValid(socket_)); +#endif auto owned_socket_count = TryAcquireGlobalUDPSocketCount(); if (owned_socket_count.empty()) return ERR_INSUFFICIENT_RESOURCES; owned_socket_count_ = std::move(owned_socket_count); +#if SB_API_VERSION >= 16 + int socket_family; + switch(address_family) { + case ADDRESS_FAMILY_IPV4: + socket_family = AF_INET; + break; + case ADDRESS_FAMILY_IPV6: + socket_family = AF_INET6; + break; + case ADDRESS_FAMILY_UNSPECIFIED: + default: + socket_family = AF_UNSPEC; + break; + } + + socket_ = socket(socket_family, SOCK_DGRAM, IPPROTO_UDP); + if (socket_ < 0) { + return errno; + } + // All Starboard sockets are non-blocking, so let's ensure it. + int result = -1; + int flags = fcntl(socket_, F_GETFL, 0); + if(fcntl(socket_, F_SETFL, flags | O_NONBLOCK) < 0){ + close(socket_); + return -1; + } +#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE) + // Use SO_NOSIGPIPE to mute SIGPIPE on darwin systems. + int optval_set = 1; + setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, + reinterpret_cast(&optval_set), sizeof(int)); +#endif + +#else address_type_ = (address_family == ADDRESS_FAMILY_IPV6 ? kSbSocketAddressTypeIpv6 : kSbSocketAddressTypeIpv4); @@ -77,14 +124,23 @@ int UDPSocketStarboard::Open(AddressFamily address_family) { owned_socket_count_.Reset(); return MapSystemError(SbSystemGetLastError()); } +#endif // SB_API_VERSION >= 16 return OK; } + +#if SB_API_VERSION >= 16 +int UDPSocketStarboard::AdoptOpenedSocket(AddressFamily address_family, + const int socket) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(socket_, -1); +#else int UDPSocketStarboard::AdoptOpenedSocket(AddressFamily address_family, const SbSocket& socket) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_EQ(socket_, kSbSocketInvalid); +#endif auto owned_socket_count = TryAcquireGlobalUDPSocketCount(); if (owned_socket_count.empty()) { return ERR_INSUFFICIENT_RESOURCES; @@ -99,8 +155,11 @@ void UDPSocketStarboard::Close() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); owned_socket_count_.Reset(); - +#if SB_API_VERSION >= 16 + if (socket_ <= -1) +#else if (socket_ == kSbSocketInvalid) +#endif return; // Zero out any pending read/write callback state. @@ -115,13 +174,20 @@ void UDPSocketStarboard::Close() { bool ok = socket_watcher_.StopWatchingSocket(); DCHECK(ok); - is_connected_ = false; + +#if SB_API_VERSION >= 16 + if (close(socket_) != 0) { + DPLOG(ERROR) << "Socket close"; + } + socket_ = -1; +#else if (!SbSocketDestroy(socket_)) { DPLOG(ERROR) << "SbSocketDestroy"; } socket_ = kSbSocketInvalid; +#endif } int UDPSocketStarboard::GetPeerAddress(IPEndPoint* address) const { @@ -142,12 +208,24 @@ int UDPSocketStarboard::GetLocalAddress(IPEndPoint* address) const { return ERR_SOCKET_NOT_CONNECTED; if (!local_address_.get()) { +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr = {0}; + socklen_t length = sizeof(saddr); + if (0 != getsockname(socket_, reinterpret_cast(&saddr), &length)) + return errno; + + std::unique_ptr endpoint(new IPEndPoint()); + if (!endpoint->FromSockAddr(reinterpret_cast(&saddr), length)) + return ERR_FAILED; +#else SbSocketAddress address; if (!SbSocketGetLocalAddress(socket_, &address)) return MapSocketError(SbSocketGetLastError(socket_)); std::unique_ptr endpoint(new IPEndPoint()); if (!endpoint->FromSbSocketAddress(&address)) return ERR_FAILED; +#endif + local_address_.reset(endpoint.release()); net_log_.AddEvent(NetLogEventType::UDP_LOCAL_ADDRESS, [&] { return CreateNetLogUDPConnectParams(*local_address_, @@ -170,7 +248,11 @@ int UDPSocketStarboard::RecvFrom(IOBuffer* buf, IPEndPoint* address, CompletionOnceCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK_NE(-1, socket_); +#else DCHECK_NE(kSbSocketInvalid, socket_); +#endif DCHECK(read_callback_.is_null()); DCHECK(!recv_from_address_); DCHECK(!callback.is_null()); // Synchronous operation not supported @@ -184,6 +266,9 @@ int UDPSocketStarboard::RecvFrom(IOBuffer* buf, socket_, true, base::MessagePumpIOStarboard::WATCH_READ, &socket_watcher_, this)) { PLOG(ERROR) << "WatchSocket failed on read"; +#if SB_API_VERSION >= 16 + int result = errno; +#else Error result = MapLastSocketError(socket_); if (result == ERR_IO_PENDING) { // Watch(...) might call SbSocketWaiterAdd() which does not guarantee @@ -191,6 +276,7 @@ int UDPSocketStarboard::RecvFrom(IOBuffer* buf, // error since watching the socket failed. result = ERR_FAILED; } +#endif LogRead(result, NULL, NULL); return result; } @@ -223,7 +309,11 @@ int UDPSocketStarboard::SendToOrWrite(IOBuffer* buf, const IPEndPoint* address, CompletionOnceCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(write_callback_.is_null()); DCHECK(!callback.is_null()); // Synchronous operation not supported DCHECK_GT(buf_len, 0); @@ -235,9 +325,15 @@ int UDPSocketStarboard::SendToOrWrite(IOBuffer* buf, if (!base::CurrentIOThread::Get()->Watch( socket_, true, base::MessagePumpIOStarboard::WATCH_WRITE, &socket_watcher_, this)) { +#if SB_API_VERSION >= 16 + DVLOG(1) << "Watch failed on write, error " + << errno; + int result = errno; +#else DVLOG(1) << "Watch failed on write, error " << SbSocketGetLastError(socket_); Error result = MapLastSocketError(socket_); +#endif LogWrite(result, NULL, NULL); return result; } @@ -253,7 +349,11 @@ int UDPSocketStarboard::SendToOrWrite(IOBuffer* buf, } int UDPSocketStarboard::Connect(const IPEndPoint& address) { +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif net_log_.BeginEvent(NetLogEventType::UDP_CONNECT, [&] { return CreateNetLogUDPConnectParams(address, handles::kInvalidNetworkHandle); @@ -266,7 +366,11 @@ int UDPSocketStarboard::Connect(const IPEndPoint& address) { int UDPSocketStarboard::InternalConnect(const IPEndPoint& address) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(!is_connected()); DCHECK(!remote_address_.get()); @@ -287,7 +391,11 @@ int UDPSocketStarboard::InternalConnect(const IPEndPoint& address) { int UDPSocketStarboard::Bind(const IPEndPoint& address) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif DCHECK(!is_connected()); int rv = DoBind(address); @@ -305,48 +413,88 @@ int UDPSocketStarboard::BindToNetwork(handles::NetworkHandle network) { int UDPSocketStarboard::SetReceiveBufferSize(int32_t size) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + int result = OK; + +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + if (setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, "SO_RCVBUF", size) != 0) { + result = errno; + } + DCHECK_EQ(result, OK) << "Could not " << __FUNCTION__ << ": "; +#else DCHECK(SbSocketIsValid(socket_)); - int result = OK; if (!SbSocketSetReceiveBufferSize(socket_, size)) { result = MapLastSocketError(socket_); } DCHECK_EQ(result, OK) << "Could not " << __FUNCTION__ << ": " << SbSocketGetLastError(socket_); +#endif + return result; } int UDPSocketStarboard::SetSendBufferSize(int32_t size) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(SbSocketIsValid(socket_)); - int result = OK; - if (!SbSocketSetSendBufferSize(socket_, size)) { +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + if (setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, "SO_SNDBUF", size) != 0) { + result = errno; + } + DCHECK_EQ(result, OK) << "Could not " << __FUNCTION__ << ": "; +#else + DCHECK(SbSocketIsValid(socket_)); + if (!SbSocketSetReceiveBufferSize(socket_, size)) { result = MapLastSocketError(socket_); } DCHECK_EQ(result, OK) << "Could not " << __FUNCTION__ << ": " << SbSocketGetLastError(socket_); +#endif + return result; } int UDPSocketStarboard::AllowAddressReuse() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!is_connected()); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + const int on = 1; + if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) { + return errno; + } + return OK; +#else DCHECK(SbSocketIsValid(socket_)); return SbSocketSetReuseAddress(socket_, true) ? OK : ERR_FAILED; +#endif + } int UDPSocketStarboard::SetBroadcast(bool broadcast) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!is_connected()); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); + int on = broadcast? 1:0; + return setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == 0 ? + OK : ERR_FAILED; +#else DCHECK(SbSocketIsValid(socket_)); return SbSocketSetBroadcast(socket_, broadcast) ? OK : ERR_FAILED; +#endif + } int UDPSocketStarboard::AllowAddressSharingForMulticast() { - DCHECK_NE(socket_, kSbSocketInvalid); +#if SB_API_VERSION >= 16 + DCHECK_NE(-1, socket_); +#else + DCHECK_NE(kSbSocketInvalid, socket_); +#endif DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!is_connected()); @@ -357,6 +505,30 @@ int UDPSocketStarboard::AllowAddressSharingForMulticast() { return OK; } +#if SB_API_VERSION >= 16 +void UDPSocketStarboard::OnSocketReadyToRead(int /*socket*/) { + if (!read_callback_.is_null()) + DidCompleteRead(); +} + +void UDPSocketStarboard::OnSocketReadyToWrite(int socket) { + if (write_async_watcher_->watching()) { + write_async_watcher_->OnSocketReadyToWrite(socket); + return; + } + + if (!write_callback_.is_null()) + DidCompleteWrite(); +} + +void UDPSocketStarboard::WriteAsyncWatcher::OnSocketReadyToWrite( + int /*socket*/) { + DVLOG(1) << __func__ << " queue " << socket_->pending_writes_.size() + << " out of " << socket_->write_async_outstanding_ << " total"; + socket_->StopWatchingSocket(); + socket_->FlushPending(); +} +#else void UDPSocketStarboard::OnSocketReadyToRead(SbSocket /*socket*/) { if (!read_callback_.is_null()) DidCompleteRead(); @@ -379,6 +551,8 @@ void UDPSocketStarboard::WriteAsyncWatcher::OnSocketReadyToWrite( socket_->StopWatchingSocket(); socket_->FlushPending(); } +#endif + void UDPSocketStarboard::DoReadCallback(int rv) { DCHECK_NE(rv, ERR_IO_PENDING); @@ -458,6 +632,35 @@ void UDPSocketStarboard::LogWrite(int result, int UDPSocketStarboard::InternalRecvFrom(IOBuffer* buf, int buf_len, IPEndPoint* address) { +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr = {0}; + socklen_t length = sizeof(saddr); + int bytes_transferred = recvfrom(socket_, buf->data(), buf_len, 0, + reinterpret_cast(&saddr), &length); + + int result; + if (bytes_transferred >= 0) { + result = bytes_transferred; + // Passing in NULL address is allowed. This is only to align with other + // platform's implementation. + if (address && !address->FromSockAddr(reinterpret_cast(&saddr), length)) { + result = ERR_ADDRESS_INVALID; + } else if (bytes_transferred == buf_len) { + result = ERR_MSG_TOO_BIG; + } + } else { + result = errno; + } + + if (result != ERR_IO_PENDING) { + IPEndPoint log_address; + if (result < 0 || !log_address.FromSockAddr(reinterpret_cast(&saddr), length)) { + LogRead(result, buf->data(), NULL); + } else { + LogRead(result, buf->data(), &log_address); + } + } +#else SbSocketAddress sb_address; int bytes_transferred = SbSocketReceiveFrom(socket_, buf->data(), buf_len, &sb_address); @@ -483,13 +686,33 @@ int UDPSocketStarboard::InternalRecvFrom(IOBuffer* buf, LogRead(result, buf->data(), &log_address); } } - +#endif return result; } int UDPSocketStarboard::InternalSendTo(IOBuffer* buf, int buf_len, const IPEndPoint* address) { +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr; + socklen_t length = sizeof(saddr); + + if (!address || !address->ToSockAddr(reinterpret_cast(&saddr), &length)) { + int result = ERR_FAILED; + LogWrite(result, NULL, NULL); + return result; + } +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif + int result = sendto(socket_, buf->data(), buf_len, kSendFlags, + reinterpret_cast(&saddr), length); + + if (result < 0) + result = errno; +#else SbSocketAddress sb_address; if (!address || !address->ToSbSocketAddress(&sb_address)) { int result = ERR_FAILED; @@ -501,6 +724,7 @@ int UDPSocketStarboard::InternalSendTo(IOBuffer* buf, if (result < 0) result = MapLastSocketError(socket_); +#endif if (result != ERR_IO_PENDING) LogWrite(result, buf->data(), address); @@ -509,6 +733,16 @@ int UDPSocketStarboard::InternalSendTo(IOBuffer* buf, } int UDPSocketStarboard::DoBind(const IPEndPoint& address) { +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr; + socklen_t length = sizeof(saddr); + if (!address.ToSockAddr(reinterpret_cast(&saddr), &length)) { + return ERR_UNEXPECTED; + } + + int rv = bind(socket_, reinterpret_cast(&saddr), length); + return rv != 0 ? errno : OK; +#else SbSocketAddress sb_address; if (!address.ToSbSocketAddress(&sb_address)) { return ERR_UNEXPECTED; @@ -516,6 +750,7 @@ int UDPSocketStarboard::DoBind(const IPEndPoint& address) { SbSocketError rv = SbSocketBind(socket_, &sb_address); return rv != kSbSocketOk ? MapSystemError(SbSystemGetLastError()) : OK; +#endif } int UDPSocketStarboard::RandomBind(const IPAddress& address) { @@ -527,6 +762,23 @@ int UDPSocketStarboard::JoinGroup(const IPAddress& group_address) const { if (!is_connected()) return ERR_SOCKET_NOT_CONNECTED; +#if SB_API_VERSION >= 16 + struct sockaddr_in saddr = {0}; + socklen_t length = sizeof(saddr); + if (!IPEndPoint(group_address, 0).ToSockAddr(reinterpret_cast(&saddr), &length)) { + return ERR_ADDRESS_INVALID; + } + struct ip_mreq imreq = {0}; + in_addr_t in_addr = *reinterpret_cast(&saddr.sin_addr); + imreq.imr_multiaddr.s_addr = in_addr; + imreq.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, + sizeof(imreq)) == -1) { + LOG(WARNING) << "!!Socket setsockopt JoinMulticastGroup failed on UDP socket."; + return errno; + } +#else SbSocketAddress sb_address = {0}; if (!IPEndPoint(group_address, 0).ToSbSocketAddress(&sb_address)) { return ERR_ADDRESS_INVALID; @@ -536,6 +788,9 @@ int UDPSocketStarboard::JoinGroup(const IPAddress& group_address) const { LOG(WARNING) << "SbSocketJoinMulticastGroup failed on UDP socket."; return MapLastSocketError(socket_); } +#endif // SB_API_VERSION >= 16 + + return OK; } @@ -599,6 +854,39 @@ SendResult::SendResult(int _rv, int _write_count, DatagramBuffers _buffers) : rv(_rv), write_count(_write_count), buffers(std::move(_buffers)) {} SendResult::SendResult(SendResult&& other) = default; +#if SB_API_VERSION >= 16 +SendResult UDPSocketStarboardSender::InternalSendBuffers( + const int socket, + DatagramBuffers buffers, + struct sockaddr* paddress, + socklen_t len) const { + int rv = 0; + int write_count = 0; +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif + for (auto& buffer : buffers) { + int result = sendto(socket, buffer->data(), buffer->length(), kSendFlags, + paddress, len); + if (result < 0) { + + rv = errno; + break; + } + write_count++; + } + return SendResult(rv, write_count, std::move(buffers)); +} + +SendResult UDPSocketStarboardSender::SendBuffers(const int socket, + DatagramBuffers buffers, + struct sockaddr* paddress, + socklen_t len) { + return InternalSendBuffers(socket, std::move(buffers), paddress, len); +} +#else SendResult UDPSocketStarboardSender::InternalSendBuffers( const SbSocket& socket, DatagramBuffers buffers, @@ -621,13 +909,29 @@ SendResult UDPSocketStarboardSender::SendBuffers(const SbSocket& socket, SbSocketAddress address) { return InternalSendBuffers(socket, std::move(buffers), address); } +#endif +#if SB_API_VERSION >= 16 +int UDPSocketStarboardSender::Send(const int socket, + const char* buf, + size_t len, + struct sockaddr* paddress, + socklen_t length) const { +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif + return sendto(socket, buf, len, kSendFlags, paddress, length); +} +#else int UDPSocketStarboardSender::Send(const SbSocket& socket, const char* buf, size_t len, SbSocketAddress address) const { return SbSocketSendTo(socket, buf, len, &address); } +#endif // SB_API_VERSION >= 16 int UDPSocketStarboard::WriteAsync( const char* buffer, @@ -747,22 +1051,44 @@ void UDPSocketStarboard::OnWriteAsyncTimerFired() { void UDPSocketStarboard::LocalSendBuffers() { DVLOG(1) << __func__ << " queue " << pending_writes_.size() << " out of " << write_async_outstanding_ << " total"; +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr = {0}; + socklen_t length = sizeof(saddr); + int result = remote_address_.get()->ToSockAddr(reinterpret_cast(&saddr), &length); +#else SbSocketAddress sb_address; int result = remote_address_.get()->ToSbSocketAddress(&sb_address); +#endif DCHECK(result); DidSendBuffers( - sender_->SendBuffers(socket_, std::move(pending_writes_), sb_address)); + sender_->SendBuffers(socket_, std::move(pending_writes_), +#if SB_API_VERSION >= 16 + reinterpret_cast(&saddr), length)); +#else + sb_address)); +#endif } void UDPSocketStarboard::PostSendBuffers() { DVLOG(1) << __func__ << " queue " << pending_writes_.size() << " out of " << write_async_outstanding_ << " total"; +#if SB_API_VERSION >= 16 + struct sockaddr_in6 saddr; + socklen_t length = sizeof(saddr); + DCHECK(remote_address_.get()->ToSockAddr(reinterpret_cast(&saddr), &length)); +#else SbSocketAddress sb_address; DCHECK(remote_address_.get()->ToSbSocketAddress(&sb_address)); +#endif task_runner_->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&UDPSocketStarboardSender::SendBuffers, sender_, socket_, - std::move(pending_writes_), sb_address), + std::move(pending_writes_), +#if SB_API_VERSION >= 16 + reinterpret_cast(&saddr), length), +#else + sb_address), +#endif base::BindOnce(&UDPSocketStarboard::DidSendBuffers, weak_factory_.GetWeakPtr())); } @@ -812,7 +1138,11 @@ void UDPSocketStarboard::DidSendBuffers(SendResult send_result) { if (last_async_result_ == ERR_IO_PENDING) { DVLOG(2) << __func__ << " WatchSocket start"; if (!WatchSocket()) { +#if SB_API_VERSION >= 16 + last_async_result_ = errno; +#else last_async_result_ = MapLastSocketError(socket_); +#endif DVLOG(1) << "WatchSocket failed on write, error: " << last_async_result_; LogWrite(last_async_result_, NULL, NULL); } else { @@ -842,7 +1172,11 @@ void UDPSocketStarboard::DidSendBuffers(SendResult send_result) { int UDPSocketStarboard::SetDoNotFragment() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif // Starboard does not supported sending non-fragmented packets yet. // All QUIC Streams call this function at initialization, setting sockets to diff --git a/net/socket/udp_socket_starboard.h b/net/socket/udp_socket_starboard.h index 905964eccc67..ca6c09f59d56 100644 --- a/net/socket/udp_socket_starboard.h +++ b/net/socket/udp_socket_starboard.h @@ -79,14 +79,34 @@ class NET_EXPORT UDPSocketStarboardSender public: explicit UDPSocketStarboardSender(); +#if SB_API_VERSION >= 16 + SendResult SendBuffers(const int socket, + DatagramBuffers buffers, + struct sockaddr* paddress, + socklen_t len); +#else SendResult SendBuffers(const SbSocket& socket, DatagramBuffers buffers, SbSocketAddress address); +#endif protected: friend class base::RefCountedThreadSafe; virtual ~UDPSocketStarboardSender(); + +#if SB_API_VERSION >= 16 + virtual int Send(const int socket, + const char* buf, + size_t len, + struct sockaddr* paddress, + socklen_t length) const; + + SendResult InternalSendBuffers(const int socket, + DatagramBuffers buffers, + struct sockaddr* paddress, + socklen_t len) const; +#else virtual int Send(const SbSocket& socket, const char* buf, size_t len, @@ -95,6 +115,7 @@ class NET_EXPORT UDPSocketStarboardSender SendResult InternalSendBuffers(const SbSocket& socket, DatagramBuffers buffers, SbSocketAddress address) const; +#endif // SB_API_VERSION >= 16 private: UDPSocketStarboardSender(const UDPSocketStarboardSender&) = delete; @@ -317,14 +338,22 @@ class NET_EXPORT UDPSocketStarboard // Enables experimental optimization. This method should be called // before the socket is used to read data for the first time. void enable_experimental_recv_optimization() { +#if SB_API_VERSION >= 16 + DCHECK(socket_ >= 0); +#else DCHECK(SbSocketIsValid(socket_)); +#endif experimental_recv_optimization_enabled_ = true; }; // Takes ownership of `socket`, which should be a socket descriptor opened // with the specified address family. The socket should only be created but // not bound or connected to an address. +#if SB_API_VERSION >= 16 + int AdoptOpenedSocket(AddressFamily address_family, const int socket); +#else int AdoptOpenedSocket(AddressFamily address_family, const SbSocket& socket); +#endif protected: // Watcher for WriteAsync paths. @@ -334,9 +363,13 @@ class NET_EXPORT UDPSocketStarboard : socket_(socket), watching_(false) {} // MessagePumpIOStarboard::Watcher methods - +#if SB_API_VERSION >= 16 + void OnSocketReadyToRead(int socket){}; + void OnSocketReadyToWrite(int socket); +#else void OnSocketReadyToRead(SbSocket socket){}; void OnSocketReadyToWrite(SbSocket socket); +#endif void set_watching(bool watching) { watching_ = watching; } @@ -372,8 +405,13 @@ class NET_EXPORT UDPSocketStarboard private: // MessagePumpIOStarboard::Watcher implementation. +#if SB_API_VERSION >= 16 + void OnSocketReadyToRead(int socket) override; + void OnSocketReadyToWrite(int socket) override; +#else void OnSocketReadyToRead(SbSocket socket) override; void OnSocketReadyToWrite(SbSocket socket) override; +#endif int InternalWriteAsync(CompletionOnceCallback callback, const NetworkTrafficAnnotationTag& traffic_annotation); @@ -419,7 +457,12 @@ class NET_EXPORT UDPSocketStarboard int ResetLastAsyncResult(); int ResetWrittenBytes(); +#if SB_API_VERSION >= 16 + int socket_; +#else SbSocket socket_; +#endif + bool is_connected_ = false; SbSocketAddressType address_type_; diff --git a/starboard/common/socket.cc b/starboard/common/socket.cc index 0e4c056c8fab..1a0c2e42d8a2 100644 --- a/starboard/common/socket.cc +++ b/starboard/common/socket.cc @@ -12,12 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/common/socket.h" - +#include "sys/socket.h" +#undef socket +#include +#include #include - +#include +#include "netinet/in.h" +#include "netinet/tcp.h" #include "starboard/common/log.h" +#include "starboard/common/socket.h" #include "starboard/configuration.h" +#include "starboard/socket.h" namespace starboard { @@ -51,121 +57,503 @@ bool GetLocalhostAddress(SbSocketAddressType address_type, return true; } -Socket::Socket(SbSocketAddressType address_type, SbSocketProtocol protocol) - : socket_(SbSocketCreate(address_type, protocol)) {} +Socket::Socket(SbSocketAddressType address_type, SbSocketProtocol protocol) { +#if SB_API_VERSION >= 16 + int family, type, proto; + if (address_type == kSbSocketAddressTypeIpv4) { + family = AF_INET; + } else { + family = AF_INET6; + } + if (protocol == kSbSocketProtocolTcp) { + type = SOCK_STREAM; + proto = IPPROTO_TCP; + } else { + type = SOCK_DGRAM; + proto = IPPROTO_UDP; + } + socket_ = ::socket(family, type, proto); +#else + socket_ = SbSocketCreate(address_type, protocol); +#endif // SB_API_VERSION >= 16 +} -Socket::Socket(SbSocketAddressType address_type) - : socket_(SbSocketCreate(address_type, kSbSocketProtocolTcp)) {} +Socket::Socket(SbSocketAddressType address_type) { +#if SB_API_VERSION >= 16 + int family, type, proto; + if (address_type == kSbSocketAddressTypeIpv4) { + family = AF_INET; + } else { + family = AF_INET6; + } + type = SOCK_STREAM; + proto = IPPROTO_TCP; -Socket::Socket(SbSocketProtocol protocol) - : socket_(SbSocketCreate(kSbSocketAddressTypeIpv4, protocol)) {} + socket_ = ::socket(family, type, proto); +#else + socket_ = SbSocketCreate(address_type, kSbSocketProtocolTcp); +#endif // SB_API_VERSION >= 16 +} -Socket::Socket() - : socket_(SbSocketCreate(kSbSocketAddressTypeIpv4, kSbSocketProtocolTcp)) {} +Socket::Socket(SbSocketProtocol protocol) { +#if SB_API_VERSION >= 16 + int family, type, proto; + family = AF_INET; + if (protocol == kSbSocketProtocolTcp) { + type = SOCK_STREAM; + proto = IPPROTO_TCP; + } else { + type = SOCK_DGRAM; + proto = IPPROTO_UDP; + } + socket_ = ::socket(family, type, proto); +#else + socket_ = SbSocketCreate(kSbSocketAddressTypeIpv4, protocol); +#endif // SB_API_VERSION >= 16 +} + +Socket::Socket() { +#if SB_API_VERSION >= 16 + int family, type, proto; + family = AF_INET; + type = SOCK_STREAM; + proto = IPPROTO_TCP; + + socket_ = ::socket(family, type, proto); +#else + socket_ = SbSocketCreate(kSbSocketAddressTypeIpv4, kSbSocketProtocolTcp); +#endif // SB_API_VERSION >= 16 +} Socket::~Socket() { +#if SB_API_VERSION >= 16 + ::close(socket_); +#else SbSocketDestroy(socket_); +#endif // SB_API_VERSION >= 16 } bool Socket::IsValid() { +#if SB_API_VERSION >= 16 + return socket_ >= 0; +#else return SbSocketIsValid(socket_); +#endif // SB_API_VERSION >= 16 } SbSocketError Socket::Connect(const SbSocketAddress* address) { +#if SB_API_VERSION >= 16 + // Convert SbSocketAddress tp POSIX sockaddr format + if (address == nullptr) { + return kSbSocketErrorFailed; + } + // sizeof(sockaddr_in6) = 28 + char saddr[28] = {0}; + socklen_t length; + +#if SB_HAS(IPV6) + if (address->type == kSbSocketAddressTypeIpv6) { + struct sockaddr_in6* saddr_in6 = + reinterpret_cast(&saddr); + length = sizeof(struct sockaddr_in6); + saddr_in6->sin6_family = AF_INET6; + saddr_in6->sin6_port = htons(address->port); + memcpy(&saddr_in6->sin6_addr, address->address, sizeof(struct in6_addr)); + } +#endif + + if (address->type == kSbSocketAddressTypeIpv4) { + struct sockaddr_in* saddr_in = + reinterpret_cast(&saddr); + length = sizeof(struct sockaddr_in); + saddr_in->sin_family = AF_INET; + saddr_in->sin_port = htons(address->port); + memcpy(&saddr_in->sin_addr, address->address, sizeof(struct in_addr)); + } + + if (::connect(socket_, reinterpret_cast(&saddr), + length) == 0) { + return kSbSocketOk; + } + return kSbSocketErrorFailed; +#else return SbSocketConnect(socket_, address); +#endif // SB_API_VERSION >= 16 } -SbSocketError Socket::Bind(const SbSocketAddress* local_address) { - return SbSocketBind(socket_, local_address); +SbSocketError Socket::Bind(const SbSocketAddress* address) { +#if SB_API_VERSION >= 16 + // Convert SbSocketAddress tp POSIX sockaddr format + if (address == nullptr) { + return kSbSocketErrorFailed; + } + // sizeof(sockaddr_in6) = 28 + char saddr[28] = {0}; + socklen_t length; + +#if SB_HAS(IPV6) + if (address->type == kSbSocketAddressTypeIpv6) { + struct sockaddr_in6* saddr_in6 = + reinterpret_cast(&saddr); + length = sizeof(struct sockaddr_in6); + saddr_in6->sin6_family = AF_INET6; + saddr_in6->sin6_port = htons(address->port); + memcpy(&saddr_in6->sin6_addr, address->address, sizeof(struct in6_addr)); + } +#endif // SB_HAS(IPV6) + + if (address->type == kSbSocketAddressTypeIpv4) { + struct sockaddr_in* saddr_in = + reinterpret_cast(&saddr); + length = sizeof(struct sockaddr_in); + saddr_in->sin_family = AF_INET; + saddr_in->sin_port = htons(address->port); + memcpy(&saddr_in->sin_addr, address->address, sizeof(struct in_addr)); + } + + if (::bind(socket_, reinterpret_cast(&saddr), + length) == 0) { + return kSbSocketOk; + } + return kSbSocketErrorFailed; +#else + return SbSocketBind(socket_, address); +#endif // SB_API_VERSION >= 16 } SbSocketError Socket::Listen() { +#if SB_API_VERSION >= 16 +#if defined(SOMAXCONN) + const int kMaxConn = SOMAXCONN; +#else + const int kMaxConn = 128; +#endif + + if (::listen(socket_, kMaxConn) == 0) { + return kSbSocketOk; + } + return kSbSocketErrorFailed; +#else return SbSocketListen(socket_); +#endif // SB_API_VERSION >= 16 } Socket* Socket::Accept() { - SbSocket accepted_socket = SbSocketAccept(socket_); - if (SbSocketIsValid(accepted_socket)) { - return new Socket(accepted_socket); +#if SB_API_VERSION >= 16 + return new Socket(::accept(socket_, NULL, NULL)); +#else + if (SbSocketIsValid(socket_)) { + return new Socket(socket_); } - return NULL; +#endif // SB_API_VERSION >= 16 } bool Socket::IsConnected() { +#if SB_API_VERSION >= 16 + if (socket_ < 0) { + return false; + } + char c; + int result = recv(socket_, &c, 1, MSG_PEEK); + if (result == 0) { + return false; + } + return (result > 0 || errno == EAGAIN || errno == EWOULDBLOCK); +#else return SbSocketIsConnected(socket_); +#endif // SB_API_VERSION >= 16 } bool Socket::IsConnectedAndIdle() { +#if SB_API_VERSION >= 16 + if (socket_ < 0) { + return false; + } + char c; + int result = recv(socket_, &c, 1, MSG_PEEK); + if (result >= 0) { + return false; + } + return (errno == EAGAIN || errno == EWOULDBLOCK); +#else return SbSocketIsConnectedAndIdle(socket_); +#endif // SB_API_VERSION >= 16 } bool Socket::IsPending() { +#if SB_API_VERSION >= 16 + return errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK; +#else return GetLastError() == kSbSocketPending; +#endif // SB_API_VERSION >= 16 } +#if SB_API_VERSION >= 16 +int Socket::GetLastError() { + return errno; +} +#else SbSocketError Socket::GetLastError() { return SbSocketGetLastError(socket_); } +#endif // SB_API_VERSION >= 16 void Socket::ClearLastError() { +#if SB_API_VERSION >= 16 + errno = 0; +#else SbSocketClearLastError(socket_); +#endif // SB_API_VERSION >= 16 } int Socket::ReceiveFrom(char* out_data, int data_size, SbSocketAddress* out_source) { +#if SB_API_VERSION >= 16 + if (socket_ < 0) { + errno = EBADF; + return -1; + } + if (out_source) { + struct sockaddr saddr = {0}; + socklen_t length = sizeof(saddr); + int result = getpeername(socket_, &saddr, &length); + if (result < 0) { + SB_LOG(ERROR) << __FUNCTION__ + << ": getpeername failed, errno = " << errno; + return -1; + } + // Transfer address from sockaddr to SbSocketAddress + if (saddr.sa_family == AF_INET) { + struct sockaddr_in* addr_in = (struct sockaddr_in*)&saddr; + out_source->type = kSbSocketAddressTypeIpv4; + out_source->port = addr_in->sin_port; + memcpy(&out_source->address, &addr_in->sin_addr, sizeof(struct in_addr)); + } +#if SB_HAS(IPV6) + if (saddr.sa_family == AF_INET6) { + struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)&saddr; + out_source->type = kSbSocketAddressTypeIpv6; + out_source->port = addr_in6->sin6_port; + memcpy(&out_source->address, &addr_in6->sin6_addr, + sizeof(struct in6_addr)); + } +#endif + } + + int kRecvFlags = 0; + ssize_t bytes_read = recv(socket_, out_data, data_size, kRecvFlags); + if (bytes_read >= 0) { + return static_cast(bytes_read); + } + + return -1; +#else return SbSocketReceiveFrom(socket_, out_data, data_size, out_source); +#endif // SB_API_VERSION >= 16 } int Socket::SendTo(const char* data, int data_size, const SbSocketAddress* destination) { +#if SB_API_VERSION >= 16 + +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif + if ((socket_ < 0) || (destination)) { + errno = EBADF; + return -1; + } + ssize_t bytes_written = send(socket_, data, data_size, kSendFlags); + if (bytes_written >= 0) { + return static_cast(bytes_written); + } + return -1; +#else return SbSocketSendTo(socket_, data, data_size, destination); +#endif // SB_API_VERSION >= 16 } bool Socket::GetLocalAddress(SbSocketAddress* out_address) { +#if SB_API_VERSION >= 16 + if (socket_ < 0) { + errno = EBADF; + return false; + } + struct sockaddr saddr = {0}; + socklen_t length; + if (getsockname(socket_, &saddr, &length) != 0) { + return false; + } + if (out_address) { + // Transfer address from sockaddr to SbSocketAddress + if (saddr.sa_family == AF_INET) { + struct sockaddr_in* addr_in = (struct sockaddr_in*)&saddr; + out_address->type = kSbSocketAddressTypeIpv4; + out_address->port = addr_in->sin_port; + memcpy(&out_address->address, &addr_in->sin_addr, sizeof(struct in_addr)); + } +#if SB_HAS(IPV6) + if (saddr.sa_family == AF_INET6) { + struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)&saddr; + out_address->type = kSbSocketAddressTypeIpv6; + out_address->port = addr_in6->sin6_port; + memcpy(&out_address->address, &addr_in6->sin6_addr, + sizeof(struct in6_addr)); + } +#endif + } +#else return SbSocketGetLocalAddress(socket_, out_address); +#endif // SB_API_VERSION >= 16 } bool Socket::SetBroadcast(bool value) { +#if SB_API_VERSION >= 16 + int true_val = value ? 1 : 0; + if (setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_val, value) == 0) { + return true; + } + return false; +#else return SbSocketSetBroadcast(socket_, value); +#endif // SB_API_VERSION >= 16 } bool Socket::SetReuseAddress(bool value) { +#if SB_API_VERSION >= 16 + const int on = value ? 1 : 0; + if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == 0) { + return true; + } + return false; +#else return SbSocketSetReuseAddress(socket_, value); +#endif // SB_API_VERSION >= 16 } bool Socket::SetReceiveBufferSize(int32_t size) { +#if SB_API_VERSION >= 16 + if (setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, + reinterpret_cast(&size), sizeof(size)) == 0) { + return true; + } + return false; +#else return SbSocketSetReceiveBufferSize(socket_, size); +#endif // SB_API_VERSION >= 16 } bool Socket::SetSendBufferSize(int32_t size) { +#if SB_API_VERSION >= 16 + if (setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, + reinterpret_cast(&size), sizeof(size)) == 0) { + return true; + } + return false; +#else return SbSocketSetSendBufferSize(socket_, size); +#endif // SB_API_VERSION >= 16 } bool Socket::SetTcpKeepAlive(bool value, int64_t period) { +#if SB_API_VERSION >= 16 + const int on = value ? 1 : 0; + if (setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&on), sizeof(on)) != 0) { + return false; + } + if (value) { + int result = 0; + result |= setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); + +#if defined(__APPLE__) + // In tvOS, TCP_KEEPIDLE and SOL_TCP are not available. + // For reference: + // https://stackoverflow.com/questions/15860127/how-to-configure-tcp-keepalive-under-mac-os-x + result |= setsockopt(socket_, IPPROTO_TCP, TCP_KEEPALIVE, &period, + sizeof(period)); +#elif !defined(_WIN32) + // In Windows, the SOL_TCP and TCP_KEEPIDLE options are not available. + // For reference: + // https://stackoverflow.com/questions/8176821/how-to-set-the-keep-alive-interval-for-winsock + result |= + setsockopt(socket_, SOL_TCP, TCP_KEEPIDLE, &period, sizeof(period)); + result |= + setsockopt(socket_, SOL_TCP, TCP_KEEPINTVL, &period, sizeof(period)); +#endif + if (result != 0) { + return false; + } + } + return true; +#else return SbSocketSetTcpKeepAlive(socket_, value, period); +#endif // SB_API_VERSION >= 16 } bool Socket::SetTcpNoDelay(bool value) { +#if SB_API_VERSION >= 16 + const int on = value ? 1 : 0; + if (setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&on), sizeof(on)) == 0) { + return true; + } + return false; +#else return SbSocketSetTcpNoDelay(socket_, value); +#endif // SB_API_VERSION >= 16 } bool Socket::SetTcpWindowScaling(bool value) { +#if SB_API_VERSION >= 16 + // This API is not supported in standard POSIX. + return true; +#else return SbSocketSetTcpWindowScaling(socket_, value); +#endif // SB_API_VERSION >= 16 } bool Socket::JoinMulticastGroup(const SbSocketAddress* address) { +#if SB_API_VERSION >= 16 + struct ip_mreq imreq = {0}; + struct sockaddr saddr = {0}; + socklen_t length = sizeof(saddr); + in_addr_t in_addr = *reinterpret_cast(&saddr); + imreq.imr_multiaddr.s_addr = in_addr; + imreq.imr_interface.s_addr = INADDR_ANY; + + if (setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, + sizeof(imreq))) { + return false; + } + return true; +#else return SbSocketJoinMulticastGroup(socket_, address); +#endif // SB_API_VERSION >= 16 } +#if SB_API_VERSION >= 16 + +int Socket::socket() { + return socket_; +} +Socket::Socket(int socket) : socket_(socket) {} + +#else + SbSocket Socket::socket() { return socket_; } Socket::Socket(SbSocket socket) : socket_(socket) {} +#endif // SB_API_VERSION >= 16 + } // namespace starboard std::ostream& operator<<(std::ostream& os, const SbSocketAddress& address) { diff --git a/starboard/common/socket.h b/starboard/common/socket.h index d02d62318a97..ac6b817364ac 100644 --- a/starboard/common/socket.h +++ b/starboard/common/socket.h @@ -55,7 +55,11 @@ class Socket { bool IsConnectedAndIdle(); bool IsPending(); +#if SB_API_VERSION >= 16 + int GetLastError(); +#else SbSocketError GetLastError(); +#endif void ClearLastError(); int ReceiveFrom(char* out_data, int data_size, SbSocketAddress* out_source); @@ -73,12 +77,20 @@ class Socket { bool SetTcpWindowScaling(bool value); bool JoinMulticastGroup(const SbSocketAddress* address); +#if SB_API_VERSION >= 16 + int socket(); +#else SbSocket socket(); +#endif private: - explicit Socket(SbSocket socket); - +#if SB_API_VERSION >= 16 + int socket_; + explicit Socket(int socket); +#else SbSocket socket_; + explicit Socket(SbSocket socket); +#endif }; } // namespace starboard diff --git a/starboard/doc/c99.md b/starboard/doc/c99.md index f8e6e799a60c..ee1c34914271 100644 --- a/starboard/doc/c99.md +++ b/starboard/doc/c99.md @@ -100,6 +100,7 @@ deprecated and eventually removed. * trunc * truncf ### +* puts * sscanf * vsscanf ### diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index 48f816a36374..b6f783873c0c 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -468,6 +468,7 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(ftruncate); REGISTER_SYMBOL(getaddrinfo); REGISTER_SYMBOL(getifaddrs); + REGISTER_SYMBOL(getpeername); REGISTER_SYMBOL(getsockname); REGISTER_SYMBOL(listen); REGISTER_SYMBOL(lseek); @@ -479,6 +480,8 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(open); REGISTER_SYMBOL(opendir); REGISTER_SYMBOL(posix_memalign); + REGISTER_SYMBOL(SbPosixSocketWaiterAdd); + REGISTER_SYMBOL(SbPosixSocketWaiterRemove); REGISTER_SYMBOL(read); REGISTER_SYMBOL(readdir_r); REGISTER_SYMBOL(realloc); diff --git a/starboard/nplb/posix_compliance/posix_socket_join_multicast_group_test.cc b/starboard/nplb/posix_compliance/posix_socket_join_multicast_group_test.cc index c7bfd4c6a49c..884dc31346b7 100644 --- a/starboard/nplb/posix_compliance/posix_socket_join_multicast_group_test.cc +++ b/starboard/nplb/posix_compliance/posix_socket_join_multicast_group_test.cc @@ -36,7 +36,6 @@ int CreateMulticastSocket(const struct ip_mreq& address) { EXPECT_NE(-1, bind(socket_fd, (struct sockaddr*)&bind_address, sizeof(bind_address))); - EXPECT_NE(-1, setsockopt(socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &address, sizeof(address))); return socket_fd; @@ -57,10 +56,10 @@ TEST(PosixSocketJoinMulticastGroupTest, SunnyDay) { // spamming it on the local network. // http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml struct ip_mreq address; -// Same as doing inet_addr("224.0.2.0");, however inet_addr is not supported -// yet in Starboard 16. -// TODO: we should support inet_addr for better handling endianness across -// different systems. + // Same as doing inet_addr("224.0.2.0");, however inet_addr is not supported + // yet in Starboard 16. + // TODO: we should support inet_addr for better handling endianness across + // different systems. #if SB_IS_BIG_ENDIAN address.imr_multiaddr.s_addr = (224 << 24) | (0 << 16) | (2 << 8) | 0; #else diff --git a/starboard/nplb/socket_send_to_test.cc b/starboard/nplb/socket_send_to_test.cc index 48f503438c1d..46e155f6e28f 100644 --- a/starboard/nplb/socket_send_to_test.cc +++ b/starboard/nplb/socket_send_to_test.cc @@ -137,8 +137,13 @@ TEST_P(PairSbSocketSendToTest, RainyDaySendToSocketUntilBlocking) { int result = trio->client_socket->SendTo(buff, sizeof(buff), NULL); if (result < 0) { +#if SB_API_VERSION >= 16 + int err = errno; + EXPECT_EQ(EINPROGRESS, err); +#else SbSocketError err = SbSocketGetLastError(trio->client_socket->socket()); EXPECT_EQ(kSbSocketPending, err); +#endif // SB_API_VERSION >= 16 return; } @@ -176,10 +181,15 @@ TEST_P(PairSbSocketSendToTest, RainyDaySendToSocketConnectionReset) { int result = trio->client_socket->SendTo(buff, sizeof(buff), NULL); if (result < 0) { +#if SB_API_VERSION >= 16 + int err = errno; + EXPECT_EQ(kSbSocketErrorConnectionReset, err); +#else SbSocketError err = SbSocketGetLastError(trio->client_socket->socket()); EXPECT_EQ(kSbSocketErrorConnectionReset, err) << "Expected connection drop."; +#endif return; } @@ -208,6 +218,7 @@ INSTANTIATE_TEST_CASE_P( kSbSocketAddressTypeIpv4)), GetSbSocketAddressTypePairName); #endif + } // namespace } // namespace nplb } // namespace starboard diff --git a/starboard/shared/posix/socket_get_local_address.cc b/starboard/shared/posix/socket_get_local_address.cc index d3534718c7cf..5c8eb2aa2f5b 100644 --- a/starboard/shared/posix/socket_get_local_address.cc +++ b/starboard/shared/posix/socket_get_local_address.cc @@ -21,6 +21,9 @@ #include "starboard/shared/posix/handle_eintr.h" #include "starboard/shared/posix/socket_internal.h" +#include +#include + namespace sbposix = starboard::shared::posix; bool SbSocketGetLocalAddress(SbSocket socket, SbSocketAddress* out_address) { @@ -33,6 +36,7 @@ bool SbSocketGetLocalAddress(SbSocket socket, SbSocketAddress* out_address) { sbposix::SockAddr sock_addr; int result = getsockname(socket->socket_fd, sock_addr.sockaddr(), &sock_addr.length); + if (result < 0) { socket->error = sbposix::TranslateSocketErrno(errno); return false; diff --git a/starboard/shared/posix/socket_join_multicast_group.cc b/starboard/shared/posix/socket_join_multicast_group.cc index 0dde43f02897..ad47f0fb1451 100644 --- a/starboard/shared/posix/socket_join_multicast_group.cc +++ b/starboard/shared/posix/socket_join_multicast_group.cc @@ -19,6 +19,9 @@ #include #include +#include +#include + #include "starboard/common/log.h" #include "starboard/shared/posix/socket_internal.h" @@ -39,6 +42,7 @@ bool SbSocketJoinMulticastGroup(SbSocket socket, SB_DCHECK(socket->socket_fd >= 0); struct ip_mreq imreq = {0}; in_addr_t in_addr = *reinterpret_cast(address->address); + imreq.imr_multiaddr.s_addr = in_addr; imreq.imr_interface.s_addr = INADDR_ANY; diff --git a/starboard/shared/starboard/link_receiver.cc b/starboard/shared/starboard/link_receiver.cc index dcc9a3f41cea..21e4b84a53e8 100644 --- a/starboard/shared/starboard/link_receiver.cc +++ b/starboard/shared/starboard/link_receiver.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "starboard/shared/starboard/link_receiver.h" +#include #include #include @@ -27,6 +27,8 @@ #include "starboard/common/string.h" #include "starboard/configuration_constants.h" #include "starboard/shared/starboard/application.h" +#include "starboard/shared/starboard/link_receiver.h" +#include "starboard/socket.h" #include "starboard/socket_waiter.h" #include "starboard/system.h" @@ -40,14 +42,12 @@ namespace { std::unique_ptr CreateServerSocket(SbSocketAddressType address_type) { std::unique_ptr socket(new Socket(address_type)); if (!socket->IsValid()) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "SbSocketCreate failed"; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbSocketCreate failed"; return std::unique_ptr(); } if (!socket->SetReuseAddress(true)) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "SbSocketSetReuseAddress failed"; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbSocketSetReuseAddress failed"; return std::unique_ptr(); } @@ -71,8 +71,8 @@ std::unique_ptr CreateLocallyBoundSocket( } SbSocketError result = socket->Bind(&address); if (result != kSbSocketOk) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "SbSocketBind to " << port << " failed: " << result; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbSocketBind to " << port + << " failed: " << result; return std::unique_ptr(); } @@ -119,8 +119,7 @@ std::string GetTemporaryDirectory() { bool has_temp = SbSystemGetPath(kSbSystemPathTempDirectory, temp_path.get(), kMaxPathLength); if (!has_temp) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "No temporary directory."; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "No temporary directory."; return ""; } @@ -138,8 +137,7 @@ void CreateTemporaryFile(const char* name, const char* contents, int size) { path += name; ScopedFile file(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY); if (!file.IsValid()) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "Unable to create: " << path; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "Unable to create: " << path; return; } @@ -187,23 +185,39 @@ class LinkReceiver::Impl { void OnAcceptReady(); // Called when the waiter reports that a socket has more data to read. - void OnReadReady(SbSocket sb_socket); +#if SB_API_VERSION >= 16 + void OnReadReady(int socket); + // SbSocketWaiter entry points. + static void HandleAccept(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests); - // Called when the waiter reports that a connection has more data to read. - void OnReadReady(Connection* connection); + static void HandleRead(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests); - // Thread entry point. - static void* RunThread(void* context); +#else + void OnReadReady(SbSocket socket); // SbSocketWaiter entry points. static void HandleAccept(SbSocketWaiter waiter, SbSocket socket, void* context, int ready_interests); + static void HandleRead(SbSocketWaiter waiter, SbSocket socket, void* context, int ready_interests); +#endif + + // Called when the waiter reports that a connection has more data to read. + void OnReadReady(Connection* connection); + + // Thread entry point. + static void* RunThread(void* context); // The application to dispatch Link() calls to. Application* application_; @@ -236,7 +250,11 @@ class LinkReceiver::Impl { std::unique_ptr listen_socket_; // A map of raw SbSockets to Connection objects. +#if SB_API_VERSION >= 16 + std::unordered_map connections_; +#else std::unordered_map connections_; +#endif }; LinkReceiver::Impl::Impl(Application* application, int port) @@ -307,12 +325,20 @@ void LinkReceiver::Impl::Run() { } for (auto& entry : connections_) { +#if SB_API_VERSION >= 16 + SbPosixSocketWaiterRemove(waiter_, entry.first); +#else SbSocketWaiterRemove(waiter_, entry.first); +#endif delete entry.second; } connections_.clear(); +#if SB_API_VERSION >= 16 + SbPosixSocketWaiterRemove(waiter_, listen_socket_->socket()); +#else SbSocketWaiterRemove(waiter_, listen_socket_->socket()); +#endif // Block until destroying thread will no longer reference waiter. destroy_waiter_.Take(); @@ -320,24 +346,41 @@ void LinkReceiver::Impl::Run() { } bool LinkReceiver::Impl::AddForAccept(Socket* socket) { + bool result = false; +#if SB_API_VERSION >= 16 + if (!SbPosixSocketWaiterAdd(waiter_, socket->socket(), this, + &LinkReceiver::Impl::HandleAccept, + kSbSocketWaiterInterestRead, true)) { + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbPosixSocketWaiterAdd failed."; + return false; + } +#else if (!SbSocketWaiterAdd(waiter_, socket->socket(), this, &LinkReceiver::Impl::HandleAccept, kSbSocketWaiterInterestRead, true)) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "SbSocketWaiterAdd failed."; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbSocketWaiterAdd failed."; return false; } +#endif return true; } bool LinkReceiver::Impl::AddForRead(Connection* connection) { +#if SB_API_VERSION >= 16 + if (!SbPosixSocketWaiterAdd(waiter_, connection->socket->socket(), this, + &LinkReceiver::Impl::HandleRead, + kSbSocketWaiterInterestRead, false)) { + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbSocketWaiterAdd failed."; + return false; + } +#else if (!SbSocketWaiterAdd(waiter_, connection->socket->socket(), this, &LinkReceiver::Impl::HandleRead, kSbSocketWaiterInterestRead, false)) { - SB_LOG(ERROR) << __FUNCTION__ << ": " - << "SbSocketWaiterAdd failed."; + SB_LOG(ERROR) << __FUNCTION__ << ": " << "SbSocketWaiterAdd failed."; return false; } +#endif return true; } @@ -350,11 +393,19 @@ void LinkReceiver::Impl::OnAcceptReady() { AddForRead(connection); } -void LinkReceiver::Impl::OnReadReady(SbSocket sb_socket) { - auto iter = connections_.find(sb_socket); +#if SB_API_VERSION >= 16 +void LinkReceiver::Impl::OnReadReady(int socket) { + auto iter = connections_.find(socket); SB_DCHECK(iter != connections_.end()); OnReadReady(iter->second); } +#else +void LinkReceiver::Impl::OnReadReady(SbSocket socket) { + auto iter = connections_.find(socket); + SB_DCHECK(iter != connections_.end()); + OnReadReady(iter->second); +} +#endif void LinkReceiver::Impl::OnReadReady(Connection* connection) { auto socket = connection->socket.get(); @@ -399,6 +450,26 @@ void* LinkReceiver::Impl::RunThread(void* context) { return NULL; } +#if SB_API_VERSION >= 16 +// static +void LinkReceiver::Impl::HandleAccept(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) { + SB_DCHECK(context); + reinterpret_cast(context)->OnAcceptReady(); +} + +// static +void LinkReceiver::Impl::HandleRead(SbSocketWaiter waiter, + int socket, + void* context, + int ready_interests) { + SB_DCHECK(context); + reinterpret_cast(context)->OnReadReady(socket); +} + +#else // static void LinkReceiver::Impl::HandleAccept(SbSocketWaiter waiter, SbSocket socket, @@ -417,6 +488,8 @@ void LinkReceiver::Impl::HandleRead(SbSocketWaiter waiter, reinterpret_cast(context)->OnReadReady(socket); } +#endif // SB_API_VERSION >= 16 + LinkReceiver::LinkReceiver(Application* application) : impl_(new Impl(application, 0)) {} diff --git a/starboard/shared/starboard/net_args.cc b/starboard/shared/starboard/net_args.cc index afd1f2d4e542..5d965c5e5dda 100644 --- a/starboard/shared/starboard/net_args.cc +++ b/starboard/shared/starboard/net_args.cc @@ -62,6 +62,25 @@ std::unique_ptr CreateListenSocket() { return socket; } +#if SB_API_VERSION >= 16 +void WaitUntilReadableOrConnectionReset(int sock) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + + struct F { + static void WakeUp(SbSocketWaiter waiter, int, void*, int) { + SbSocketWaiterWakeUp(waiter); + } + }; + + SbPosixSocketWaiterAdd(waiter, sock, NULL, &F::WakeUp, + kSbSocketWaiterInterestRead, + false); // false means one shot. + + SbSocketWaiterWait(waiter); + SbPosixSocketWaiterRemove(waiter, sock); + SbSocketWaiterDestroy(waiter); +} +#else void WaitUntilReadableOrConnectionReset(SbSocket sock) { SbSocketWaiter waiter = SbSocketWaiterCreate(); @@ -78,6 +97,7 @@ void WaitUntilReadableOrConnectionReset(SbSocket sock) { SbSocketWaiterRemove(waiter, sock); SbSocketWaiterDestroy(waiter); } +#endif std::unique_ptr WaitForClientConnection(Socket* listen_sock, int64_t timeout) { @@ -135,6 +155,24 @@ std::vector NetArgsWaitForPayload(int64_t timeout) { // Socket has closed. break; } else if (result < 0) { // Handle error condition. +#if SB_API_VERSION >= 16 + int err = client_connection->GetLastError(); + switch (err) { + case 0: { + SB_NOTREACHED() << "Expected error condition when return val " + << "is < 0."; + continue; + } + case EINPROGRESS: { + WaitUntilReadableOrConnectionReset(client_connection->socket()); + continue; + } + default: { + break; + } + } + +#else SbSocketError err = client_connection->GetLastError(); client_connection->ClearLastError(); @@ -152,6 +190,7 @@ std::vector NetArgsWaitForPayload(int64_t timeout) { break; } } +#endif } } return SplitStringByLines(str_buff); diff --git a/starboard/shared/starboard/net_log.cc b/starboard/shared/starboard/net_log.cc index 632fdc847221..c0c6c6e68ade 100644 --- a/starboard/shared/starboard/net_log.cc +++ b/starboard/shared/starboard/net_log.cc @@ -15,7 +15,9 @@ #include "starboard/shared/starboard/net_log.h" #include +#include #include +#undef socket #include #include @@ -161,6 +163,30 @@ class BufferedSocketWriter { } } +#if SB_API_VERSION >= 16 + void WaitUntilWritableOrConnectionReset(int sock) { + SbSocketWaiter waiter = SbSocketWaiterCreate(); + + struct F { + static void WakeUp(SbSocketWaiter waiter, int, void*, int) { + SbSocketWaiterWakeUp(waiter); + } + }; + SbPosixSocketWaiterAdd(waiter, sock, NULL, &F::WakeUp, + kSbSocketWaiterInterestWrite, + false); // false means one shot. + SbSocketWaiterWait(waiter); + SbPosixSocketWaiterRemove(waiter, sock); + SbSocketWaiterDestroy(waiter); + } + + bool IsConnectionReset(int err) { + return err == WSAECONNRESET || err == WSAENETRESET || + err == WSAECONNABORTED; + } + +#else + void WaitUntilWritableOrConnectionReset(SbSocket sock) { SbSocketWaiter waiter = SbSocketWaiterCreate(); @@ -183,8 +209,53 @@ class BufferedSocketWriter { return err == kSbSocketErrorConnectionReset; } +#endif + // Will flush data through to the dest_socket. Returns |true| if // flushed, else connection was dropped or an error occurred. +#if SB_API_VERSION >= 16 + bool Flush(int dest_socket) { + std::string curr_write_block; + while (TransferData(chunk_size_, &curr_write_block)) { + while (!curr_write_block.empty()) { + int bytes_to_write = static_cast(curr_write_block.size()); +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif + int result = send(dest_socket, curr_write_block.c_str(), bytes_to_write, + kSendFlags); + if (result < 0) { + int err = errno; + if (err == kSbSocketPending) { + blocked_counts_.increment(); + WaitUntilWritableOrConnectionReset(dest_socket); + continue; + } else if (IsConnectionReset(err)) { + return false; + } else { + SB_LOG(ERROR) << "An error happened while writing to socket: " + << (err); + return false; + } + break; + } else if (result == 0) { + // Socket has closed. + return false; + } else { + // Expected condition. Partial or full write was successful. + size_t bytes_written = static_cast(result); + SB_DCHECK(bytes_written <= bytes_to_write); + curr_write_block.erase(0, bytes_written); + } + } + } + return true; + } + +#else + bool Flush(SbSocket dest_socket) { std::string curr_write_block; while (TransferData(chunk_size_, &curr_write_block)) { @@ -221,6 +292,7 @@ class BufferedSocketWriter { } return true; } +#endif int32_t blocked_counts() const { return blocked_counts_.load(); } diff --git a/starboard/shared/win32/posix_emu/include/netinet/in.h b/starboard/shared/win32/posix_emu/include/netinet/in.h index 77c73bb8f954..811e7d384186 100644 --- a/starboard/shared/win32/posix_emu/include/netinet/in.h +++ b/starboard/shared/win32/posix_emu/include/netinet/in.h @@ -18,6 +18,8 @@ #include #include +typedef int in_addr_t; + #include "starboard/shared/win32/posix_emu/include/remove_problematic_windows_macros.h" #endif // STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_NETINET_IN_H_ diff --git a/starboard/shared/win32/posix_emu/socket.cc b/starboard/shared/win32/posix_emu/socket.cc index c8a8dba2ed81..f8cc233f2b50 100644 --- a/starboard/shared/win32/posix_emu/socket.cc +++ b/starboard/shared/win32/posix_emu/socket.cc @@ -77,16 +77,19 @@ static FileOrSocket handle_db_get(int fd, bool erase) { _set_errno(EBADF); return invalid_handle; } + EnterCriticalSection(&g_critical_section.critical_section_); if (g_map_addr == nullptr) { g_map_addr = new std::map(); _set_errno(EBADF); + LeaveCriticalSection(&g_critical_section.critical_section_); return invalid_handle; } auto itr = g_map_addr->find(fd); if (itr == g_map_addr->end()) { _set_errno(EBADF); + LeaveCriticalSection(&g_critical_section.critical_section_); return invalid_handle; } diff --git a/starboard/tools/api_leak_detector/api_leak_detector.py b/starboard/tools/api_leak_detector/api_leak_detector.py index cdfe27f99752..2a3273f52b0d 100755 --- a/starboard/tools/api_leak_detector/api_leak_detector.py +++ b/starboard/tools/api_leak_detector/api_leak_detector.py @@ -103,12 +103,17 @@ 'gettimeofday', 'getifaddrs', 'getaddrinfo', + 'getpeername', + 'getsockname', 'gmtime_r', 'inet_ntop', 'listen', 'lseek', 'malloc', 'posix_memalign', + 'SbPosixSocketWaiterAdd', + 'SbPosixSocketWaiterRemove', + 'puts', 'recv', 'recvfrom', 'realloc',