OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client 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 "debugger/base/debug_socket.h" | |
6 #include <memory.h> | |
7 #include <string.h> | |
8 | |
9 #ifndef _WIN32 | |
10 #include <sys/socket.h> | |
11 #include <netinet/in.h> | |
12 #include <netdb.h> | |
13 #include <netinet/tcp.h> | |
14 #include <errno.h> | |
15 #endif | |
16 | |
17 namespace { | |
18 fd_set* kNoFdSet = NULL; | |
19 const int kMicroPerMilli = 1000; | |
20 const char* kAnyLocalHost = NULL; | |
21 sockaddr* kNoPeerAddress = NULL; | |
22 const int kWaitForOneWriteMs = 1000; | |
23 const int kWaitForOneReadMs = 1000; | |
24 const int kWriteBufferSize = 2048; | |
25 const int kLingerSeconds = 10; | |
26 | |
27 bool InitSocketLib() { | |
28 #ifdef _WIN32 | |
29 WSADATA wsa_data; | |
30 WORD version_requested = MAKEWORD(1, 1); | |
31 return (WSAStartup(version_requested, &wsa_data) == 0); | |
32 #else | |
33 return true; | |
34 #endif | |
35 } | |
36 | |
37 void FreeSocketLib() { | |
38 #ifdef _WIN32 | |
39 WSACleanup(); | |
40 #endif | |
41 } | |
42 | |
43 timeval CreateTimeval(int milliseconds) { | |
44 timeval timeout; | |
45 timeout.tv_sec = 0; | |
46 timeout.tv_usec = milliseconds * kMicroPerMilli; | |
47 return timeout; | |
48 } | |
49 | |
50 sockaddr_in CreateSockAddr(const char* host, int port) { | |
51 sockaddr_in addr; | |
52 memset(&addr, 0, sizeof(addr)); | |
53 addr.sin_family = AF_INET; | |
54 addr.sin_port = htons(port); // Convert port number from host byte order | |
55 // to network byte order. | |
56 if ((NULL == host) || (strlen(host) == 0)) { | |
57 addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
58 } else { | |
59 hostent* hostDescr = gethostbyname(host); | |
60 if (NULL != hostDescr) | |
61 addr.sin_addr.s_addr = | |
62 *(reinterpret_cast<unsigned int**>(hostDescr->h_addr_list)[0]); | |
63 } | |
64 return addr; | |
65 } | |
66 | |
67 void SetSocketOptions(SOCKET sock) { | |
68 if (INVALID_SOCKET != sock) { | |
69 // Setup socket to flush pending data on close. | |
70 linger ling; | |
71 ling.l_onoff = 1; | |
72 // A socket should remain open for kLingerSeconds seconds after | |
73 // a closesocket function call to enable queued data to be sent. | |
74 ling.l_linger = kLingerSeconds; | |
75 setsockopt(sock, | |
76 SOL_SOCKET, | |
77 SO_LINGER, | |
78 reinterpret_cast<char*>(&ling), | |
79 sizeof(ling)); | |
80 // Turn off buffering, to speedup debugger communication. | |
81 int opt = 1; | |
82 setsockopt(sock, | |
83 IPPROTO_TCP, | |
84 TCP_NODELAY, | |
85 reinterpret_cast<char*>(&opt), | |
86 sizeof(opt)); | |
87 } | |
88 } | |
89 } // namespace | |
90 | |
91 namespace debug { | |
92 SocketBase::SocketBase() | |
93 : sock_(INVALID_SOCKET), | |
94 init_success_(false), | |
95 saved_last_error_(kSocketNoError) { | |
96 init_success_ = InitSocketLib(); | |
97 } | |
98 | |
99 SocketBase::~SocketBase() { | |
100 if (init_success_) | |
101 FreeSocketLib(); | |
102 } | |
103 | |
104 int SocketBase::GetLastError() { | |
105 #ifdef _WIN32 | |
106 int res = WSAGetLastError(); | |
107 if (kSocketNoError == res) | |
108 return saved_last_error_; | |
109 return res; | |
110 #else | |
111 return errno; | |
112 #endif | |
113 } | |
114 | |
115 void SocketBase::Close() { | |
116 if (INVALID_SOCKET != sock_) { | |
117 saved_last_error_ = GetLastError(); | |
118 #ifdef _WIN32 | |
119 closesocket(sock_); | |
120 #else | |
121 shutdown(sock_, SHUT_RDWR); | |
122 close(sock_); | |
123 #endif | |
124 sock_ = INVALID_SOCKET; | |
125 } | |
126 } | |
127 | |
128 void SocketBase::ClearSavedLastError() { | |
129 saved_last_error_ = kSocketNoError; | |
130 } | |
131 | |
132 bool ListeningSocket::Listen(int port) { | |
133 ClearSavedLastError(); | |
134 Close(); | |
135 sock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
136 if (INVALID_SOCKET == sock_) | |
137 return false; | |
138 | |
139 // Associate local address with socket. | |
140 sockaddr_in addr = CreateSockAddr(kAnyLocalHost, port); | |
141 if (bind(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) { | |
142 Close(); | |
143 return false; | |
144 } | |
145 // Mark a socket as accepting connections. | |
146 if (listen(sock_, SOMAXCONN) != 0) { | |
147 Close(); | |
148 } | |
149 return (INVALID_SOCKET != sock_); | |
150 } | |
151 | |
152 bool ListeningSocket::Accept(int wait_ms, Socket* new_connection) { | |
153 ClearSavedLastError(); | |
154 fd_set socks; | |
155 FD_ZERO(&socks); | |
156 FD_SET(sock_, &socks); | |
157 | |
158 // Wait for incoming connection. | |
159 timeval timeout = CreateTimeval(wait_ms); | |
160 if (select(sock_ + 1, &socks, kNoFdSet, kNoFdSet, &timeout) < 0) { | |
161 Close(); | |
162 return false; | |
163 } | |
164 // No connection requests. | |
165 if (!FD_ISSET(sock_, &socks)) | |
166 return false; | |
167 | |
168 // Accept a connection request. | |
169 SOCKET sock = accept(sock_, kNoPeerAddress, 0); | |
170 if (INVALID_SOCKET != sock) | |
171 new_connection->AttachTo(sock); | |
172 | |
173 return new_connection->IsConnected(); | |
174 } | |
175 | |
176 void Socket::AttachTo(SOCKET sock) { | |
177 Close(); | |
178 ClearSavedLastError(); | |
179 sock_ = sock; | |
180 SetSocketOptions(sock_); | |
181 } | |
182 | |
183 bool Socket::ConnectTo(const std::string& host, int port) { | |
184 Close(); | |
185 ClearSavedLastError(); | |
186 sock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
187 if (INVALID_SOCKET == sock_) | |
188 return false; | |
189 | |
190 sockaddr_in addr = CreateSockAddr(host.c_str(), port); | |
191 if (connect(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) | |
192 Close(); | |
193 else | |
194 SetSocketOptions(sock_); | |
195 return IsConnected(); | |
196 } | |
197 | |
198 bool Socket::IsConnected() const { | |
199 bool connected = (INVALID_SOCKET != sock_); | |
200 if (!connected && (kSocketNoError == saved_last_error_)) | |
201 const_cast<Socket*>(this)->saved_last_error_ = 666; | |
202 return connected; | |
203 } | |
204 | |
205 size_t Socket::Write(const void* buff, size_t buff_len, int wait_ms) { | |
206 if (!IsConnected()) | |
207 return 0; | |
208 | |
209 ClearSavedLastError(); | |
210 fd_set socks; | |
211 FD_ZERO(&socks); | |
212 FD_SET(sock_, &socks); | |
213 | |
214 // Wait for 'write ready'. | |
215 timeval timeout = CreateTimeval(wait_ms); | |
216 if (select(sock_ + 1, kNoFdSet, &socks, kNoFdSet, &timeout) < 0) { | |
217 Close(); | |
218 return 0; | |
219 } | |
220 int bytes_send = 0; | |
221 if (FD_ISSET(sock_, &socks)) { | |
222 bytes_send = send(sock_, static_cast<const char*>(buff), buff_len, 0); | |
223 if (bytes_send < 0) { | |
224 Close(); | |
225 return 0; | |
226 } | |
227 } | |
228 return bytes_send; | |
229 } | |
230 | |
231 // Blocks until all data has been sent. | |
232 size_t Socket::WriteAll(const void* buff, size_t buff_len) { | |
233 const char* ptr = static_cast<const char*>(buff); | |
234 size_t sent_bytes = 0; | |
235 while (IsConnected() && (buff_len > 0)) { | |
236 size_t wr = Write(ptr, buff_len, kWaitForOneWriteMs); | |
237 sent_bytes += wr; | |
238 buff_len -= wr; | |
239 ptr += wr; | |
240 } | |
241 return sent_bytes; | |
242 } | |
243 | |
244 size_t Socket::WriteAll(const Blob& blob) { | |
245 size_t sent_bytes = 0; | |
246 while (IsConnected() && (sent_bytes < blob.size())) { | |
247 char buff[kWriteBufferSize]; | |
248 size_t bytes_to_send = blob.Peek(sent_bytes, buff, sizeof(buff)); | |
249 sent_bytes += WriteAll(buff, bytes_to_send); | |
250 } | |
251 return sent_bytes; | |
252 } | |
253 | |
254 size_t Socket::Read(void* buff, size_t buff_len, int wait_ms) { | |
255 if (!IsConnected()) | |
256 return 0; | |
257 | |
258 ClearSavedLastError(); | |
259 fd_set socks; | |
260 FD_ZERO(&socks); | |
261 FD_SET(sock_, &socks); | |
262 timeval timeout = CreateTimeval(wait_ms); | |
263 | |
264 // Wait for data. | |
265 if (select(sock_ + 1, &socks, kNoFdSet, kNoFdSet, &timeout) < 0) { | |
266 Close(); | |
267 return 0; | |
268 } | |
269 // No data available. | |
270 if (!FD_ISSET(sock_, &socks)) | |
271 return 0; | |
272 | |
273 ssize_t read_bytes = recv(sock_, static_cast<char*>(buff), buff_len, 0); | |
274 if ((-1 == read_bytes) || (0 == read_bytes)) { | |
275 Close(); | |
276 return 0; | |
277 } | |
278 return read_bytes; | |
279 } | |
280 | |
281 size_t Socket::ReadAll(void* buff, size_t buff_len) { | |
282 size_t total_rd_bytes = 0; | |
283 char* ptr = static_cast<char*>(buff); | |
284 char* buff_end = ptr + buff_len; | |
285 while (IsConnected() && (ptr < buff_end)) { | |
286 size_t rd = Read(ptr, buff_len - total_rd_bytes, kWaitForOneReadMs); | |
287 total_rd_bytes += rd; | |
288 ptr += rd; | |
289 } | |
290 return total_rd_bytes; | |
291 } | |
292 | |
293 } // namespace debug | |
294 | |
OLD | NEW |