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.
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"
22 using gdb_rsp::stringvec;
23 using gdb_rsp::StringSplit;
26 typedef int socklen_t;
31 class Transport : public ITransport {
34 : buf_(new char[kBufSize]),
37 handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
43 explicit Transport(NaClSocketHandle s)
44 : buf_(new char[kBufSize]),
54 if (handle_ != NACL_INVALID_SOCKET) NaClCloseSocket(handle_);
56 if (!WSACloseEvent(socket_event_)) {
58 "Transport::~Transport: Failed to close socket event\n");
64 void CreateSocketEvent() {
65 socket_event_ = WSACreateEvent();
66 if (socket_event_ == WSA_INVALID_EVENT) {
68 "Transport::CreateSocketEvent: Failed to create socket event\n");
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
75 handle_, socket_event_, FD_CLOSE | FD_READ) == SOCKET_ERROR) {
77 "Transport::CreateSocketEvent: Failed to bind event to socket\n");
82 // Read from this transport, return true on success.
83 virtual bool Read(void *ptr, int32_t len);
85 // Write to this transport, return true on success.
86 virtual bool Write(const void *ptr, int32_t len);
88 // Return true if there is data to read.
89 virtual bool IsDataAvailable() {
96 FD_SET(handle_, &fds);
98 // We want a "non-blocking" check
99 struct timeval timeout;
103 // Check if this file handle can select on read
104 int cnt = select(static_cast<int>(handle_) + 1, &fds, 0, 0, &timeout);
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 if (cnt != 0) return true;
113 virtual void WaitForDebugStubEvent(struct NaClApp *nap,
114 bool ignore_input_from_gdb);
116 // On windows, the header that defines this has other definition
117 // colitions, so we define it outselves just in case
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 (void) ::shutdown(handle_, SD_BOTH);
129 // Copy buffered data to *dst up to len bytes and update dst and len.
130 void CopyFromBuffer(char **dst, int32_t *len);
132 // Read available data from the socket. Return false on EOF or error.
135 static const int kBufSize = 4096;
136 nacl::scoped_array<char> buf_;
139 NaClSocketHandle handle_;
141 HANDLE socket_event_;
145 void Transport::CopyFromBuffer(char **dst, int32_t *len) {
146 int32_t copy_bytes = std::min(*len, size_ - pos_);
147 memcpy(*dst, buf_.get() + pos_, copy_bytes);
153 bool Transport::ReadSomeData() {
155 int result = ::recv(handle_, buf_.get() + size_, kBufSize - size_, 0);
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) {
170 "Transport::ReadSomeData: Failed to wait on socket event\n");
172 if (!ResetEvent(socket_event_)) {
174 "Transport::ReadSomeData: Failed to reset socket event\n");
179 if (NaClSocketGetLastError() != EINTR)
184 bool Transport::Read(void *ptr, int32_t len) {
185 char *dst = static_cast<char *>(ptr);
187 CopyFromBuffer(&dst, &len);
192 if (!ReadSomeData()) {
195 CopyFromBuffer(&dst, &len);
200 bool Transport::Write(const void *ptr, int32_t len) {
201 const char *src = static_cast<const char *>(ptr);
203 int result = ::send(handle_, src, len, 0);
212 if (NaClSocketGetLastError() != EINTR) {
219 void Transport::WaitForDebugStubEvent(struct NaClApp *nap,
220 bool ignore_input_from_gdb) {
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 if ((pos_ < size_ && !ignore_input_from_gdb) ||
225 nap->faulted_thread_count > 0) {
226 // Clear faulted thread events to save debug stub loop iterations.
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_)) {
239 "Transport::WaitForDebugStubEvent: "
240 "Failed to reset socket event\n");
244 if (result == WAIT_TIMEOUT || result == WAIT_OBJECT_0)
247 "Transport::WaitForDebugStubEvent: Wait for events failed\n");
252 FD_SET(nap->faulted_thread_fd_read, &fds);
253 int max_fd = nap->faulted_thread_fd_read;
254 if (size_ < kBufSize) {
255 FD_SET(handle_, &fds);
256 max_fd = std::max(max_fd, handle_);
260 // We don't need sleep-polling on Linux now, so we set either zero or infinite
263 ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
265 struct timeval timeout;
268 ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
272 "Transport::WaitForDebugStubEvent: Failed to wait for "
273 "debug stub event\n");
277 if (FD_ISSET(nap->faulted_thread_fd_read, &fds)) {
279 if (read(nap->faulted_thread_fd_read, &buf, sizeof(buf)) < 0) {
281 "Transport::WaitForDebugStubEvent: Failed to read from "
282 "debug stub event pipe fd\n");
285 if (FD_ISSET(handle_, &fds))
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 static bool StringToIPv4(const std::string &instr, uint32_t *addr,
297 // Make a copy so the are unchanged unless we succeed
298 uint32_t outaddr = *addr;
299 uint16_t outport = *port;
301 // Substrings of the full ADDR:PORT
305 // We should either have one or two tokens in the form of:
309 // IP:PORT - IP, PORT
311 // Search for the port marker
312 size_t portoff = instr.find(':');
314 // If we found a ":" before the end, get both substrings
315 if ((portoff != std::string::npos) && (portoff + 1 < instr.size())) {
316 addrstr = instr.substr(0, portoff);
317 portstr = instr.substr(portoff + 1, std::string::npos);
319 // otherwise the entire string is the addr portion.
324 // If the address portion was provided, update it
325 if (addrstr.size()) {
326 // Special case 0.0.0.0 which means any IPv4 interface
327 if (addrstr == "0.0.0.0") {
330 struct hostent *host = gethostbyname(addrstr.data());
332 // Check that we found an IPv4 host
333 if ((NULL == host) || (AF_INET != host->h_addrtype)) return false;
335 // Make sure the IP list isn't empty.
336 if (0 == host->h_addr_list[0]) return false;
338 // Use the first address in the array of address pointers.
339 uint32_t **addrarray = reinterpret_cast<uint32_t**>(host->h_addr_list);
340 outaddr = *addrarray[0];
344 // if the port portion was provided, then update it
345 if (portstr.size()) {
346 int val = atoi(portstr.data());
347 if ((val < 0) || (val > 65535)) return false;
348 outport = ntohs(static_cast<uint16_t>(val));
351 // We haven't failed, so set the values
357 static bool BuildSockAddr(const char *addr, struct sockaddr_in *sockaddr) {
358 std::string addrstr = addr;
359 uint32_t *pip = reinterpret_cast<uint32_t*>(&sockaddr->sin_addr.s_addr);
360 uint16_t *pport = reinterpret_cast<uint16_t*>(&sockaddr->sin_port);
362 sockaddr->sin_family = AF_INET;
363 return StringToIPv4(addrstr, pip, pport);
366 SocketBinding::SocketBinding(NaClSocketHandle socket_handle)
367 : socket_handle_(socket_handle) {
370 SocketBinding *SocketBinding::Bind(const char *addr) {
371 NaClSocketHandle socket_handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
372 if (socket_handle == NACL_INVALID_SOCKET) {
373 NaClLog(LOG_ERROR, "Failed to create socket.\n");
376 struct sockaddr_in saddr;
377 // Clearing sockaddr_in first appears to be necessary on Mac OS X.
378 memset(&saddr, 0, sizeof(saddr));
379 socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
380 saddr.sin_family = AF_INET;
381 saddr.sin_addr.s_addr = htonl(0x7F000001);
382 saddr.sin_port = htons(4014);
384 // Override portions address that are provided
385 if (addr) BuildSockAddr(addr, &saddr);
387 // This is necessary to ensure that the TCP port is released
388 // promptly when sel_ldr exits. Without this, the TCP port might
389 // only be released after a timeout, and later processes can fail
391 int reuse_address = 1;
392 if (setsockopt(socket_handle, SOL_SOCKET, SO_REUSEADDR,
393 reinterpret_cast<char *>(&reuse_address),
394 sizeof(reuse_address))) {
395 NaClLog(LOG_WARNING, "Failed to set SO_REUSEADDR option.\n");
398 struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
399 if (bind(socket_handle, psaddr, addrlen)) {
400 NaClLog(LOG_ERROR, "Failed to bind server.\n");
404 if (listen(socket_handle, 1)) {
405 NaClLog(LOG_ERROR, "Failed to listen.\n");
408 return new SocketBinding(socket_handle);
411 ITransport *SocketBinding::AcceptConnection() {
412 NaClSocketHandle socket = ::accept(socket_handle_, NULL, 0);
413 if (socket != NACL_INVALID_SOCKET) {
414 // Do not delay sending small packets. This significantly speeds up
415 // remote debugging. Debug stub uses buffering to send outgoing packets so
416 // they are not split into more TCP packets than necessary.
418 if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
419 reinterpret_cast<char *>(&nodelay),
421 NaClLog(LOG_WARNING, "Failed to set TCP_NODELAY option.\n");
423 return new Transport(socket);
428 uint16_t SocketBinding::GetBoundPort() {
429 struct sockaddr_in saddr;
430 struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
431 // Clearing sockaddr_in first appears to be necessary on Mac OS X.
432 memset(&saddr, 0, sizeof(saddr));
433 socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
434 if (::getsockname(socket_handle_, psaddr, &addrlen)) {
435 NaClLog(LOG_ERROR, "Failed to retrieve bound address.\n");
438 return ntohs(saddr.sin_port);