Commit ca955512 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Remove socket implementation from V8.

R=jkummerow@chromium.org, svenpanne@chromium.org

Review URL: https://codereview.chromium.org/281723007

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21316 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 33fba3bf
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <time.h> #include <time.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/socket.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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 <errno.h>
#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, static_cast<int>(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.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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 {
return native_handle_ != kInvalidNativeHandle;
}
static int GetLastError();
// 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() {
return native_handle_;
}
const NativeHandle& native_handle() const {
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_
...@@ -105,7 +105,6 @@ ...@@ -105,7 +105,6 @@
'test-representation.cc', 'test-representation.cc',
'test-semaphore.cc', 'test-semaphore.cc',
'test-serialize.cc', 'test-serialize.cc',
'test-socket.cc',
'test-spaces.cc', 'test-spaces.cc',
'test-strings.cc', 'test-strings.cc',
'test-symbols.cc', 'test-symbols.cc',
......
...@@ -403,13 +403,6 @@ static inline v8::Local<v8::Value> CompileRunWithOrigin( ...@@ -403,13 +403,6 @@ static inline v8::Local<v8::Value> CompileRunWithOrigin(
} }
// Pick a slightly different port to allow tests to be run in parallel.
static inline int FlagDependentPortOffset() {
return ::v8::internal::FLAG_crankshaft == false ? 100 :
::v8::internal::FLAG_always_opt ? 200 : 0;
}
// Helper function that simulates a full new-space in the heap. // Helper function that simulates a full new-space in the heap.
static inline void SimulateFullSpace(v8::internal::NewSpace* space) { static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
int new_linear_size = static_cast<int>( int new_linear_size = static_cast<int>(
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include "frames.h" #include "frames.h"
#include "platform.h" #include "platform.h"
#include "platform/condition-variable.h" #include "platform/condition-variable.h"
#include "platform/socket.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "utils.h" #include "utils.h"
......
// Copyright 2009 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 "v8.h"
#include "platform.h"
#include "platform/socket.h"
#include "cctest.h"
using namespace ::v8::internal;
class SocketListenerThread : public Thread {
public:
SocketListenerThread(int port, int data_size)
: Thread("SocketListenerThread"),
port_(port),
data_size_(data_size),
server_(NULL),
client_(NULL),
listening_(0) {
data_ = new char[data_size_];
}
~SocketListenerThread() {
// Close both sockets.
delete client_;
delete server_;
delete[] data_;
}
void Run();
void WaitForListening() { listening_.Wait(); }
char* data() { return data_; }
private:
int port_;
char* data_;
int data_size_;
Socket* server_; // Server socket used for bind/accept.
Socket* client_; // Single client connection used by the test.
Semaphore listening_; // Signalled when the server socket is in listen mode.
};
void SocketListenerThread::Run() {
bool ok;
// Create the server socket and bind it to the requested port.
server_ = new Socket;
server_->SetReuseAddress(true);
CHECK(server_ != NULL);
ok = server_->Bind(port_);
CHECK(ok);
// Listen for new connections.
ok = server_->Listen(1);
CHECK(ok);
listening_.Signal();
// Accept a connection.
client_ = server_->Accept();
CHECK(client_ != NULL);
// Read the expected niumber of bytes of data.
int bytes_read = 0;
while (bytes_read < data_size_) {
bytes_read += client_->Receive(data_ + bytes_read, data_size_ - bytes_read);
}
}
static bool SendAll(Socket* socket, const char* data, int len) {
int sent_len = 0;
while (sent_len < len) {
int status = socket->Send(data, len);
if (status <= 0) {
return false;
}
sent_len += status;
}
return true;
}
static void SendAndReceive(int port, char *data, int len) {
static const char* kLocalhost = "localhost";
bool ok;
// Make a string with the port number.
const int kPortBuferLen = 6;
char port_str[kPortBuferLen];
OS::SNPrintF(Vector<char>(port_str, kPortBuferLen), "%d", port);
// Create a socket listener.
SocketListenerThread* listener = new SocketListenerThread(port, len);
listener->Start();
listener->WaitForListening();
// Connect and write some data.
Socket* client = new Socket;
CHECK(client != NULL);
ok = client->Connect(kLocalhost, port_str);
CHECK(ok);
// Send all the data.
ok = SendAll(client, data, len);
CHECK(ok);
// Wait until data is received.
listener->Join();
// Check that data received is the same as data send.
for (int i = 0; i < len; i++) {
CHECK(data[i] == listener->data()[i]);
}
// Close the client before the listener to avoid TIME_WAIT issues.
client->Shutdown();
delete client;
delete listener;
}
TEST(Socket) {
// Make sure this port is not used by other tests to allow tests to run in
// parallel.
static const int kPort = 5859 + FlagDependentPortOffset();
// Send and receive some data.
static const int kBufferSizeSmall = 20;
char small_data[kBufferSizeSmall + 1] = "1234567890abcdefghij";
SendAndReceive(kPort, small_data, kBufferSizeSmall);
// Send and receive some more data.
static const int kBufferSizeMedium = 10000;
char* medium_data = new char[kBufferSizeMedium];
for (int i = 0; i < kBufferSizeMedium; i++) {
medium_data[i] = i % 256;
}
SendAndReceive(kPort, medium_data, kBufferSizeMedium);
delete[] medium_data;
// Send and receive even more data.
static const int kBufferSizeLarge = 1000000;
char* large_data = new char[kBufferSizeLarge];
for (int i = 0; i < kBufferSizeLarge; i++) {
large_data[i] = i % 256;
}
SendAndReceive(kPort, large_data, kBufferSizeLarge);
delete[] large_data;
}
...@@ -500,8 +500,6 @@ ...@@ -500,8 +500,6 @@
'../../src/platform/mutex.h', '../../src/platform/mutex.h',
'../../src/platform/semaphore.cc', '../../src/platform/semaphore.cc',
'../../src/platform/semaphore.h', '../../src/platform/semaphore.h',
'../../src/platform/socket.cc',
'../../src/platform/socket.h',
'../../src/preparse-data-format.h', '../../src/preparse-data-format.h',
'../../src/preparse-data.cc', '../../src/preparse-data.cc',
'../../src/preparse-data.h', '../../src/preparse-data.h',
...@@ -867,7 +865,7 @@ ...@@ -867,7 +865,7 @@
}], }],
['_toolset=="target"', { ['_toolset=="target"', {
'libraries': [ 'libraries': [
'-lbacktrace', '-lsocket' '-lbacktrace'
], ],
}], }],
], ],
...@@ -930,7 +928,7 @@ ...@@ -930,7 +928,7 @@
['OS=="solaris"', { ['OS=="solaris"', {
'link_settings': { 'link_settings': {
'libraries': [ 'libraries': [
'-lsocket -lnsl', '-lnsl',
]}, ]},
'sources': [ 'sources': [
'../../src/platform-solaris.cc', '../../src/platform-solaris.cc',
......
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