Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / debug_stub / transport_common.cc
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   explicit Transport(NaClSocketHandle s)
44     : buf_(new char[kBufSize]),
45       pos_(0),
46       size_(0),
47       handle_(s) {
48 #if NACL_WINDOWS
49     CreateSocketEvent();
50 #endif
51   }
52
53   ~Transport() {
54     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   }
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     if (pos_ < size_) {
91       return true;
92     }
93     fd_set fds;
94
95     FD_ZERO(&fds);
96     FD_SET(handle_, &fds);
97
98     // We want a "non-blocking" check
99     struct timeval timeout;
100     timeout.tv_sec = 0;
101     timeout.tv_usec = 0;
102
103     // Check if this file handle can select on read
104     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     if (cnt != 0) return true;
109
110     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   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);
126   }
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 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);
148   pos_ += copy_bytes;
149   *len -= copy_bytes;
150   *dst += copy_bytes;
151 }
152
153 bool Transport::ReadSomeData() {
154   while (true) {
155     int result = ::recv(handle_, buf_.get() + size_, kBufSize - size_, 0);
156     if (result > 0) {
157       size_ += result;
158       return true;
159     }
160     if (result == 0)
161       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     if (NaClSocketGetLastError() != EINTR)
180       return false;
181   }
182 }
183
184 bool Transport::Read(void *ptr, int32_t len) {
185   char *dst = static_cast<char *>(ptr);
186   if (pos_ < size_) {
187     CopyFromBuffer(&dst, &len);
188   }
189   while (len > 0) {
190     pos_ = 0;
191     size_ = 0;
192     if (!ReadSomeData()) {
193       return false;
194     }
195     CopyFromBuffer(&dst, &len);
196   }
197   return true;
198 }
199
200 bool Transport::Write(const void *ptr, int32_t len) {
201   const char *src = static_cast<const char *>(ptr);
202   while (len > 0) {
203     int result = ::send(handle_, src, len, 0);
204     if (result > 0) {
205       src += result;
206       len -= result;
207       continue;
208     }
209     if (result == 0) {
210       return false;
211     }
212     if (NaClSocketGetLastError() != EINTR) {
213       return false;
214     }
215   }
216   return true;
217 }
218
219 void Transport::WaitForDebugStubEvent(struct NaClApp *nap,
220                                       bool ignore_input_from_gdb) {
221   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   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     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   FD_ZERO(&fds);
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_);
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   if (wait) {
263     ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
264   } else {
265     struct timeval timeout;
266     timeout.tv_sec = 0;
267     timeout.tv_usec = 0;
268     ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
269   }
270   if (ret < 0) {
271     NaClLog(LOG_FATAL,
272             "Transport::WaitForDebugStubEvent: Failed to wait for "
273             "debug stub event\n");
274   }
275
276   if (ret > 0) {
277     if (FD_ISSET(nap->faulted_thread_fd_read, &fds)) {
278       char buf[16];
279       if (read(nap->faulted_thread_fd_read, &buf, sizeof(buf)) < 0) {
280         NaClLog(LOG_FATAL,
281                 "Transport::WaitForDebugStubEvent: Failed to read from "
282                 "debug stub event pipe fd\n");
283       }
284     }
285     if (FD_ISSET(handle_, &fds))
286       ReadSomeData();
287   }
288 #endif
289 }
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 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   uint32_t outaddr = *addr;
299   uint16_t outport = *port;
300
301   // Substrings of the full ADDR:PORT
302   std::string addrstr;
303   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   size_t portoff = instr.find(':');
313
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);
318   } else {
319     // otherwise the entire string is the addr portion.
320     addrstr = instr;
321     portstr = "";
322   }
323
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") {
328       outaddr = 0;
329     } else {
330       struct hostent *host = gethostbyname(addrstr.data());
331
332       // Check that we found an IPv4 host
333       if ((NULL == host) || (AF_INET != host->h_addrtype)) return false;
334
335       // Make sure the IP list isn't empty.
336       if (0 == host->h_addr_list[0]) return false;
337
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];
341     }
342   }
343
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));
349   }
350
351   // We haven't failed, so set the values
352   *addr = outaddr;
353   *port = outport;
354   return true;
355 }
356
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);
361
362   sockaddr->sin_family = AF_INET;
363   return StringToIPv4(addrstr, pip, pport);
364 }
365
366 SocketBinding::SocketBinding(NaClSocketHandle socket_handle)
367     : socket_handle_(socket_handle) {
368 }
369
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");
374     return NULL;
375   }
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);
383
384   // Override portions address that are provided
385   if (addr) BuildSockAddr(addr, &saddr);
386
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
390   // to bind it.
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");
396   }
397
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");
401     return NULL;
402   }
403
404   if (listen(socket_handle, 1)) {
405     NaClLog(LOG_ERROR, "Failed to listen.\n");
406     return NULL;
407   }
408   return new SocketBinding(socket_handle);
409 }
410
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.
417     int nodelay = 1;
418     if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
419                    reinterpret_cast<char *>(&nodelay),
420                    sizeof(nodelay))) {
421       NaClLog(LOG_WARNING, "Failed to set TCP_NODELAY option.\n");
422     }
423     return new Transport(socket);
424   }
425   return NULL;
426 }
427
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");
436     return 0;
437   }
438   return ntohs(saddr.sin_port);
439 }
440
441 }  // namespace port