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 31 : explicit Transport(NaClSocketHandle s)
44 31 : : buf_(new char[kBufSize]),
45 : pos_(0),
46 : size_(0),
47 62 : handle_(s) {
48 : #if NACL_WINDOWS
49 : CreateSocketEvent();
50 : #endif
51 31 : }
52 :
53 45 : ~Transport() {
54 15 : 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 30 : }
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 1 : virtual bool IsDataAvailable() {
90 1 : if (pos_ < size_) {
91 0 : return true;
92 : }
93 : fd_set fds;
94 :
95 1 : FD_ZERO(&fds);
96 1 : FD_SET(handle_, &fds);
97 :
98 : // We want a "non-blocking" check
99 : struct timeval timeout;
100 1 : timeout.tv_sec = 0;
101 1 : timeout.tv_usec = 0;
102 :
103 : // Check if this file handle can select on read
104 1 : 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 1 : if (cnt != 0) return true;
109 :
110 0 : return false;
111 : }
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 30 : 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 16065 : void Transport::CopyFromBuffer(char **dst, int32_t *len) {
146 16065 : int32_t copy_bytes = std::min(*len, size_ - pos_);
147 16065 : memcpy(*dst, buf_.get() + pos_, copy_bytes);
148 16065 : pos_ += copy_bytes;
149 16065 : *len -= copy_bytes;
150 16065 : *dst += copy_bytes;
151 16065 : }
152 :
153 1625 : bool Transport::ReadSomeData() {
154 0 : while (true) {
155 1625 : int result = ::recv(handle_, buf_.get() + size_, kBufSize - size_, 0);
156 1625 : if (result > 0) {
157 1596 : size_ += result;
158 1596 : return true;
159 : }
160 29 : if (result == 0)
161 28 : 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 1 : if (NaClSocketGetLastError() != EINTR)
180 1 : return false;
181 : }
182 : }
183 :
184 16093 : bool Transport::Read(void *ptr, int32_t len) {
185 16093 : char *dst = static_cast<char *>(ptr);
186 16093 : if (pos_ < size_) {
187 14486 : CopyFromBuffer(&dst, &len);
188 : }
189 33765 : while (len > 0) {
190 1607 : pos_ = 0;
191 1607 : size_ = 0;
192 1607 : if (!ReadSomeData()) {
193 28 : return false;
194 : }
195 1579 : CopyFromBuffer(&dst, &len);
196 : }
197 16065 : return true;
198 : }
199 :
200 1805 : bool Transport::Write(const void *ptr, int32_t len) {
201 1805 : const char *src = static_cast<const char *>(ptr);
202 5415 : while (len > 0) {
203 1805 : int result = ::send(handle_, src, len, 0);
204 1805 : if (result > 0) {
205 1805 : src += result;
206 1805 : len -= result;
207 1805 : continue;
208 : }
209 0 : if (result == 0) {
210 0 : return false;
211 : }
212 0 : if (NaClSocketGetLastError() != EINTR) {
213 0 : return false;
214 : }
215 : }
216 1805 : return true;
217 : }
218 :
219 10344 : void Transport::WaitForDebugStubEvent(struct NaClApp *nap,
220 : bool ignore_input_from_gdb) {
221 10344 : 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 10344 : 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 10282 : wait = false;
228 : }
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 : fd_set fds;
250 :
251 10344 : FD_ZERO(&fds);
252 10344 : FD_SET(nap->faulted_thread_fd_read, &fds);
253 10344 : int max_fd = nap->faulted_thread_fd_read;
254 10344 : if (size_ < kBufSize) {
255 10344 : FD_SET(handle_, &fds);
256 10344 : max_fd = std::max(max_fd, handle_);
257 : }
258 :
259 : int ret;
260 : // We don't need sleep-polling on Linux now, so we set either zero or infinite
261 : // timeout.
262 10344 : if (wait) {
263 62 : ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
264 : } else {
265 : struct timeval timeout;
266 10282 : timeout.tv_sec = 0;
267 10282 : timeout.tv_usec = 0;
268 10282 : ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
269 : }
270 10344 : if (ret < 0) {
271 : NaClLog(LOG_FATAL,
272 : "Transport::WaitForDebugStubEvent: Failed to wait for "
273 0 : "debug stub event\n");
274 : }
275 :
276 10344 : if (ret > 0) {
277 85 : if (FD_ISSET(nap->faulted_thread_fd_read, &fds)) {
278 : char buf[16];
279 84 : if (read(nap->faulted_thread_fd_read, &buf, sizeof(buf)) < 0) {
280 : NaClLog(LOG_FATAL,
281 : "Transport::WaitForDebugStubEvent: Failed to read from "
282 0 : "debug stub event pipe fd\n");
283 : }
284 : }
285 85 : if (FD_ISSET(handle_, &fds))
286 18 : ReadSomeData();
287 : }
288 : #endif
289 10344 : }
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 19 : static bool StringToIPv4(const std::string &instr, uint32_t *addr,
296 : uint16_t *port) {
297 : // Make a copy so the are unchanged unless we succeed
298 19 : uint32_t outaddr = *addr;
299 19 : uint16_t outport = *port;
300 :
301 : // Substrings of the full ADDR:PORT
302 19 : std::string addrstr;
303 19 : 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 19 : size_t portoff = instr.find(':');
313 :
314 : // If we found a ":" before the end, get both substrings
315 19 : if ((portoff != std::string::npos) && (portoff + 1 < instr.size())) {
316 19 : addrstr = instr.substr(0, portoff);
317 19 : portstr = instr.substr(portoff + 1, std::string::npos);
318 : } 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 19 : if (addrstr.size()) {
326 : // Special case 0.0.0.0 which means any IPv4 interface
327 19 : if (addrstr == "0.0.0.0") {
328 0 : outaddr = 0;
329 : } else {
330 19 : struct hostent *host = gethostbyname(addrstr.data());
331 :
332 : // Check that we found an IPv4 host
333 19 : if ((NULL == host) || (AF_INET != host->h_addrtype)) return false;
334 :
335 : // Make sure the IP list isn't empty.
336 19 : if (0 == host->h_addr_list[0]) return false;
337 :
338 : // Use the first address in the array of address pointers.
339 19 : uint32_t **addrarray = reinterpret_cast<uint32_t**>(host->h_addr_list);
340 19 : outaddr = *addrarray[0];
341 : }
342 : }
343 :
344 : // if the port portion was provided, then update it
345 19 : if (portstr.size()) {
346 19 : int val = atoi(portstr.data());
347 19 : if ((val < 0) || (val > 65535)) return false;
348 19 : outport = ntohs(static_cast<uint16_t>(val));
349 : }
350 :
351 : // We haven't failed, so set the values
352 19 : *addr = outaddr;
353 19 : *port = outport;
354 19 : return true;
355 : }
356 :
357 19 : static bool BuildSockAddr(const char *addr, struct sockaddr_in *sockaddr) {
358 19 : std::string addrstr = addr;
359 19 : uint32_t *pip = reinterpret_cast<uint32_t*>(&sockaddr->sin_addr.s_addr);
360 19 : uint16_t *pport = reinterpret_cast<uint16_t*>(&sockaddr->sin_port);
361 :
362 19 : sockaddr->sin_family = AF_INET;
363 19 : return StringToIPv4(addrstr, pip, pport);
364 : }
365 :
366 19 : SocketBinding::SocketBinding(NaClSocketHandle socket_handle)
367 19 : : socket_handle_(socket_handle) {
368 19 : }
369 :
370 19 : SocketBinding *SocketBinding::Bind(const char *addr) {
371 19 : NaClSocketHandle socket_handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
372 19 : if (socket_handle == NACL_INVALID_SOCKET) {
373 0 : NaClLog(LOG_ERROR, "Failed to create socket.\n");
374 0 : return NULL;
375 : }
376 : struct sockaddr_in saddr;
377 : // Clearing sockaddr_in first appears to be necessary on Mac OS X.
378 19 : memset(&saddr, 0, sizeof(saddr));
379 19 : socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
380 19 : saddr.sin_family = AF_INET;
381 19 : saddr.sin_addr.s_addr = htonl(0x7F000001);
382 19 : saddr.sin_port = htons(4014);
383 :
384 : // Override portions address that are provided
385 19 : 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 19 : int reuse_address = 1;
407 19 : if (setsockopt(socket_handle, SOL_SOCKET, SO_REUSEADDR,
408 : reinterpret_cast<char *>(&reuse_address),
409 19 : sizeof(reuse_address))) {
410 0 : NaClLog(LOG_WARNING, "Failed to set SO_REUSEADDR option.\n");
411 : }
412 : #endif
413 :
414 19 : struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
415 19 : if (bind(socket_handle, psaddr, addrlen)) {
416 0 : NaClLog(LOG_ERROR, "Failed to bind server.\n");
417 0 : return NULL;
418 : }
419 :
420 19 : if (listen(socket_handle, 1)) {
421 0 : NaClLog(LOG_ERROR, "Failed to listen.\n");
422 0 : return NULL;
423 : }
424 19 : return new SocketBinding(socket_handle);
425 : }
426 :
427 34 : ITransport *SocketBinding::AcceptConnection() {
428 34 : NaClSocketHandle socket = ::accept(socket_handle_, NULL, 0);
429 31 : 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 31 : int nodelay = 1;
434 31 : if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
435 : reinterpret_cast<char *>(&nodelay),
436 31 : sizeof(nodelay))) {
437 0 : NaClLog(LOG_WARNING, "Failed to set TCP_NODELAY option.\n");
438 : }
439 31 : return new Transport(socket);
440 : }
441 0 : return NULL;
442 : }
443 :
444 19 : uint16_t SocketBinding::GetBoundPort() {
445 : struct sockaddr_in saddr;
446 19 : struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
447 : // Clearing sockaddr_in first appears to be necessary on Mac OS X.
448 19 : memset(&saddr, 0, sizeof(saddr));
449 19 : socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
450 19 : if (::getsockname(socket_handle_, psaddr, &addrlen)) {
451 0 : NaClLog(LOG_ERROR, "Failed to retrieve bound address.\n");
452 0 : return 0;
453 : }
454 19 : return ntohs(saddr.sin_port);
455 : }
456 :
457 : } // namespace port
|