Home | History | Annotate | Download | only in platform
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "platform/socket.h"
     29 
     30 #if V8_OS_POSIX
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 
     34 #include <netinet/in.h>
     35 #include <netdb.h>
     36 
     37 #include <unistd.h>
     38 #endif
     39 
     40 #include <cerrno>
     41 
     42 #include "checks.h"
     43 #include "once.h"
     44 
     45 namespace v8 {
     46 namespace internal {
     47 
     48 #if V8_OS_WIN
     49 
     50 static V8_DECLARE_ONCE(initialize_winsock) = V8_ONCE_INIT;
     51 
     52 
     53 static void InitializeWinsock() {
     54   WSADATA wsa_data;
     55   int result = WSAStartup(MAKEWORD(1, 0), &wsa_data);
     56   CHECK_EQ(0, result);
     57 }
     58 
     59 #endif  // V8_OS_WIN
     60 
     61 
     62 Socket::Socket() {
     63 #if V8_OS_WIN
     64   // Be sure to initialize the WinSock DLL first.
     65   CallOnce(&initialize_winsock, &InitializeWinsock);
     66 #endif  // V8_OS_WIN
     67 
     68   // Create the native socket handle.
     69   native_handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     70 }
     71 
     72 
     73 bool Socket::Bind(int port) {
     74   ASSERT_GE(port, 0);
     75   ASSERT_LT(port, 65536);
     76   if (!IsValid()) return false;
     77   struct sockaddr_in sin;
     78   memset(&sin, 0, sizeof(sin));
     79   sin.sin_family = AF_INET;
     80   sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
     81   sin.sin_port = htons(static_cast<uint16_t>(port));
     82   int result = ::bind(
     83       native_handle_, reinterpret_cast<struct sockaddr*>(&sin), sizeof(sin));
     84   return result == 0;
     85 }
     86 
     87 
     88 bool Socket::Listen(int backlog) {
     89   if (!IsValid()) return false;
     90   int result = ::listen(native_handle_, backlog);
     91   return result == 0;
     92 }
     93 
     94 
     95 Socket* Socket::Accept() {
     96   if (!IsValid()) return NULL;
     97   while (true) {
     98     NativeHandle native_handle = ::accept(native_handle_, NULL, NULL);
     99     if (native_handle == kInvalidNativeHandle) {
    100 #if V8_OS_POSIX
    101       if (errno == EINTR) continue;  // Retry after signal.
    102 #endif
    103       return NULL;
    104     }
    105     return new Socket(native_handle);
    106   }
    107 }
    108 
    109 
    110 bool Socket::Connect(const char* host, const char* port) {
    111   ASSERT_NE(NULL, host);
    112   ASSERT_NE(NULL, port);
    113   if (!IsValid()) return false;
    114 
    115   // Lookup host and port.
    116   struct addrinfo* info = NULL;
    117   struct addrinfo hint;
    118   memset(&hint, 0, sizeof(hint));
    119   hint.ai_family = AF_INET;
    120   hint.ai_socktype = SOCK_STREAM;
    121   hint.ai_protocol = IPPROTO_TCP;
    122   int result = ::getaddrinfo(host, port, &hint, &info);
    123   if (result != 0) {
    124     return false;
    125   }
    126 
    127   // Connect to the host on the given port.
    128   for (struct addrinfo* ai = info; ai != NULL; ai = ai->ai_next) {
    129     // Try to connect using this addr info.
    130     while (true) {
    131       result = ::connect(
    132           native_handle_, ai->ai_addr, static_cast<int>(ai->ai_addrlen));
    133       if (result == 0) {
    134         freeaddrinfo(info);
    135         return true;
    136       }
    137 #if V8_OS_POSIX
    138       if (errno == EINTR) continue;  // Retry after signal.
    139 #endif
    140       break;
    141     }
    142   }
    143   freeaddrinfo(info);
    144   return false;
    145 }
    146 
    147 
    148 bool Socket::Shutdown() {
    149   if (!IsValid()) return false;
    150   // Shutdown socket for both read and write.
    151 #if V8_OS_POSIX
    152   int result = ::shutdown(native_handle_, SHUT_RDWR);
    153   ::close(native_handle_);
    154 #elif V8_OS_WIN
    155   int result = ::shutdown(native_handle_, SD_BOTH);
    156   ::closesocket(native_handle_);
    157 #endif
    158   native_handle_ = kInvalidNativeHandle;
    159   return result == 0;
    160 }
    161 
    162 
    163 int Socket::Send(const char* buffer, int length) {
    164   ASSERT(length <= 0 || buffer != NULL);
    165   if (!IsValid()) return 0;
    166   int offset = 0;
    167   while (offset < length) {
    168     int result = ::send(native_handle_, buffer + offset, length - offset, 0);
    169     if (result == 0) {
    170       break;
    171     } else if (result > 0) {
    172       ASSERT(result <= length - offset);
    173       offset += result;
    174     } else {
    175 #if V8_OS_POSIX
    176       if (errno == EINTR) continue;  // Retry after signal.
    177 #endif
    178       return 0;
    179     }
    180   }
    181   return offset;
    182 }
    183 
    184 
    185 int Socket::Receive(char* buffer, int length) {
    186   if (!IsValid()) return 0;
    187   if (length <= 0) return 0;
    188   ASSERT_NE(NULL, buffer);
    189   while (true) {
    190     int result = ::recv(native_handle_, buffer, length, 0);
    191     if (result < 0) {
    192 #if V8_OS_POSIX
    193       if (errno == EINTR) continue;  // Retry after signal.
    194 #endif
    195       return 0;
    196     }
    197     return result;
    198   }
    199 }
    200 
    201 
    202 bool Socket::SetReuseAddress(bool reuse_address) {
    203   if (!IsValid()) return 0;
    204   int v = reuse_address ? 1 : 0;
    205   int result = ::setsockopt(native_handle_, SOL_SOCKET, SO_REUSEADDR,
    206                             reinterpret_cast<char*>(&v), sizeof(v));
    207   return result == 0;
    208 }
    209 
    210 
    211 // static
    212 int Socket::GetLastError() {
    213 #if V8_OS_POSIX
    214   return errno;
    215 #elif V8_OS_WIN
    216   // Be sure to initialize the WinSock DLL first.
    217   CallOnce(&initialize_winsock, &InitializeWinsock);
    218 
    219   // Now we can safely perform WSA calls.
    220   return ::WSAGetLastError();
    221 #endif
    222 }
    223 
    224 } }  // namespace v8::internal
    225