OLD | NEW |
| (Empty) |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "platform/socket.h" | |
6 | |
7 #if V8_OS_POSIX | |
8 #include <sys/types.h> | |
9 #include <sys/socket.h> | |
10 | |
11 #include <netinet/in.h> | |
12 #include <netdb.h> | |
13 | |
14 #include <unistd.h> | |
15 #endif | |
16 | |
17 #include <errno.h> | |
18 | |
19 #include "checks.h" | |
20 #include "once.h" | |
21 | |
22 namespace v8 { | |
23 namespace internal { | |
24 | |
25 #if V8_OS_WIN | |
26 | |
27 static V8_DECLARE_ONCE(initialize_winsock) = V8_ONCE_INIT; | |
28 | |
29 | |
30 static void InitializeWinsock() { | |
31 WSADATA wsa_data; | |
32 int result = WSAStartup(MAKEWORD(1, 0), &wsa_data); | |
33 CHECK_EQ(0, result); | |
34 } | |
35 | |
36 #endif // V8_OS_WIN | |
37 | |
38 | |
39 Socket::Socket() { | |
40 #if V8_OS_WIN | |
41 // Be sure to initialize the WinSock DLL first. | |
42 CallOnce(&initialize_winsock, &InitializeWinsock); | |
43 #endif // V8_OS_WIN | |
44 | |
45 // Create the native socket handle. | |
46 native_handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | |
47 } | |
48 | |
49 | |
50 bool Socket::Bind(int port) { | |
51 ASSERT_GE(port, 0); | |
52 ASSERT_LT(port, 65536); | |
53 if (!IsValid()) return false; | |
54 struct sockaddr_in sin; | |
55 memset(&sin, 0, sizeof(sin)); | |
56 sin.sin_family = AF_INET; | |
57 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
58 sin.sin_port = htons(static_cast<uint16_t>(port)); | |
59 int result = ::bind( | |
60 native_handle_, reinterpret_cast<struct sockaddr*>(&sin), sizeof(sin)); | |
61 return result == 0; | |
62 } | |
63 | |
64 | |
65 bool Socket::Listen(int backlog) { | |
66 if (!IsValid()) return false; | |
67 int result = ::listen(native_handle_, backlog); | |
68 return result == 0; | |
69 } | |
70 | |
71 | |
72 Socket* Socket::Accept() { | |
73 if (!IsValid()) return NULL; | |
74 while (true) { | |
75 NativeHandle native_handle = ::accept(native_handle_, NULL, NULL); | |
76 if (native_handle == kInvalidNativeHandle) { | |
77 #if V8_OS_POSIX | |
78 if (errno == EINTR) continue; // Retry after signal. | |
79 #endif | |
80 return NULL; | |
81 } | |
82 return new Socket(native_handle); | |
83 } | |
84 } | |
85 | |
86 | |
87 bool Socket::Connect(const char* host, const char* port) { | |
88 ASSERT_NE(NULL, host); | |
89 ASSERT_NE(NULL, port); | |
90 if (!IsValid()) return false; | |
91 | |
92 // Lookup host and port. | |
93 struct addrinfo* info = NULL; | |
94 struct addrinfo hint; | |
95 memset(&hint, 0, sizeof(hint)); | |
96 hint.ai_family = AF_INET; | |
97 hint.ai_socktype = SOCK_STREAM; | |
98 hint.ai_protocol = IPPROTO_TCP; | |
99 int result = ::getaddrinfo(host, port, &hint, &info); | |
100 if (result != 0) { | |
101 return false; | |
102 } | |
103 | |
104 // Connect to the host on the given port. | |
105 for (struct addrinfo* ai = info; ai != NULL; ai = ai->ai_next) { | |
106 // Try to connect using this addr info. | |
107 while (true) { | |
108 result = ::connect( | |
109 native_handle_, ai->ai_addr, static_cast<int>(ai->ai_addrlen)); | |
110 if (result == 0) { | |
111 freeaddrinfo(info); | |
112 return true; | |
113 } | |
114 #if V8_OS_POSIX | |
115 if (errno == EINTR) continue; // Retry after signal. | |
116 #endif | |
117 break; | |
118 } | |
119 } | |
120 freeaddrinfo(info); | |
121 return false; | |
122 } | |
123 | |
124 | |
125 bool Socket::Shutdown() { | |
126 if (!IsValid()) return false; | |
127 // Shutdown socket for both read and write. | |
128 #if V8_OS_POSIX | |
129 int result = ::shutdown(native_handle_, SHUT_RDWR); | |
130 ::close(native_handle_); | |
131 #elif V8_OS_WIN | |
132 int result = ::shutdown(native_handle_, SD_BOTH); | |
133 ::closesocket(native_handle_); | |
134 #endif | |
135 native_handle_ = kInvalidNativeHandle; | |
136 return result == 0; | |
137 } | |
138 | |
139 | |
140 int Socket::Send(const char* buffer, int length) { | |
141 ASSERT(length <= 0 || buffer != NULL); | |
142 if (!IsValid()) return 0; | |
143 int offset = 0; | |
144 while (offset < length) { | |
145 int result = ::send(native_handle_, buffer + offset, length - offset, 0); | |
146 if (result == 0) { | |
147 break; | |
148 } else if (result > 0) { | |
149 ASSERT(result <= length - offset); | |
150 offset += result; | |
151 } else { | |
152 #if V8_OS_POSIX | |
153 if (errno == EINTR) continue; // Retry after signal. | |
154 #endif | |
155 return 0; | |
156 } | |
157 } | |
158 return offset; | |
159 } | |
160 | |
161 | |
162 int Socket::Receive(char* buffer, int length) { | |
163 if (!IsValid()) return 0; | |
164 if (length <= 0) return 0; | |
165 ASSERT_NE(NULL, buffer); | |
166 while (true) { | |
167 int result = ::recv(native_handle_, buffer, length, 0); | |
168 if (result < 0) { | |
169 #if V8_OS_POSIX | |
170 if (errno == EINTR) continue; // Retry after signal. | |
171 #endif | |
172 return 0; | |
173 } | |
174 return result; | |
175 } | |
176 } | |
177 | |
178 | |
179 bool Socket::SetReuseAddress(bool reuse_address) { | |
180 if (!IsValid()) return 0; | |
181 int v = reuse_address ? 1 : 0; | |
182 int result = ::setsockopt(native_handle_, SOL_SOCKET, SO_REUSEADDR, | |
183 reinterpret_cast<char*>(&v), sizeof(v)); | |
184 return result == 0; | |
185 } | |
186 | |
187 | |
188 // static | |
189 int Socket::GetLastError() { | |
190 #if V8_OS_POSIX | |
191 return errno; | |
192 #elif V8_OS_WIN | |
193 // Be sure to initialize the WinSock DLL first. | |
194 CallOnce(&initialize_winsock, &InitializeWinsock); | |
195 | |
196 // Now we can safely perform WSA calls. | |
197 return ::WSAGetLastError(); | |
198 #endif | |
199 } | |
200 | |
201 } } // namespace v8::internal | |
OLD | NEW |