From 8f8222e9ad9d0346fe2b9ca56f21a4ddec835705 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Wed, 4 Sep 2013 10:41:51 +0000 Subject: [PATCH] Cleanup Socket class and remove it from the platform files. Move the Socket class to dedicated platform/socket.{cc,h} files. Cleaned up the implementation to allow for more code sharing. R=verwaest@chromium.org Review URL: https://codereview.chromium.org/23484014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16521 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/d8-debug.cc | 14 +- src/debug-agent.cc | 84 ++++++--- src/debug-agent.h | 30 +--- src/debug.cc | 12 +- src/platform-posix.cc | 198 --------------------- src/platform-win32.cc | 192 -------------------- src/platform.h | 48 ----- src/platform/socket.cc | 223 ++++++++++++++++++++++++ src/platform/socket.h | 101 +++++++++++ test/cctest/cctest.gyp | 2 +- test/cctest/cctest.status | 2 +- test/cctest/test-debug.cc | 33 ++-- test/cctest/{test-sockets.cc => test-socket.cc} | 20 +-- tools/gyp/v8.gyp | 2 + 14 files changed, 424 insertions(+), 537 deletions(-) create mode 100644 src/platform/socket.cc create mode 100644 src/platform/socket.h rename test/cctest/{test-sockets.cc => test-socket.cc} (94%) diff --git a/src/d8-debug.cc b/src/d8-debug.cc index 2905500..602ae16 100644 --- a/src/d8-debug.cc +++ b/src/d8-debug.cc @@ -29,8 +29,9 @@ #include "d8.h" #include "d8-debug.h" -#include "platform.h" #include "debug-agent.h" +#include "platform.h" +#include "platform/socket.h" namespace v8 { @@ -171,21 +172,14 @@ void RunRemoteDebugger(Isolate* isolate, int port) { void RemoteDebugger::Run() { bool ok; - // Make sure that socket support is initialized. - ok = i::Socket::SetUp(); - if (!ok) { - printf("Unable to initialize socket support %d\n", i::Socket::LastError()); - return; - } - // Connect to the debugger agent. - conn_ = i::OS::CreateSocket(); + conn_ = new i::Socket; static const int kPortStrSize = 6; char port_str[kPortStrSize]; i::OS::SNPrintF(i::Vector(port_str, kPortStrSize), "%d", port_); ok = conn_->Connect("localhost", port_str); if (!ok) { - printf("Unable to connect to debug agent %d\n", i::Socket::LastError()); + printf("Unable to connect to debug agent %d\n", i::Socket::GetLastError()); return; } diff --git a/src/debug-agent.cc b/src/debug-agent.cc index 51bd4b1..aad3608 100644 --- a/src/debug-agent.cc +++ b/src/debug-agent.cc @@ -25,12 +25,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef ENABLE_DEBUGGER_SUPPORT #include "v8.h" #include "debug.h" #include "debug-agent.h" - -#ifdef ENABLE_DEBUGGER_SUPPORT +#include "platform/socket.h" namespace v8 { namespace internal { @@ -44,6 +44,27 @@ void DebuggerAgentMessageHandler(const v8::Debug::Message& message) { } +DebuggerAgent::DebuggerAgent(Isolate* isolate, const char* name, int port) + : Thread(name), + isolate_(isolate), + name_(StrDup(name)), + port_(port), + server_(new Socket), + terminate_(false), + session_(NULL), + terminate_now_(0), + listening_(0) { + ASSERT(isolate_->debugger_agent_instance() == NULL); + isolate_->set_debugger_agent_instance(this); +} + + +DebuggerAgent::~DebuggerAgent() { + isolate_->set_debugger_agent_instance(NULL); + delete server_; +} + + // Debugger agent main thread. void DebuggerAgent::Run() { // Allow this socket to reuse port even if still in TIME_WAIT. @@ -112,8 +133,10 @@ void DebuggerAgent::CreateSession(Socket* client) { // If another session is already established terminate this one. if (session_ != NULL) { - client->Send(kCreateSessionMessage, StrLength(kCreateSessionMessage)); + int len = StrLength(kCreateSessionMessage); + int res = client->Send(kCreateSessionMessage, len); delete client; + USE(res); return; } @@ -228,7 +251,7 @@ void DebuggerAgentSession::Shutdown() { const char* const DebuggerAgentUtil::kContentLength = "Content-Length"; -SmartArrayPointer DebuggerAgentUtil::ReceiveMessage(const Socket* conn) { +SmartArrayPointer DebuggerAgentUtil::ReceiveMessage(Socket* conn) { int received; // Read header. @@ -245,7 +268,7 @@ SmartArrayPointer DebuggerAgentUtil::ReceiveMessage(const Socket* conn) { prev_c = c; received = conn->Receive(&c, 1); if (received == 0) { - PrintF("Error %d\n", Socket::LastError()); + PrintF("Error %d\n", Socket::GetLastError()); return SmartArrayPointer(); } @@ -307,7 +330,7 @@ SmartArrayPointer DebuggerAgentUtil::ReceiveMessage(const Socket* conn) { char* buffer = NewArray(content_length + 1); received = ReceiveAll(conn, buffer, content_length); if (received < content_length) { - PrintF("Error %d\n", Socket::LastError()); + PrintF("Error %d\n", Socket::GetLastError()); return SmartArrayPointer(); } buffer[content_length] = '\0'; @@ -316,7 +339,7 @@ SmartArrayPointer DebuggerAgentUtil::ReceiveMessage(const Socket* conn) { } -bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn, +bool DebuggerAgentUtil::SendConnectMessage(Socket* conn, const char* embedding_host) { static const int kBufferSize = 80; char buffer[kBufferSize]; // Sending buffer. @@ -362,7 +385,7 @@ bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn, } -bool DebuggerAgentUtil::SendMessage(const Socket* conn, +bool DebuggerAgentUtil::SendMessage(Socket* conn, const Vector message) { static const int kBufferSize = 80; char buffer[kBufferSize]; // Sending buffer both for header and body. @@ -377,14 +400,17 @@ bool DebuggerAgentUtil::SendMessage(const Socket* conn, } // Send the header. - int len; - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "%s: %d\r\n", kContentLength, utf8_len); - conn->Send(buffer, len); + int len = OS::SNPrintF(Vector(buffer, kBufferSize), + "%s: %d\r\n", kContentLength, utf8_len); + if (conn->Send(buffer, len) < len) { + return false; + } // Terminate header with empty line. len = OS::SNPrintF(Vector(buffer, kBufferSize), "\r\n"); - conn->Send(buffer, len); + if (conn->Send(buffer, len) < len) { + return false; + } // Send message body as UTF-8. int buffer_position = 0; // Current buffer position. @@ -404,13 +430,19 @@ bool DebuggerAgentUtil::SendMessage(const Socket* conn, const int kEncodedSurrogateLength = unibrow::Utf16::kUtf8BytesToCodeASurrogate; ASSERT(buffer_position >= kEncodedSurrogateLength); - conn->Send(buffer, buffer_position - kEncodedSurrogateLength); + len = buffer_position - kEncodedSurrogateLength; + if (conn->Send(buffer, len) < len) { + return false; + } for (int i = 0; i < kEncodedSurrogateLength; i++) { buffer[i] = buffer[buffer_position + i]; } buffer_position = kEncodedSurrogateLength; } else { - conn->Send(buffer, buffer_position); + len = buffer_position; + if (conn->Send(buffer, len) < len) { + return false; + } buffer_position = 0; } } @@ -421,7 +453,7 @@ bool DebuggerAgentUtil::SendMessage(const Socket* conn, } -bool DebuggerAgentUtil::SendMessage(const Socket* conn, +bool DebuggerAgentUtil::SendMessage(Socket* conn, const v8::Handle request) { static const int kBufferSize = 80; char buffer[kBufferSize]; // Sending buffer both for header and body. @@ -430,24 +462,30 @@ bool DebuggerAgentUtil::SendMessage(const Socket* conn, v8::String::Utf8Value utf8_request(request); // Send the header. - int len; - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "Content-Length: %d\r\n", utf8_request.length()); - conn->Send(buffer, len); + int len = OS::SNPrintF(Vector(buffer, kBufferSize), + "Content-Length: %d\r\n", utf8_request.length()); + if (conn->Send(buffer, len) < len) { + return false; + } // Terminate header with empty line. len = OS::SNPrintF(Vector(buffer, kBufferSize), "\r\n"); - conn->Send(buffer, len); + if (conn->Send(buffer, len) < len) { + return false; + } // Send message body as UTF-8. - conn->Send(*utf8_request, utf8_request.length()); + len = utf8_request.length(); + if (conn->Send(*utf8_request, len) < len) { + return false; + } return true; } // Receive the full buffer before returning unless an error occours. -int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) { +int DebuggerAgentUtil::ReceiveAll(Socket* conn, char* data, int len) { int total_received = 0; while (total_received < len) { int received = conn->Receive(data + total_received, len - total_received); diff --git a/src/debug-agent.h b/src/debug-agent.h index 9d7c62b..138e51a 100644 --- a/src/debug-agent.h +++ b/src/debug-agent.h @@ -37,27 +37,15 @@ namespace internal { // Forward decelrations. class DebuggerAgentSession; +class Socket; // Debugger agent which starts a socket listener on the debugger port and // handles connection from a remote debugger. class DebuggerAgent: public Thread { public: - DebuggerAgent(Isolate* isolate, const char* name, int port) - : Thread(name), - isolate_(isolate), - name_(StrDup(name)), port_(port), - server_(OS::CreateSocket()), terminate_(false), - session_(NULL), - terminate_now_(0), - listening_(0) { - ASSERT(isolate_->debugger_agent_instance() == NULL); - isolate_->set_debugger_agent_instance(this); - } - ~DebuggerAgent() { - isolate_->set_debugger_agent_instance(NULL); - delete server_; - } + DebuggerAgent(Isolate* isolate, const char* name, int port); + ~DebuggerAgent(); void Shutdown(); void WaitUntilListening(); @@ -116,13 +104,11 @@ class DebuggerAgentUtil { public: static const char* const kContentLength; - static SmartArrayPointer ReceiveMessage(const Socket* conn); - static bool SendConnectMessage(const Socket* conn, - const char* embedding_host); - static bool SendMessage(const Socket* conn, const Vector message); - static bool SendMessage(const Socket* conn, - const v8::Handle message); - static int ReceiveAll(const Socket* conn, char* data, int len); + static SmartArrayPointer ReceiveMessage(Socket* conn); + static bool SendConnectMessage(Socket* conn, const char* embedding_host); + static bool SendMessage(Socket* conn, const Vector message); + static bool SendMessage(Socket* conn, const v8::Handle message); + static int ReceiveAll(Socket* conn, char* data, int len); }; } } // namespace v8::internal diff --git a/src/debug.cc b/src/debug.cc index 9f38601..c3d737e 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -3433,15 +3433,11 @@ bool Debugger::StartAgent(const char* name, int port, v8::Debug::DebugBreak(); } - if (Socket::SetUp()) { - if (agent_ == NULL) { - agent_ = new DebuggerAgent(isolate_, name, port); - agent_->Start(); - } - return true; + if (agent_ == NULL) { + agent_ = new DebuggerAgent(isolate_, name, port); + agent_->Start(); } - - return false; + return true; } diff --git a/src/platform-posix.cc b/src/platform-posix.cc index aaf0ca7..504d140 100644 --- a/src/platform-posix.cc +++ b/src/platform-posix.cc @@ -739,202 +739,4 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) { } -// ---------------------------------------------------------------------------- -// POSIX socket support. -// - -class POSIXSocket : public Socket { - public: - explicit POSIXSocket() { - // Create the socket. - socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (IsValid()) { - // Allow rapid reuse. - static const int kOn = 1; - int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, - &kOn, sizeof(kOn)); - ASSERT(ret == 0); - USE(ret); - } - } - explicit POSIXSocket(int socket): socket_(socket) { } - virtual ~POSIXSocket() { Shutdown(); } - - // Server initialization. - bool Bind(const int port); - bool Listen(int backlog) const; - Socket* Accept() const; - - // Client initialization. - bool Connect(const char* host, const char* port); - - // Shutdown socket for both read and write. - bool Shutdown(); - - // Data Transimission - int Send(const char* data, int len) const; - int Receive(char* data, int len) const; - - bool SetReuseAddress(bool reuse_address); - - bool IsValid() const { return socket_ != -1; } - - private: - int socket_; -}; - - -bool POSIXSocket::Bind(const int port) { - if (!IsValid()) { - return false; - } - - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(port); - int status = bind(socket_, - BitCast(&addr), - sizeof(addr)); - return status == 0; -} - - -bool POSIXSocket::Listen(int backlog) const { - if (!IsValid()) { - return false; - } - - int status = listen(socket_, backlog); - return status == 0; -} - - -Socket* POSIXSocket::Accept() const { - if (!IsValid()) { - return NULL; - } - - int socket; - do { - socket = accept(socket_, NULL, NULL); - } while (socket == -1 && errno == EINTR); - - if (socket == -1) { - return NULL; - } else { - return new POSIXSocket(socket); - } -} - - -bool POSIXSocket::Connect(const char* host, const char* port) { - if (!IsValid()) { - return false; - } - - // Lookup host and port. - struct addrinfo *result = NULL; - struct addrinfo hints; - memset(&hints, 0, sizeof(addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - int status = getaddrinfo(host, port, &hints, &result); - if (status != 0) { - return false; - } - - // Connect. - do { - status = connect(socket_, result->ai_addr, result->ai_addrlen); - } while (status == -1 && errno == EINTR); - freeaddrinfo(result); - return status == 0; -} - - -bool POSIXSocket::Shutdown() { - if (IsValid()) { - // Shutdown socket for both read and write. - int status = shutdown(socket_, SHUT_RDWR); - close(socket_); - socket_ = -1; - return status == 0; - } - return true; -} - - -int POSIXSocket::Send(const char* data, int len) const { - if (len <= 0) return 0; - int written = 0; - while (written < len) { - int status = send(socket_, data + written, len - written, 0); - if (status == 0) { - break; - } else if (status > 0) { - written += status; - } else if (errno != EINTR) { - return 0; - } - } - return written; -} - - -int POSIXSocket::Receive(char* data, int len) const { - if (len <= 0) return 0; - int status; - do { - status = recv(socket_, data, len, 0); - } while (status == -1 && errno == EINTR); - return (status < 0) ? 0 : status; -} - - -bool POSIXSocket::SetReuseAddress(bool reuse_address) { - int on = reuse_address ? 1 : 0; - int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - return status == 0; -} - - -bool Socket::SetUp() { - // Nothing to do on POSIX. - return true; -} - - -int Socket::LastError() { - return errno; -} - - -uint16_t Socket::HToN(uint16_t value) { - return htons(value); -} - - -uint16_t Socket::NToH(uint16_t value) { - return ntohs(value); -} - - -uint32_t Socket::HToN(uint32_t value) { - return htonl(value); -} - - -uint32_t Socket::NToH(uint32_t value) { - return ntohl(value); -} - - -Socket* OS::CreateSocket() { - return new POSIXSocket(); -} - - } } // namespace v8::internal diff --git a/src/platform-win32.cc b/src/platform-win32.cc index 199ed2d..87387e7 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -1615,198 +1615,6 @@ void Thread::YieldCPU() { } -// ---------------------------------------------------------------------------- -// Win32 socket support. -// - -class Win32Socket : public Socket { - public: - explicit Win32Socket() { - // Create the socket. - socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - } - explicit Win32Socket(SOCKET socket): socket_(socket) { } - virtual ~Win32Socket() { Shutdown(); } - - // Server initialization. - bool Bind(const int port); - bool Listen(int backlog) const; - Socket* Accept() const; - - // Client initialization. - bool Connect(const char* host, const char* port); - - // Shutdown socket for both read and write. - bool Shutdown(); - - // Data Transimission - int Send(const char* data, int len) const; - int Receive(char* data, int len) const; - - bool SetReuseAddress(bool reuse_address); - - bool IsValid() const { return socket_ != INVALID_SOCKET; } - - private: - SOCKET socket_; -}; - - -bool Win32Socket::Bind(const int port) { - if (!IsValid()) { - return false; - } - - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(port); - int status = bind(socket_, - reinterpret_cast(&addr), - sizeof(addr)); - return status == 0; -} - - -bool Win32Socket::Listen(int backlog) const { - if (!IsValid()) { - return false; - } - - int status = listen(socket_, backlog); - return status == 0; -} - - -Socket* Win32Socket::Accept() const { - if (!IsValid()) { - return NULL; - } - - SOCKET socket = accept(socket_, NULL, NULL); - if (socket == INVALID_SOCKET) { - return NULL; - } else { - return new Win32Socket(socket); - } -} - - -bool Win32Socket::Connect(const char* host, const char* port) { - if (!IsValid()) { - return false; - } - - // Lookup host and port. - struct addrinfo *result = NULL; - struct addrinfo hints; - memset(&hints, 0, sizeof(addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - int status = getaddrinfo(host, port, &hints, &result); - if (status != 0) { - return false; - } - - // Connect. - status = connect(socket_, - result->ai_addr, - static_cast(result->ai_addrlen)); - freeaddrinfo(result); - return status == 0; -} - - -bool Win32Socket::Shutdown() { - if (IsValid()) { - // Shutdown socket for both read and write. - int status = shutdown(socket_, SD_BOTH); - closesocket(socket_); - socket_ = INVALID_SOCKET; - return status == SOCKET_ERROR; - } - return true; -} - - -int Win32Socket::Send(const char* data, int len) const { - if (len <= 0) return 0; - int written = 0; - while (written < len) { - int status = send(socket_, data + written, len - written, 0); - if (status == 0) { - break; - } else if (status > 0) { - written += status; - } else { - return 0; - } - } - return written; -} - - -int Win32Socket::Receive(char* data, int len) const { - if (len <= 0) return 0; - int status = recv(socket_, data, len, 0); - return (status == SOCKET_ERROR) ? 0 : status; -} - - -bool Win32Socket::SetReuseAddress(bool reuse_address) { - BOOL on = reuse_address ? true : false; - int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&on), sizeof(on)); - return status == SOCKET_ERROR; -} - - -bool Socket::SetUp() { - // Initialize Winsock32 - int err; - WSADATA winsock_data; - WORD version_requested = MAKEWORD(1, 0); - err = WSAStartup(version_requested, &winsock_data); - if (err != 0) { - PrintF("Unable to initialize Winsock, err = %d\n", Socket::LastError()); - } - - return err == 0; -} - - -int Socket::LastError() { - return WSAGetLastError(); -} - - -uint16_t Socket::HToN(uint16_t value) { - return htons(value); -} - - -uint16_t Socket::NToH(uint16_t value) { - return ntohs(value); -} - - -uint32_t Socket::HToN(uint32_t value) { - return htonl(value); -} - - -uint32_t Socket::NToH(uint32_t value) { - return ntohl(value); -} - - -Socket* OS::CreateSocket() { - return new Win32Socket(); -} - - void OS::SetUp() { // Seed the random number generator. // Convert the current time to a 64-bit integer first, before converting it diff --git a/src/platform.h b/src/platform.h index 8565775..18bf6b0 100644 --- a/src/platform.h +++ b/src/platform.h @@ -108,9 +108,6 @@ double fast_sqrt(double input); // on demand. void lazily_initialize_fast_exp(); -// Forward declarations. -class Socket; - // ---------------------------------------------------------------------------- // Fast TLS support @@ -287,10 +284,6 @@ class OS { static int StackWalk(Vector frames); - // Factory method for creating platform dependent Socket. - // Please use delete to reclaim the storage for the returned Socket. - static Socket* CreateSocket(); - class MemoryMappedFile { public: static MemoryMappedFile* open(const char* name); @@ -619,47 +612,6 @@ class Thread { DISALLOW_COPY_AND_ASSIGN(Thread); }; - -// ---------------------------------------------------------------------------- -// Socket -// - -class Socket { - public: - virtual ~Socket() {} - - // Server initialization. - virtual bool Bind(const int port) = 0; - virtual bool Listen(int backlog) const = 0; - virtual Socket* Accept() const = 0; - - // Client initialization. - virtual bool Connect(const char* host, const char* port) = 0; - - // Shutdown socket for both read and write. This causes blocking Send and - // Receive calls to exit. After Shutdown the Socket object cannot be used for - // any communication. - virtual bool Shutdown() = 0; - - // Data Transimission - // Return 0 on failure. - virtual int Send(const char* data, int len) const = 0; - virtual int Receive(char* data, int len) const = 0; - - // Set the value of the SO_REUSEADDR socket option. - virtual bool SetReuseAddress(bool reuse_address) = 0; - - virtual bool IsValid() const = 0; - - static bool SetUp(); - static int LastError(); - static uint16_t HToN(uint16_t value); - static uint16_t NToH(uint16_t value); - static uint32_t HToN(uint32_t value); - static uint32_t NToH(uint32_t value); -}; - - } } // namespace v8::internal #endif // V8_PLATFORM_H_ diff --git a/src/platform/socket.cc b/src/platform/socket.cc new file mode 100644 index 0000000..e82c38c --- /dev/null +++ b/src/platform/socket.cc @@ -0,0 +1,223 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "platform/socket.h" + +#if V8_OS_POSIX +#include +#include + +#include +#include + +#include +#endif + +#include + +#include "checks.h" +#include "once.h" + +namespace v8 { +namespace internal { + +#if V8_OS_WIN + +static V8_DECLARE_ONCE(initialize_winsock) = V8_ONCE_INIT; + + +static void InitializeWinsock() { + WSADATA wsa_data; + int result = WSAStartup(MAKEWORD(1, 0), &wsa_data); + CHECK_EQ(0, result); +} + +#endif // V8_OS_WIN + + +Socket::Socket() { +#if V8_OS_WIN + // Be sure to initialize the WinSock DLL first. + CallOnce(&initialize_winsock, &InitializeWinsock); +#endif // V8_OS_WIN + + // Create the native socket handle. + native_handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +} + + +bool Socket::Bind(int port) { + ASSERT_GE(port, 0); + ASSERT_LT(port, 65536); + if (!IsValid()) return false; + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_port = htons(static_cast(port)); + int result = ::bind( + native_handle_, reinterpret_cast(&sin), sizeof(sin)); + return result == 0; +} + + +bool Socket::Listen(int backlog) { + if (!IsValid()) return false; + int result = ::listen(native_handle_, backlog); + return result == 0; +} + + +Socket* Socket::Accept() { + if (!IsValid()) return NULL; + while (true) { + NativeHandle native_handle = ::accept(native_handle_, NULL, NULL); + if (native_handle == kInvalidNativeHandle) { +#if V8_OS_POSIX + if (errno == EINTR) continue; // Retry after signal. +#endif + return NULL; + } + return new Socket(native_handle); + } +} + + +bool Socket::Connect(const char* host, const char* port) { + ASSERT_NE(NULL, host); + ASSERT_NE(NULL, port); + if (!IsValid()) return false; + + // Lookup host and port. + struct addrinfo* info = NULL; + struct addrinfo hint; + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_INET; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = IPPROTO_TCP; + int result = ::getaddrinfo(host, port, &hint, &info); + if (result != 0) { + return false; + } + + // Connect to the host on the given port. + for (struct addrinfo* ai = info; ai != NULL; ai = ai->ai_next) { + // Try to connect using this addr info. + while (true) { + result = ::connect(native_handle_, ai->ai_addr, ai->ai_addrlen); + if (result == 0) { + freeaddrinfo(info); + return true; + } +#if V8_OS_POSIX + if (errno == EINTR) continue; // Retry after signal. +#endif + break; + } + } + freeaddrinfo(info); + return false; +} + + +bool Socket::Shutdown() { + if (!IsValid()) return false; + // Shutdown socket for both read and write. +#if V8_OS_POSIX + int result = ::shutdown(native_handle_, SHUT_RDWR); + ::close(native_handle_); +#elif V8_OS_WIN + int result = ::shutdown(native_handle_, SD_BOTH); + ::closesocket(native_handle_); +#endif + native_handle_ = kInvalidNativeHandle; + return result == 0; +} + + +int Socket::Send(const char* buffer, int length) { + ASSERT(length <= 0 || buffer != NULL); + if (!IsValid()) return 0; + int offset = 0; + while (offset < length) { + int result = ::send(native_handle_, buffer + offset, length - offset, 0); + if (result == 0) { + break; + } else if (result > 0) { + ASSERT(result <= length - offset); + offset += result; + } else { +#if V8_OS_POSIX + if (errno == EINTR) continue; // Retry after signal. +#endif + return 0; + } + } + return offset; +} + + +int Socket::Receive(char* buffer, int length) { + if (!IsValid()) return 0; + if (length <= 0) return 0; + ASSERT_NE(NULL, buffer); + while (true) { + int result = ::recv(native_handle_, buffer, length, 0); + if (result < 0) { +#if V8_OS_POSIX + if (errno == EINTR) continue; // Retry after signal. +#endif + return 0; + } + return result; + } +} + + +bool Socket::SetReuseAddress(bool reuse_address) { + if (!IsValid()) return 0; + int v = reuse_address ? 1 : 0; + int result = ::setsockopt(native_handle_, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&v), sizeof(v)); + return result == 0; +} + + +// static +int Socket::GetLastError() { +#if V8_OS_POSIX + return errno; +#elif V8_OS_WIN + // Be sure to initialize the WinSock DLL first. + CallOnce(&initialize_winsock, &InitializeWinsock); + + // Now we can safely perform WSA calls. + return ::WSAGetLastError(); +#endif +} + +} } // namespace v8::internal diff --git a/src/platform/socket.h b/src/platform/socket.h new file mode 100644 index 0000000..6710692 --- /dev/null +++ b/src/platform/socket.h @@ -0,0 +1,101 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_PLATFORM_SOCKET_H_ +#define V8_PLATFORM_SOCKET_H_ + +#include "globals.h" +#if V8_OS_WIN +#include "win32-headers.h" +#endif + +namespace v8 { +namespace internal { + +// ---------------------------------------------------------------------------- +// Socket +// + +class Socket V8_FINAL { + public: + Socket(); + ~Socket() { Shutdown(); } + + // Server initialization. + bool Bind(int port) V8_WARN_UNUSED_RESULT; + bool Listen(int backlog) V8_WARN_UNUSED_RESULT; + Socket* Accept() V8_WARN_UNUSED_RESULT; + + // Client initialization. + bool Connect(const char* host, const char* port) V8_WARN_UNUSED_RESULT; + + // Shutdown socket for both read and write. This causes blocking Send and + // Receive calls to exit. After |Shutdown()| the Socket object cannot be + // used for any communication. + bool Shutdown(); + + // Data Transimission + // Return 0 on failure. + int Send(const char* buffer, int length) V8_WARN_UNUSED_RESULT; + int Receive(char* buffer, int length) V8_WARN_UNUSED_RESULT; + + // Set the value of the SO_REUSEADDR socket option. + bool SetReuseAddress(bool reuse_address); + + V8_INLINE(bool IsValid()) const V8_WARN_UNUSED_RESULT { + return native_handle_ != kInvalidNativeHandle; + } + + static int GetLastError() V8_WARN_UNUSED_RESULT; + + // The implementation-defined native handle type. +#if V8_OS_POSIX + typedef int NativeHandle; + static const NativeHandle kInvalidNativeHandle = -1; +#elif V8_OS_WIN + typedef SOCKET NativeHandle; + static const NativeHandle kInvalidNativeHandle = INVALID_SOCKET; +#endif + + NativeHandle& native_handle() V8_WARN_UNUSED_RESULT { + return native_handle_; + } + const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT { + return native_handle_; + } + + private: + explicit Socket(NativeHandle native_handle) : native_handle_(native_handle) {} + + NativeHandle native_handle_; + + DISALLOW_COPY_AND_ASSIGN(Socket); +}; + +} } // namespace v8::internal + +#endif // V8_PLATFORM_SOCKET_H_ diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index ce01e3d..75d26b6 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -95,7 +95,7 @@ 'test-reloc-info.cc', 'test-semaphore.cc', 'test-serialize.cc', - 'test-sockets.cc', + 'test-socket.cc', 'test-spaces.cc', 'test-strings.cc', 'test-symbols.cc', diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index c034e48..e09de7d 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -116,7 +116,7 @@ test-log/ProfLazyMode: SKIP # Native Client doesn't support sockets. test-debug/DebuggerAgent: SKIP test-debug/DebuggerAgentProtocolOverflowHeader: SKIP -test-sockets/Socket: SKIP +test-socket/Socket: SKIP # Profiling doesn't work on Native Client. test-cpu-profiler/*: SKIP diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index b41a77a..012face 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -37,7 +37,7 @@ #include "compilation-cache.h" #include "debug.h" #include "deoptimizer.h" -#include "platform.h" +#include "platform/socket.h" #include "stub-cache.h" #include "utils.h" #undef V8_DISABLE_DEPRECATIONS @@ -5947,9 +5947,6 @@ TEST(DebuggerAgent) { bool ok; - // Initialize the socket library. - i::Socket::SetUp(); - // Test starting and stopping the agent without any client connection. debugger->StartAgent("test", kPort1); debugger->StopAgent(); @@ -5958,7 +5955,7 @@ TEST(DebuggerAgent) { ok = debugger->StartAgent("test", kPort2); CHECK(ok); debugger->WaitForAgent(); - i::Socket* client = i::OS::CreateSocket(); + i::Socket* client = new i::Socket; ok = client->Connect("localhost", port2_str); CHECK(ok); // It is important to wait for a message from the agent. Otherwise, @@ -5972,8 +5969,9 @@ TEST(DebuggerAgent) { // Test starting and stopping the agent with the required port already // occoupied. - i::Socket* server = i::OS::CreateSocket(); - server->Bind(kPort3); + i::Socket* server = new i::Socket; + ok = server->Bind(kPort3); + CHECK(ok); debugger->StartAgent("test", kPort3); debugger->StopAgent(); @@ -6014,7 +6012,7 @@ void DebuggerAgentProtocolServerThread::Run() { bool ok; // Create the server socket and bind it to the requested port. - server_ = i::OS::CreateSocket(); + server_ = new i::Socket; CHECK(server_ != NULL); ok = server_->Bind(port_); CHECK(ok); @@ -6044,9 +6042,6 @@ TEST(DebuggerAgentProtocolOverflowHeader) { char port_str[kPortBufferLen]; OS::SNPrintF(i::Vector(port_str, kPortBufferLen), "%d", kPort); - // Initialize the socket library. - i::Socket::SetUp(); - // Create a socket server to receive a debugger agent message. DebuggerAgentProtocolServerThread* server = new DebuggerAgentProtocolServerThread(kPort); @@ -6054,7 +6049,7 @@ TEST(DebuggerAgentProtocolOverflowHeader) { server->WaitForListening(); // Connect. - i::Socket* client = i::OS::CreateSocket(); + i::Socket* client = new i::Socket; CHECK(client != NULL); bool ok = client->Connect(kLocalhost, port_str); CHECK(ok); @@ -6071,7 +6066,8 @@ TEST(DebuggerAgentProtocolOverflowHeader) { buffer[kBufferSize - 3] = '0'; buffer[kBufferSize - 2] = '\r'; buffer[kBufferSize - 1] = '\n'; - client->Send(buffer, kBufferSize); + int result = client->Send(buffer, kBufferSize); + CHECK_EQ(kBufferSize, result); // Short key and long value: X:XXXX....XXXX\r\n. buffer[0] = 'X'; @@ -6081,13 +6077,16 @@ TEST(DebuggerAgentProtocolOverflowHeader) { } buffer[kBufferSize - 2] = '\r'; buffer[kBufferSize - 1] = '\n'; - client->Send(buffer, kBufferSize); + result = client->Send(buffer, kBufferSize); + CHECK_EQ(kBufferSize, result); // Add empty body to request. const char* content_length_zero_header = "Content-Length:0\r\n"; - client->Send(content_length_zero_header, - StrLength(content_length_zero_header)); - client->Send("\r\n", 2); + int length = StrLength(content_length_zero_header); + result = client->Send(content_length_zero_header, length); + CHECK_EQ(length, result); + result = client->Send("\r\n", 2); + CHECK_EQ(2, result); // Wait until data is received. server->Join(); diff --git a/test/cctest/test-sockets.cc b/test/cctest/test-socket.cc similarity index 94% rename from test/cctest/test-sockets.cc rename to test/cctest/test-socket.cc index 87a62ce..47d8b17 100644 --- a/test/cctest/test-sockets.cc +++ b/test/cctest/test-socket.cc @@ -27,6 +27,7 @@ #include "v8.h" #include "platform.h" +#include "platform/socket.h" #include "cctest.h" @@ -69,7 +70,7 @@ void SocketListenerThread::Run() { bool ok; // Create the server socket and bind it to the requested port. - server_ = OS::CreateSocket(); + server_ = new Socket; server_->SetReuseAddress(true); CHECK(server_ != NULL); ok = server_->Bind(port_); @@ -121,7 +122,7 @@ static void SendAndReceive(int port, char *data, int len) { listener->WaitForListening(); // Connect and write some data. - Socket* client = OS::CreateSocket(); + Socket* client = new Socket; CHECK(client != NULL); ok = client->Connect(kLocalhost, port_str); CHECK(ok); @@ -150,12 +151,6 @@ TEST(Socket) { // parallel. static const int kPort = 5859 + FlagDependentPortOffset(); - bool ok; - - // Initialize socket support. - ok = Socket::SetUp(); - CHECK(ok); - // Send and receive some data. static const int kBufferSizeSmall = 20; char small_data[kBufferSizeSmall + 1] = "1234567890abcdefghij"; @@ -179,12 +174,3 @@ TEST(Socket) { SendAndReceive(kPort, large_data, kBufferSizeLarge); delete[] large_data; } - - -TEST(HToNNToH) { - uint16_t x = 1234; - CHECK_EQ(x, Socket::NToH(Socket::HToN(x))); - - uint32_t y = 12345678; - CHECK(y == Socket::NToH(Socket::HToN(y))); -} diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 8548efe..5a5a2ae 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -447,6 +447,8 @@ '../../src/platform/mutex.h', '../../src/platform/semaphore.cc', '../../src/platform/semaphore.h', + '../../src/platform/socket.cc', + '../../src/platform/socket.h', '../../src/preparse-data-format.h', '../../src/preparse-data.cc', '../../src/preparse-data.h', -- 2.7.4