1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <errno.h>
8 : #include <stdlib.h>
9 : #include <string.h>
10 :
11 : #include <algorithm>
12 : #include <string>
13 :
14 : #include "native_client/src/include/nacl_scoped_ptr.h"
15 : #include "native_client/src/include/portability_sockets.h"
16 : #include "native_client/src/shared/platform/nacl_log.h"
17 : #include "native_client/src/trusted/debug_stub/platform.h"
18 : #include "native_client/src/trusted/debug_stub/transport.h"
19 : #include "native_client/src/trusted/debug_stub/util.h"
20 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
21 :
22 : using gdb_rsp::stringvec;
23 : using gdb_rsp::StringSplit;
24 :
25 : #if NACL_WINDOWS
26 : typedef int socklen_t;
27 : #endif
28 :
29 : namespace port {
30 :
31 : class Transport : public ITransport {
32 : public:
33 : Transport()
34 : : buf_(new char[kBufSize]),
35 : pos_(0),
36 : size_(0) {
37 : handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
38 : #if NACL_WINDOWS
39 : CreateSocketEvent();
40 : #endif
41 : }
42 :
43 58 : explicit Transport(NaClSocketHandle s)
44 : : buf_(new char[kBufSize]),
45 : pos_(0),
46 : size_(0),
47 87 : handle_(s) {
48 : #if NACL_WINDOWS
49 : CreateSocketEvent();
50 : #endif
51 58 : }
52 :
53 56 : ~Transport() {
54 42 : if (handle_ != NACL_INVALID_SOCKET) NaClCloseSocket(handle_);
55 : #if NACL_WINDOWS
56 : if (!WSACloseEvent(socket_event_)) {
57 : NaClLog(LOG_FATAL,
58 : "Transport::~Transport: Failed to close socket event\n");
59 : }
60 : #endif
61 56 : }
62 :
63 : #if NACL_WINDOWS
64 : void CreateSocketEvent() {
65 : socket_event_ = WSACreateEvent();
66 : if (socket_event_ == WSA_INVALID_EVENT) {
67 : NaClLog(LOG_FATAL,
68 : "Transport::CreateSocketEvent: Failed to create socket event\n");
69 : }
70 : // Listen for close events in order to handle them correctly.
71 : // Additionally listen for read readiness as WSAEventSelect sets the socket
72 : // to non-blocking mode.
73 : // http://msdn.microsoft.com/en-us/library/windows/desktop/ms738547(v=vs.85).aspx
74 : if (WSAEventSelect(
75 : handle_, socket_event_, FD_CLOSE | FD_READ) == SOCKET_ERROR) {
76 : NaClLog(LOG_FATAL,
77 : "Transport::CreateSocketEvent: Failed to bind event to socket\n");
78 : }
79 : }
80 : #endif
81 :
82 : // Read from this transport, return true on success.
83 : virtual bool Read(void *ptr, int32_t len);
84 :
85 : // Write to this transport, return true on success.
86 : virtual bool Write(const void *ptr, int32_t len);
87 :
88 : // Return true if there is data to read.
89 : virtual bool IsDataAvailable() {
90 1 : if (pos_ < size_) {
91 1 : return true;
92 : }
93 0 : fd_set fds;
94 :
95 0 : FD_ZERO(&fds);
96 0 : FD_SET(handle_, &fds);
97 :
98 : // We want a "non-blocking" check
99 0 : struct timeval timeout;
100 0 : timeout.tv_sec = 0;
101 0 : timeout.tv_usec = 0;
102 :
103 : // Check if this file handle can select on read
104 0 : int cnt = select(static_cast<int>(handle_) + 1, &fds, 0, 0, &timeout);
105 :
106 : // If we are ready, or if there is an error. We return true
107 : // on error, to let the next IO request fail.
108 0 : if (cnt != 0) return true;
109 :
110 0 : return false;
111 1 : }
112 :
113 : virtual void WaitForDebugStubEvent(struct NaClApp *nap,
114 : bool ignore_input_from_gdb);
115 :
116 : // On windows, the header that defines this has other definition
117 : // colitions, so we define it outselves just in case
118 : #ifndef SD_BOTH
119 : #define SD_BOTH 2
120 : #endif
121 :
122 : virtual void Disconnect() {
123 : // Shutdown the conneciton in both diections. This should
124 : // always succeed, and nothing we can do if this fails.
125 30 : (void) ::shutdown(handle_, SD_BOTH);
126 30 : }
127 :
128 : protected:
129 : // Copy buffered data to *dst up to len bytes and update dst and len.
130 : void CopyFromBuffer(char **dst, int32_t *len);
131 :
132 : // Read available data from the socket. Return false on EOF or error.
133 : bool ReadSomeData();
134 :
135 : static const int kBufSize = 4096;
136 : nacl::scoped_array<char> buf_;
137 : int32_t pos_;
138 : int32_t size_;
139 : NaClSocketHandle handle_;
140 : #if NACL_WINDOWS
141 : HANDLE socket_event_;
142 : #endif
143 : };
144 :
145 23738 : void Transport::CopyFromBuffer(char **dst, int32_t *len) {
146 23738 : int32_t copy_bytes = std::min(*len, size_ - pos_);
147 23738 : memcpy(*dst, buf_.get() + pos_, copy_bytes);
148 23738 : pos_ += copy_bytes;
149 23738 : *len -= copy_bytes;
150 23738 : *dst += copy_bytes;
151 23738 : }
152 :
153 : bool Transport::ReadSomeData() {
154 1793 : while (true) {
155 1793 : int result = ::recv(handle_, buf_.get() + size_, kBufSize - size_, 0);
156 1793 : if (result > 0) {
157 1764 : size_ += result;
158 1764 : return true;
159 : }
160 29 : if (result == 0)
161 24 : return false;
162 : #if NACL_WINDOWS
163 : // WSAEventSelect sets socket to non-blocking mode. This is essential
164 : // for socket event notification to work, there is no workaround.
165 : // See remarks section at the page
166 : // http://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx
167 : if (NaClSocketGetLastError() == WSAEWOULDBLOCK) {
168 : if (WaitForSingleObject(socket_event_, INFINITE) == WAIT_FAILED) {
169 : NaClLog(LOG_FATAL,
170 : "Transport::ReadSomeData: Failed to wait on socket event\n");
171 : }
172 : if (!ResetEvent(socket_event_)) {
173 : NaClLog(LOG_FATAL,
174 : "Transport::ReadSomeData: Failed to reset socket event\n");
175 : }
176 : continue;
177 : }
178 : #endif
179 5 : if (NaClSocketGetLastError() != EINTR)
180 5 : return false;
181 0 : }
182 1793 : }
183 :
184 23767 : bool Transport::Read(void *ptr, int32_t len) {
185 23767 : char *dst = static_cast<char *>(ptr);
186 23767 : if (pos_ < size_) {
187 21986 : CopyFromBuffer(&dst, &len);
188 21986 : }
189 49286 : while (len > 0) {
190 1781 : pos_ = 0;
191 1781 : size_ = 0;
192 1781 : if (!ReadSomeData()) {
193 29 : return false;
194 : }
195 1752 : CopyFromBuffer(&dst, &len);
196 1752 : }
197 23738 : return true;
198 23767 : }
199 :
200 2349 : bool Transport::Write(const void *ptr, int32_t len) {
201 2349 : const char *src = static_cast<const char *>(ptr);
202 7047 : while (len > 0) {
203 2349 : int result = ::send(handle_, src, len, 0);
204 2349 : if (result > 0) {
205 2349 : src += result;
206 2349 : len -= result;
207 2349 : continue;
208 : }
209 0 : if (result == 0) {
210 0 : return false;
211 : }
212 0 : if (NaClSocketGetLastError() != EINTR) {
213 0 : return false;
214 : }
215 0 : }
216 2349 : return true;
217 2349 : }
218 :
219 148 : void Transport::WaitForDebugStubEvent(struct NaClApp *nap,
220 148 : bool ignore_input_from_gdb) {
221 148 : bool wait = true;
222 : // If we are told to ignore messages from gdb, we will exit from this
223 : // function only if new data is sent by gdb.
224 296 : if ((pos_ < size_ && !ignore_input_from_gdb) ||
225 : nap->faulted_thread_count > 0) {
226 : // Clear faulted thread events to save debug stub loop iterations.
227 84 : wait = false;
228 84 : }
229 : #if NACL_WINDOWS
230 : HANDLE handles[2];
231 : handles[0] = nap->faulted_thread_event;
232 : handles[1] = socket_event_;
233 : int count = size_ < kBufSize ? 2 : 1;
234 : int result = WaitForMultipleObjects(count, handles, FALSE,
235 : wait ? INFINITE : 0);
236 : if (result == WAIT_OBJECT_0 + 1) {
237 : if (!ResetEvent(socket_event_)) {
238 : NaClLog(LOG_FATAL,
239 : "Transport::WaitForDebugStubEvent: "
240 : "Failed to reset socket event\n");
241 : }
242 : return;
243 : }
244 : if (result == WAIT_TIMEOUT || result == WAIT_OBJECT_0)
245 : return;
246 : NaClLog(LOG_FATAL,
247 : "Transport::WaitForDebugStubEvent: Wait for events failed\n");
248 : #else
249 148 : fd_set fds;
250 :
251 148 : FD_ZERO(&fds);
252 296 : FD_SET(nap->faulted_thread_fd_read, &fds);
253 148 : int max_fd = nap->faulted_thread_fd_read;
254 148 : if (size_ < kBufSize) {
255 296 : FD_SET(handle_, &fds);
256 148 : max_fd = std::max(max_fd, handle_);
257 148 : }
258 :
259 148 : int ret;
260 : // We don't need sleep-polling on Linux now, so we set either zero or infinite
261 : // timeout.
262 148 : if (wait) {
263 64 : ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
264 64 : } else {
265 84 : struct timeval timeout;
266 84 : timeout.tv_sec = 0;
267 84 : timeout.tv_usec = 0;
268 84 : ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
269 : }
270 148 : if (ret < 0) {
271 0 : NaClLog(LOG_FATAL,
272 : "Transport::WaitForDebugStubEvent: Failed to wait for "
273 : "debug stub event\n");
274 0 : }
275 :
276 148 : if (ret > 0) {
277 84 : if (FD_ISSET(nap->faulted_thread_fd_read, &fds)) {
278 83 : char buf[16];
279 83 : if (read(nap->faulted_thread_fd_read, &buf, sizeof(buf)) < 0) {
280 0 : NaClLog(LOG_FATAL,
281 : "Transport::WaitForDebugStubEvent: Failed to read from "
282 : "debug stub event pipe fd\n");
283 0 : }
284 83 : }
285 84 : if (FD_ISSET(handle_, &fds))
286 12 : ReadSomeData();
287 84 : }
288 : #endif
289 148 : }
290 :
291 : // Convert string in the form of [addr][:port] where addr is a
292 : // IPv4 address or host name, and port is a 16b tcp/udp port.
293 : // Both portions are optional, and only the portion of the address
294 : // provided is updated. Values are provided in network order.
295 17 : static bool StringToIPv4(const std::string &instr, uint32_t *addr,
296 17 : uint16_t *port) {
297 : // Make a copy so the are unchanged unless we succeed
298 17 : uint32_t outaddr = *addr;
299 17 : uint16_t outport = *port;
300 :
301 : // Substrings of the full ADDR:PORT
302 17 : std::string addrstr;
303 17 : std::string portstr;
304 :
305 : // We should either have one or two tokens in the form of:
306 : // IP - IP, NUL
307 : // IP: - IP, NUL
308 : // :PORT - NUL, PORT
309 : // IP:PORT - IP, PORT
310 :
311 : // Search for the port marker
312 34 : size_t portoff = instr.find(':');
313 :
314 : // If we found a ":" before the end, get both substrings
315 51 : if ((portoff != std::string::npos) && (portoff + 1 < instr.size())) {
316 51 : addrstr = instr.substr(0, portoff);
317 51 : portstr = instr.substr(portoff + 1, std::string::npos);
318 17 : } else {
319 : // otherwise the entire string is the addr portion.
320 0 : addrstr = instr;
321 0 : portstr = "";
322 : }
323 :
324 : // If the address portion was provided, update it
325 34 : if (addrstr.size()) {
326 : // Special case 0.0.0.0 which means any IPv4 interface
327 34 : if (addrstr == "0.0.0.0") {
328 0 : outaddr = 0;
329 0 : } else {
330 51 : struct hostent *host = gethostbyname(addrstr.data());
331 :
332 : // Check that we found an IPv4 host
333 34 : if ((NULL == host) || (AF_INET != host->h_addrtype)) return false;
334 :
335 : // Make sure the IP list isn't empty.
336 17 : if (0 == host->h_addr_list[0]) return false;
337 :
338 : // Use the first address in the array of address pointers.
339 17 : uint32_t **addrarray = reinterpret_cast<uint32_t**>(host->h_addr_list);
340 17 : outaddr = *addrarray[0];
341 : }
342 17 : }
343 :
344 : // if the port portion was provided, then update it
345 34 : if (portstr.size()) {
346 51 : int val = atoi(portstr.data());
347 34 : if ((val < 0) || (val > 65535)) return false;
348 34 : outport = ntohs(static_cast<uint16_t>(val));
349 17 : }
350 :
351 : // We haven't failed, so set the values
352 17 : *addr = outaddr;
353 17 : *port = outport;
354 51 : return true;
355 17 : }
356 :
357 17 : static bool BuildSockAddr(const char *addr, struct sockaddr_in *sockaddr) {
358 34 : std::string addrstr = addr;
359 17 : uint32_t *pip = reinterpret_cast<uint32_t*>(&sockaddr->sin_addr.s_addr);
360 17 : uint16_t *pport = reinterpret_cast<uint16_t*>(&sockaddr->sin_port);
361 :
362 17 : sockaddr->sin_family = AF_INET;
363 17 : return StringToIPv4(addrstr, pip, pport);
364 17 : }
365 :
366 34 : SocketBinding::SocketBinding(NaClSocketHandle socket_handle)
367 17 : : socket_handle_(socket_handle) {
368 34 : }
369 :
370 17 : SocketBinding *SocketBinding::Bind(const char *addr) {
371 17 : NaClSocketHandle socket_handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
372 17 : if (socket_handle == NACL_INVALID_SOCKET) {
373 0 : NaClLog(LOG_ERROR, "Failed to create socket.\n");
374 0 : return NULL;
375 : }
376 17 : struct sockaddr_in saddr;
377 : // Clearing sockaddr_in first appears to be necessary on Mac OS X.
378 17 : memset(&saddr, 0, sizeof(saddr));
379 17 : socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
380 17 : saddr.sin_family = AF_INET;
381 17 : saddr.sin_addr.s_addr = htonl(0x7F000001);
382 17 : saddr.sin_port = htons(4014);
383 :
384 : // Override portions address that are provided
385 34 : if (addr) BuildSockAddr(addr, &saddr);
386 :
387 : #if NACL_WINDOWS
388 : // On Windows, SO_REUSEADDR has a different meaning than on POSIX systems.
389 : // SO_REUSEADDR allows hijacking of an open socket by another process.
390 : // The SO_EXCLUSIVEADDRUSE flag prevents this behavior.
391 : // See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx
392 : //
393 : // Additionally, unlike POSIX, TCP server sockets can be bound to
394 : // ports in the TIME_WAIT state, without setting SO_REUSEADDR.
395 : int exclusive_address = 1;
396 : if (setsockopt(socket_handle, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
397 : reinterpret_cast<char *>(&exclusive_address),
398 : sizeof(exclusive_address))) {
399 : NaClLog(LOG_WARNING, "Failed to set SO_EXCLUSIVEADDRUSE option.\n");
400 : }
401 : #else
402 : // On POSIX, this is necessary to ensure that the TCP port is released
403 : // promptly when sel_ldr exits. Without this, the TCP port might
404 : // only be released after a timeout, and later processes can fail
405 : // to bind it.
406 17 : int reuse_address = 1;
407 17 : if (setsockopt(socket_handle, SOL_SOCKET, SO_REUSEADDR,
408 : reinterpret_cast<char *>(&reuse_address),
409 : sizeof(reuse_address))) {
410 0 : NaClLog(LOG_WARNING, "Failed to set SO_REUSEADDR option.\n");
411 0 : }
412 : #endif
413 :
414 17 : struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
415 17 : if (bind(socket_handle, psaddr, addrlen)) {
416 0 : NaClLog(LOG_ERROR, "Failed to bind server.\n");
417 0 : return NULL;
418 : }
419 :
420 17 : if (listen(socket_handle, 1)) {
421 0 : NaClLog(LOG_ERROR, "Failed to listen.\n");
422 0 : return NULL;
423 : }
424 34 : return new SocketBinding(socket_handle);
425 17 : }
426 :
427 : ITransport *SocketBinding::AcceptConnection() {
428 29 : NaClSocketHandle socket = ::accept(socket_handle_, NULL, 0);
429 29 : if (socket != NACL_INVALID_SOCKET) {
430 : // Do not delay sending small packets. This significantly speeds up
431 : // remote debugging. Debug stub uses buffering to send outgoing packets so
432 : // they are not split into more TCP packets than necessary.
433 29 : int nodelay = 1;
434 29 : if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
435 : reinterpret_cast<char *>(&nodelay),
436 : sizeof(nodelay))) {
437 0 : NaClLog(LOG_WARNING, "Failed to set TCP_NODELAY option.\n");
438 0 : }
439 58 : return new Transport(socket);
440 : }
441 0 : return NULL;
442 29 : }
443 :
444 : uint16_t SocketBinding::GetBoundPort() {
445 17 : struct sockaddr_in saddr;
446 17 : struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
447 : // Clearing sockaddr_in first appears to be necessary on Mac OS X.
448 17 : memset(&saddr, 0, sizeof(saddr));
449 17 : socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
450 17 : if (::getsockname(socket_handle_, psaddr, &addrlen)) {
451 0 : NaClLog(LOG_ERROR, "Failed to retrieve bound address.\n");
452 0 : return 0;
453 : }
454 17 : return ntohs(saddr.sin_port);
455 17 : }
456 :
457 : } // namespace port
|