// 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, 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