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