Commit 8f8222e9 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

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
parent 2b7efe05
......@@ -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<char>(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;
}
......
......@@ -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<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(Socket* conn) {
int received;
// Read header.
......@@ -245,7 +268,7 @@ SmartArrayPointer<char> 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<char>();
}
......@@ -307,7 +330,7 @@ SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
char* buffer = NewArray<char>(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<char>();
}
buffer[content_length] = '\0';
......@@ -316,7 +339,7 @@ SmartArrayPointer<char> 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<uint16_t> 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<char>(buffer, kBufferSize),
"%s: %d\r\n", kContentLength, utf8_len);
conn->Send(buffer, len);
int len = OS::SNPrintF(Vector<char>(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<char>(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<v8::String> 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<char>(buffer, kBufferSize),
"Content-Length: %d\r\n", utf8_request.length());
conn->Send(buffer, len);
int len = OS::SNPrintF(Vector<char>(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<char>(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);
......
......@@ -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<char> ReceiveMessage(const Socket* conn);
static bool SendConnectMessage(const Socket* conn,
const char* embedding_host);
static bool SendMessage(const Socket* conn, const Vector<uint16_t> message);
static bool SendMessage(const Socket* conn,
const v8::Handle<v8::String> message);
static int ReceiveAll(const Socket* conn, char* data, int len);
static SmartArrayPointer<char> ReceiveMessage(Socket* conn);
static bool SendConnectMessage(Socket* conn, const char* embedding_host);
static bool SendMessage(Socket* conn, const Vector<uint16_t> message);
static bool SendMessage(Socket* conn, const v8::Handle<v8::String> message);
static int ReceiveAll(Socket* conn, char* data, int len);
};
} } // namespace v8::internal
......
......@@ -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;
}
......
......@@ -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<struct sockaddr *>(&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
......@@ -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<struct sockaddr *>(&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<int>(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<char*>(&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
......
......@@ -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<StackFrame> 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_
// 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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <cerrno>
#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<uint16_t>(port));
int result = ::bind(
native_handle_, reinterpret_cast<struct sockaddr*>(&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<char*>(&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
// 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_
......@@ -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',
......
......@@ -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
......
......@@ -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<char>(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();
......
......@@ -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)));
}
......@@ -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',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment