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