LCOV - code coverage report
Current view: directory - src/trusted/gdb_rsp - session.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 141 113 80.1 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright 2010 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can
       4                 :  * be found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include <assert.h>
       8                 : #include <string.h>
       9                 : #include <stdlib.h>
      10                 : 
      11                 : #include <string>
      12                 : #include <sstream>
      13                 : 
      14                 : #include "native_client/src/trusted/gdb_rsp/packet.h"
      15                 : #include "native_client/src/trusted/gdb_rsp/session.h"
      16                 : #include "native_client/src/trusted/gdb_rsp/util.h"
      17                 : 
      18                 : #include "native_client/src/trusted/port/mutex.h"
      19                 : #include "native_client/src/trusted/port/platform.h"
      20                 : #include "native_client/src/trusted/port/transport.h"
      21                 : 
      22                 : using port::IPlatform;
      23                 : using port::ITransport;
      24                 : using port::IMutex;
      25                 : using port::MutexLock;
      26                 : 
      27                 : // Use a timeout of 1 second
      28                 : int const kSessionTimeoutMs = 1000;
      29                 : 
      30                 : namespace gdb_rsp {
      31                 : 
      32               6 : Session::Session()
      33                 :   : mutex_(NULL),
      34                 :     io_(NULL),
      35                 :     flags_(0),
      36                 :     seq_(0),
      37               6 :     connected_(false) {
      38               6 : }
      39                 : 
      40               6 : Session::~Session() {
      41               6 :   if (mutex_) IMutex::Free(mutex_);
      42               6 : }
      43                 : 
      44                 : 
      45               7 : bool Session::Init(port::ITransport *transport) {
      46               7 :   if (NULL == transport) return false;
      47                 : 
      48               6 :   mutex_ = IMutex::Allocate();
      49               6 :   if (NULL == mutex_) return false;
      50                 : 
      51               6 :   connected_ = true;
      52               6 :   io_ = transport;
      53               6 :   return true;
      54                 : }
      55                 : 
      56               3 : void Session::SetFlags(uint32_t flags) {
      57               3 :   flags_ |= flags;
      58               3 : }
      59                 : 
      60               2 : void Session::ClearFlags(uint32_t flags) {
      61               2 :   flags_ &= ~flags;
      62               2 : }
      63                 : 
      64              72 : uint32_t Session::GetFlags() {
      65              72 :   return flags_;
      66                 : }
      67                 : 
      68              17 : bool Session::DataAvailable() {
      69              17 :   assert(io_);
      70                 : 
      71              17 :   return io_->ReadWaitWithTimeout(kSessionTimeoutMs);
      72                 : }
      73                 : 
      74              13 : bool Session::Connected() {
      75              13 :   return connected_;
      76                 : }
      77                 : 
      78              17 : bool Session::GetChar(char *ch) {
      79              17 :   assert(io_);
      80                 : 
      81                 :   // Attempt to select this IO for reading.
      82              17 :   if (DataAvailable() == false) return false;
      83                 : 
      84              17 :   int32_t len = io_->Read(ch, 1);
      85                 : 
      86                 :   // If data is "availible" but we can't read, it must be closed.
      87              17 :   if (len < 1) {
      88               2 :     io_->Disconnect();
      89               2 :     connected_ = false;
      90               2 :     return false;
      91                 :   }
      92                 : 
      93              15 :   return true;
      94                 : }
      95                 : 
      96                 : 
      97              20 : bool Session::SendPacket(Packet *pkt) {
      98              20 :   MutexLock lock(mutex_);
      99                 :   char ch;
     100                 : 
     101               1 :   do {
     102              20 :     if (!SendPacketOnly(pkt)) return false;
     103                 : 
     104                 :     // If ACKs are off, we are done.
     105              20 :     if (GetFlags() & IGNORE_ACK) break;
     106                 : 
     107                 :     // Otherwise, poll for '+'
     108               1 :     if (!GetChar(&ch)) return false;
     109                 : 
     110                 :     // Retry if we didn't get a '+'
     111                 :   } while (ch != '+');
     112                 : 
     113              20 :   return true;
     114                 : }
     115                 : 
     116                 : 
     117               2 : bool Session::SendPacketOnly(Packet *pkt) {
     118               2 :   MutexLock lock(mutex_);
     119                 : 
     120                 :   const char *ptr;
     121                 :   char ch;
     122               2 :   std::stringstream outstr;
     123                 : 
     124               2 :   char run_xsum = 0;
     125                 :   int32_t seq;
     126                 : 
     127               2 :   ptr = pkt->GetPayload();
     128                 : 
     129               2 :   if (!pkt->GetSequence(&seq) && (GetFlags() & USE_SEQ)) {
     130               0 :     pkt->SetSequence(seq_++);
     131                 :   }
     132                 : 
     133                 :   // Signal start of response
     134               2 :   outstr << '$';
     135                 : 
     136                 :   // If there is a sequence, send as two nibble 8bit value + ':'
     137               2 :   if (pkt->GetSequence(&seq)) {
     138               0 :     IntToNibble((seq & 0xFF) >> 4, &ch);
     139               0 :     outstr << ch;
     140               0 :     run_xsum += ch;
     141                 : 
     142               0 :     IntToNibble(seq & 0xF, &ch);
     143               0 :     outstr << ch;
     144               0 :     run_xsum += ch;
     145                 : 
     146               0 :     ch = ':';
     147               0 :     outstr << ch;
     148               0 :     run_xsum += ch;
     149                 :   }
     150                 : 
     151                 :   // Send the main payload
     152               2 :   int offs = 0;
     153              12 :   while ((ch = ptr[offs++]) != 0) {
     154               8 :     outstr << ch;
     155               8 :     run_xsum += ch;
     156                 :   }
     157                 : 
     158                 :   // Send XSUM as two nible 8bit value preceeded by '#'
     159               2 :   outstr << '#';
     160               2 :   IntToNibble((run_xsum >> 4) & 0xF, &ch);
     161               2 :   outstr << ch;
     162               2 :   IntToNibble(run_xsum & 0xF, &ch);
     163               2 :   outstr << ch;
     164                 : 
     165               2 :   return SendStream(outstr.str().data());
     166                 : }
     167                 : 
     168                 : // We do not take the mutex here since we already have it
     169                 : // this function is protected so it can't be called directly.
     170               4 : bool Session::SendStream(const char *out) {
     171               4 :   int32_t len = static_cast<int32_t>(strlen(out));
     172               4 :   int32_t sent = 0;
     173                 : 
     174               4 :   assert(io_);
     175                 : 
     176              12 :   while (sent < len) {
     177               4 :     const char *cur = &out[sent];
     178               4 :     int32_t tx = io_->Write(cur, len - sent);
     179                 : 
     180               4 :     if (tx <= 0) {
     181               0 :       IPlatform::LogWarning("Send of %d bytes : '%s' failed.\n", len, out);
     182               0 :       io_->Disconnect();
     183               0 :       connected_ = false;
     184               0 :       return false;
     185                 :     }
     186                 : 
     187               4 :     sent += tx;
     188                 :   }
     189                 : 
     190               4 :   if (GetFlags() & DEBUG_SEND) IPlatform::LogInfo("TX %s\n", out);
     191               4 :   return true;
     192                 : }
     193                 : 
     194                 : 
     195                 : // Attempt to receive a packet
     196               4 : bool Session::GetPacket(Packet *pkt) {
     197               4 :   assert(io_);
     198                 : 
     199               4 :   MutexLock lock(mutex_);
     200                 : 
     201                 :   char run_xsum, fin_xsum, ch;
     202               4 :   std::string in;
     203                 :   int has_seq, offs;
     204                 : 
     205                 :   // If nothing is waiting, return false
     206               4 :   if (!io_->ReadWaitWithTimeout(kSessionTimeoutMs)) return false;
     207                 : 
     208                 :   // Toss characters until we see a start of command
     209               2 :   do {
     210               4 :     if (!GetChar(&ch)) return false;
     211               2 :     in += ch;
     212                 :   } while (ch != '$');
     213                 : 
     214               2 :  retry:
     215               2 :   has_seq = 1;
     216               2 :   offs    = 0;
     217                 : 
     218                 :   // If nothing is waiting, return NONE
     219               2 :   if (!io_->ReadWaitWithTimeout(kSessionTimeoutMs)) return false;
     220                 : 
     221                 :   // Clear the stream
     222               2 :   pkt->Clear();
     223                 : 
     224                 :   // Prepare XSUM calc
     225               2 :   run_xsum = 0;
     226               2 :   fin_xsum = 0;
     227                 : 
     228                 :   // Stream in the characters
     229               6 :   while (1) {
     230               8 :     if (!GetChar(&ch)) return false;
     231                 : 
     232               8 :     in += ch;
     233                 :      // Check SEQ statemachine  xx:
     234               8 :     switch (offs) {
     235                 :       case 0:
     236                 :       case 1:
     237               4 :         if (!NibbleToInt(ch, 0)) has_seq = 0;
     238               4 :         break;
     239                 : 
     240                 :       case 2:
     241               2 :         if (ch != ':') has_seq = 0;
     242                 :         break;
     243                 :     }
     244               8 :     offs++;
     245                 : 
     246                 :     // If we see a '#' we must be done with the data
     247               8 :     if (ch == '#') break;
     248                 : 
     249                 :     // If we see a '$' we must have missed the last cmd
     250               6 :     if (ch == '$') {
     251               0 :       IPlatform::LogInfo("RX Missing $, retry.\n");
     252               0 :       goto retry;
     253                 :     }
     254                 :     // Keep a running XSUM
     255               6 :     run_xsum += ch;
     256               6 :     pkt->AddRawChar(ch);
     257                 :   }
     258                 : 
     259                 : 
     260                 :   // Get two Nibble XSUM
     261               2 :   if (!GetChar(&ch)) return false;
     262               2 :   in += ch;
     263                 : 
     264                 :   int val;
     265               2 :   NibbleToInt(ch, & val);
     266               2 :   fin_xsum = val << 4;
     267                 : 
     268               2 :   if (!GetChar(&ch)) return false;
     269               2 :   in += ch;
     270               2 :   NibbleToInt(ch, &val);
     271               2 :   fin_xsum |= val;
     272                 : 
     273               2 :   if (GetFlags() & DEBUG_RECV) IPlatform::LogInfo("RX %s\n", in.data());
     274                 : 
     275                 :   // Pull off teh sequence number if we have one
     276               2 :   if (has_seq) {
     277                 :     uint8_t seq;
     278                 :     char ch;
     279                 : 
     280               0 :     pkt->GetWord8(&seq);
     281               0 :     pkt->SetSequence(seq);
     282               0 :     pkt->GetRawChar(&ch);
     283               0 :     if (ch != ':') {
     284               0 :       IPlatform::LogError("RX mismatched SEQ.\n");
     285               0 :       return false;
     286                 :     }
     287                 :   }
     288                 : 
     289                 :   // If ACKs are off, we are done.
     290               2 :   if (GetFlags() & IGNORE_ACK) return true;
     291                 : 
     292                 :   // If the XSUMs don't match, signal bad packet
     293               2 :   if (fin_xsum == run_xsum) {
     294               2 :     char out[4] = { '+', 0, 0, 0};
     295                 :     int32_t seq;
     296                 : 
     297                 :     // If we have a sequence number
     298               2 :     if (pkt->GetSequence(&seq)) {
     299                 :       // Respond with Sequence number
     300               0 :       IntToNibble(seq >> 4, &out[1]);
     301               0 :       IntToNibble(seq & 0xF, &out[2]);
     302                 :     }
     303               2 :     return SendStream(out);
     304                 :   } else {
     305                 :     // Resend a bad XSUM and look for retransmit
     306               0 :     SendStream("-");
     307                 : 
     308               0 :     IPlatform::LogInfo("RX Bad XSUM, retry\n");
     309               0 :     goto retry;
     310                 :   }
     311                 : 
     312               0 :   return true;
     313                 : }
     314                 : 
     315                 : }  // End of namespace gdb_rsp
     316                 : 

Generated by: LCOV version 1.7