LCOV - code coverage report
Current view: directory - src/trusted/debug_stub - transport_common.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 104 0 0.0 %
Date: 2012-02-16 Functions: 0 0 -

       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                 : #ifdef _WIN32
       8                 : #include <windows.h>
       9                 : #ifndef AF_IPX
      10                 : #include <winsock2.h>
      11                 : #endif
      12                 : #define SOCKET_HANDLE SOCKET
      13                 : #else
      14                 : 
      15                 : #include <arpa/inet.h>
      16                 : #include <netdb.h>
      17                 : #include <sys/select.h>
      18                 : #include <sys/socket.h>
      19                 : #include <sys/types.h>
      20                 : #include <unistd.h>
      21                 : 
      22                 : #define SOCKET_HANDLE int
      23                 : #define closesocket close
      24                 : #endif
      25                 : 
      26                 : #include <stdlib.h>
      27                 : #include <string>
      28                 : 
      29                 : #include "native_client/src/trusted/gdb_rsp/util.h"
      30                 : #include "native_client/src/trusted/port/platform.h"
      31                 : #include "native_client/src/trusted/port/transport.h"
      32                 : 
      33                 : using gdb_rsp::stringvec;
      34                 : using gdb_rsp::StringSplit;
      35                 : 
      36                 : namespace port {
      37                 : 
      38                 : typedef int socklen_t;
      39                 : 
      40                 : class Transport : public ITransport {
      41                 :  public:
      42                 :   Transport() {
      43                 :     handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      44                 :   }
      45                 : 
      46               0 :   explicit Transport(SOCKET_HANDLE s) {
      47               0 :     handle_ = s;
      48               0 :   }
      49                 : 
      50               0 :   ~Transport() {
      51               0 :     if (handle_ != -1) closesocket(handle_);
      52               0 :   }
      53                 : 
      54                 :   // Read from this transport, return a negative value if there is an error
      55                 :   // otherwise return the number of bytes actually read.
      56               0 :   virtual int32_t Read(void *ptr, int32_t len) {
      57               0 :     return ::recv(handle_, reinterpret_cast<char *>(ptr), len, 0);
      58                 :   }
      59                 : 
      60                 :   // Write to this transport, return a negative value if there is an error
      61                 :   // otherwise return the number of bytes actually written.
      62               0 :   virtual int32_t Write(const void *ptr, int32_t len) {
      63               0 :     return ::send(handle_, reinterpret_cast<const char *>(ptr), len, 0);
      64                 :   }
      65                 : 
      66                 :   // Return true if data becomes availible or false after ms milliseconds.
      67               0 :   virtual bool ReadWaitWithTimeout(uint32_t ms = 0) {
      68                 :     fd_set fds;
      69                 : 
      70               0 :     FD_ZERO(&fds);
      71               0 :     FD_SET(handle_, &fds);
      72                 : 
      73                 :     // We want a "non-blocking" check
      74                 :     struct timeval timeout;
      75               0 :     timeout.tv_sec = 0;
      76               0 :     timeout.tv_usec= ms * 1000;
      77                 : 
      78                 :     // Check if this file handle can select on read
      79               0 :     int cnt = select(static_cast<int>(handle_) + 1, &fds, 0, 0, &timeout);
      80                 : 
      81                 :     // If we are ready, or if there is an error.  We return true
      82                 :     // on error, to "timeout" and let the next IO request fail.
      83               0 :     if (cnt != 0) return true;
      84                 : 
      85               0 :     return false;
      86                 :   }
      87                 : 
      88                 : // On windows, the header that defines this has other definition
      89                 : // colitions, so we define it outselves just in case
      90                 : #ifndef SD_BOTH
      91                 : #define SD_BOTH 2
      92                 : #endif
      93                 : 
      94               0 :   virtual void Disconnect() {
      95                 :     // Shutdown the conneciton in both diections.  This should
      96                 :     // always succeed, and nothing we can do if this fails.
      97               0 :     (void) ::shutdown(handle_, SD_BOTH);
      98               0 :   }
      99                 : 
     100                 :  protected:
     101                 :   SOCKET_HANDLE handle_;
     102                 : };
     103                 : 
     104                 : // Convert string in the form of [addr][:port] where addr is a
     105                 : // IPv4 address or host name, and port is a 16b tcp/udp port.
     106                 : // Both portions are optional, and only the portion of the address
     107                 : // provided is updated.  Values are provided in network order.
     108                 : static bool StringToIPv4(const std::string &instr, uint32_t *addr,
     109               0 :                          uint16_t *port) {
     110                 :   // Make a copy so the are unchanged unless we succeed
     111               0 :   uint32_t outaddr = *addr;
     112               0 :   uint16_t outport = *port;
     113                 : 
     114                 :   // Substrings of the full ADDR:PORT
     115               0 :   std::string addrstr;
     116               0 :   std::string portstr;
     117                 : 
     118                 :   // We should either have one or two tokens in the form of:
     119                 :   //  IP - IP, NUL
     120                 :   //  IP: -  IP, NUL
     121                 :   //  :PORT - NUL, PORT
     122                 :   //  IP:PORT - IP, PORT
     123                 : 
     124                 :   // Search for the port marker
     125               0 :   size_t portoff = instr.find(':');
     126                 : 
     127                 :   // If we found a ":" before the end, get both substrings
     128               0 :   if ((portoff != std::string::npos) && (portoff + 1 < instr.size())) {
     129               0 :     addrstr = instr.substr(0, portoff);
     130               0 :     portstr = instr.substr(portoff + 1, std::string::npos);
     131                 :   } else {
     132                 :     // otherwise the entire string is the addr portion.
     133               0 :     addrstr = instr;
     134               0 :     portstr = "";
     135                 :   }
     136                 : 
     137                 :   // If the address portion was provided, update it
     138               0 :   if (addrstr.size()) {
     139                 :     // Special case 0.0.0.0 which means any IPv4 interface
     140               0 :     if (addrstr == "0.0.0.0") {
     141               0 :       outaddr = 0;
     142                 :     } else {
     143               0 :       struct hostent *host = gethostbyname(addrstr.data());
     144                 : 
     145                 :       // Check that we found an IPv4 host
     146               0 :       if ((NULL == host) || (AF_INET != host->h_addrtype))  return false;
     147                 : 
     148                 :       // Make sure the IP list isn't empty.
     149               0 :       if (0 == host->h_addr_list[0]) return false;
     150                 : 
     151                 :       // Use the first address in the array of address pointers.
     152               0 :       uint32_t **addrarray = reinterpret_cast<uint32_t**>(host->h_addr_list);
     153               0 :       outaddr = *addrarray[0];
     154                 :     }
     155                 :   }
     156                 : 
     157                 :   // if the port portion was provided, then update it
     158               0 :   if (portstr.size()) {
     159               0 :     int val = atoi(portstr.data());
     160               0 :     if ((val < 0) || (val > 65535)) return false;
     161               0 :     outport = ntohs(static_cast<uint16_t>(val));
     162                 :   }
     163                 : 
     164                 :   // We haven't failed, so set the values
     165               0 :   *addr = outaddr;
     166               0 :   *port = outport;
     167               0 :   return true;
     168                 : }
     169                 : 
     170                 : 
     171                 : static SOCKET_HANDLE s_ServerSock;
     172                 : 
     173               0 : static bool SocketInit() {
     174               0 :   s_ServerSock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     175               0 :   if (s_ServerSock == -1) {
     176               0 :     IPlatform::LogError("Failed to create socket.\n");
     177               0 :     return false;
     178                 :   }
     179                 : 
     180               0 :   return true;
     181                 : }
     182                 : 
     183               0 : static bool SocketsAvailable() {
     184               0 :   static bool _init = SocketInit();
     185               0 :   return _init;
     186                 : }
     187                 : 
     188               0 : static bool BuildSockAddr(const char *addr, struct sockaddr_in *sockaddr) {
     189               0 :   std::string addrstr = addr;
     190               0 :   uint32_t *pip = reinterpret_cast<uint32_t*>(&sockaddr->sin_addr.s_addr);
     191               0 :   uint16_t *pport = reinterpret_cast<uint16_t*>(&sockaddr->sin_port);
     192                 : 
     193               0 :   sockaddr->sin_family = AF_INET;
     194               0 :   return StringToIPv4(addrstr, pip, pport);
     195                 : }
     196                 : 
     197               0 : ITransport* ITransport::Connect(const char *addr) {
     198               0 :   if (!SocketsAvailable()) return NULL;
     199                 : 
     200               0 :   SOCKET_HANDLE s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     201               0 :   if (s == -1) {
     202               0 :     IPlatform::LogError("Failed to create connection socket.\n");
     203               0 :     return NULL;
     204                 :   }
     205                 : 
     206                 :   struct sockaddr_in saddr;
     207               0 :   saddr.sin_family = AF_INET;
     208               0 :   saddr.sin_addr.s_addr = htonl(0x7F000001);
     209               0 :   saddr.sin_port = htons(4014);
     210                 : 
     211                 :   // Override portions address that are provided
     212               0 :   if (addr) BuildSockAddr(addr, &saddr);
     213                 : 
     214               0 :   if (::connect(s, reinterpret_cast<sockaddr*>(&saddr), sizeof(saddr)) != 0) {
     215               0 :     closesocket(s);
     216               0 :     IPlatform::LogError("Failed to connect.\n");
     217               0 :     return NULL;
     218                 :   }
     219                 : 
     220               0 :   return new Transport(s);
     221                 : }
     222                 : 
     223               0 : ITransport* ITransport::Accept(const char *addr) {
     224                 :   static bool listening = false;
     225               0 :   if (!SocketsAvailable()) return NULL;
     226                 : 
     227               0 :   if (!listening) {
     228                 :     struct sockaddr_in saddr;
     229               0 :     socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
     230               0 :     saddr.sin_family = AF_INET;
     231               0 :     saddr.sin_addr.s_addr = htonl(0x7F000001);
     232               0 :     saddr.sin_port = htons(4014);
     233                 : 
     234                 :     // Override portions address that are provided
     235               0 :     if (addr) BuildSockAddr(addr, &saddr);
     236                 : 
     237                 :     // This is necessary to ensure that the TCP port is released
     238                 :     // promptly when sel_ldr exits.  Without this, the TCP port might
     239                 :     // only be released after a timeout, and later processes can fail
     240                 :     // to bind it.
     241               0 :     int reuse_address = 1;
     242                 :     setsockopt(s_ServerSock, SOL_SOCKET, SO_REUSEADDR,
     243                 :                reinterpret_cast<char *>(&reuse_address),
     244               0 :                sizeof(reuse_address));
     245                 : 
     246               0 :     struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
     247               0 :     if (bind(s_ServerSock, psaddr, addrlen)) {
     248               0 :       IPlatform::LogError("Failed to bind server.\n");
     249               0 :       return NULL;
     250                 :     }
     251                 : 
     252               0 :     if (listen(s_ServerSock, 1)) {
     253               0 :       IPlatform::LogError("Failed to listen.\n");
     254               0 :       return NULL;
     255                 :     }
     256                 : 
     257               0 :     listening = true;
     258                 :   }
     259                 : 
     260               0 :   if (listening) {
     261               0 :     SOCKET_HANDLE s = ::accept(s_ServerSock, NULL, 0);
     262               0 :     if (-1 != s) return new Transport(s);
     263               0 :     return NULL;
     264                 :   }
     265                 : 
     266               0 :   return NULL;
     267                 : }
     268                 : 
     269               0 : void ITransport::Free(ITransport* itrans) {
     270               0 :   Transport* trans = static_cast<Transport*>(itrans);
     271               0 :   delete trans;
     272               0 : }
     273                 : 
     274                 : }  // namespace port

Generated by: LCOV version 1.7