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 <stdio.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 :
12 : #include <string>
13 : #include <sstream>
14 :
15 : #include "native_client/src/trusted/gdb_rsp/session.h"
16 : #include "native_client/src/trusted/gdb_rsp/test.h"
17 : #include "native_client/src/trusted/port/platform.h"
18 :
19 : using gdb_rsp::Session;
20 : using gdb_rsp::Packet;
21 :
22 : // Transport simulation class, this stores data and a r/w index
23 : // to simulate one direction of a pipe, or a pipe to self.
24 1 : class SharedVector {
25 : public:
26 1 : SharedVector() : rd(0), wr(0) {}
27 :
28 : public:
29 : std::vector<char> data;
30 : volatile uint32_t rd;
31 : volatile uint32_t wr;
32 : };
33 :
34 : // Simulates a transport (such as a socket), the reports "ready"
35 : // when polled, but fails on TX/RX.
36 2 : class DCSocketTransport : public port::ITransport {
37 : public:
38 1 : virtual int32_t Read(void *ptr, int32_t len) {
39 : (void) ptr;
40 : (void) len;
41 1 : return -1;
42 : }
43 :
44 0 : virtual int32_t Write(const void *ptr, int32_t len) {
45 : (void) ptr;
46 : (void) len;
47 0 : return -1;
48 : }
49 :
50 2 : virtual bool ReadWaitWithTimeout(uint32_t ms) {
51 : (void) ms;
52 2 : return true;
53 : }
54 :
55 1 : virtual void Disconnect() {}
56 0 : virtual bool DataAvail() { return true; }
57 : };
58 :
59 :
60 : // Simulate a transport transmitting data Q'd in TX and verifying that
61 : // inbound data matches expected "golden" string.
62 1 : class GoldenTransport : public port::ITransport {
63 : public:
64 1 : GoldenTransport(const char *rx, const char *tx, int cnt) {
65 1 : rx_ = rx;
66 1 : tx_ = tx;
67 1 : cnt_ = cnt;
68 1 : txCnt_ = 0;
69 1 : rxCnt_ = 0;
70 1 : errs_ = 0;
71 1 : disconnected_ = false;
72 1 : }
73 :
74 8 : virtual int32_t Read(void *ptr, int32_t len) {
75 8 : if (disconnected_) return -1;
76 7 : memcpy(ptr, &rx_[rxCnt_], len);
77 7 : rxCnt_ += len;
78 7 : if (static_cast<int>(strlen(rx_)) < rxCnt_) {
79 0 : printf("End of RX\n");
80 0 : errs_++;
81 : }
82 7 : return len;
83 : }
84 :
85 : // Read from this link, return a negative value if there is an error
86 2 : virtual int32_t Write(const void *ptr, int32_t len) {
87 2 : const char *str = reinterpret_cast<const char *>(ptr);
88 2 : if (disconnected_) return -1;
89 2 : if (strncmp(str, &tx_[txCnt_], len) != 0) {
90 0 : printf("TX mismatch in %s vs %s.\n", str, &tx_[txCnt_]);
91 0 : errs_++;
92 : }
93 2 : txCnt_ += len;
94 2 : return len;
95 : }
96 :
97 11 : virtual bool ReadWaitWithTimeout(uint32_t ms) {
98 11 : if (disconnected_) return true;
99 :
100 9 : for (int loop = 0; loop < 8; loop++) {
101 9 : if (DataAvail()) return true;
102 0 : port::IPlatform::Relinquish(ms >> 3);
103 : }
104 0 : return false;
105 : }
106 :
107 2 : virtual void Disconnect() {
108 2 : disconnected_ = true;
109 2 : }
110 :
111 9 : virtual bool DataAvail() {
112 9 : return rxCnt_ < static_cast<int>(strlen(rx_));
113 : }
114 :
115 1 : int errs() { return errs_; }
116 :
117 :
118 : protected:
119 : const char *rx_;
120 : const char *tx_;
121 : int cnt_;
122 : int rxCnt_;
123 : int txCnt_;
124 : int errs_;
125 : bool disconnected_;
126 : };
127 :
128 :
129 0 : class TestTransport : public port::ITransport {
130 : public:
131 2 : TestTransport(SharedVector *rvec, SharedVector *wvec) {
132 2 : rvector_ = rvec;
133 2 : wvector_ = wvec;
134 2 : disconnected_ = false;
135 2 : }
136 :
137 8 : virtual int32_t Read(void *ptr, int32_t len) {
138 8 : if (disconnected_) return -1;
139 8 : DataAvail();
140 :
141 8 : int max = rvector_->wr - rvector_->rd;
142 8 : if (max > len)
143 7 : max = len;
144 :
145 8 : if (max > 0) {
146 8 : char *src = &rvector_->data[rvector_->rd];
147 8 : memcpy(ptr, src, max);
148 : }
149 8 : rvector_->rd += max;
150 8 : return max;
151 : }
152 :
153 2 : virtual int32_t Write(const void *ptr, int32_t len) {
154 2 : if (disconnected_) return -1;
155 :
156 2 : wvector_->data.resize(wvector_->wr + len);
157 2 : memcpy(&wvector_->data[wvector_->wr], ptr, len);
158 2 : wvector_->wr += len;
159 2 : return len;
160 : }
161 :
162 10 : virtual bool ReadWaitWithTimeout(uint32_t ms) {
163 10 : if (disconnected_) return true;
164 :
165 10 : for (int loop = 0; loop < 8; loop++) {
166 10 : if (DataAvail()) return true;
167 0 : port::IPlatform::Relinquish(ms >> 3);
168 : }
169 0 : return false;
170 : }
171 :
172 0 : virtual void Disconnect() {
173 0 : disconnected_ = true;
174 0 : }
175 :
176 : // Return true if vec->data is availible (
177 18 : virtual bool DataAvail() {
178 18 : return (rvector_->rd < rvector_->wr);
179 : }
180 :
181 : protected:
182 : SharedVector *rvector_;
183 : SharedVector *wvector_;
184 : bool disconnected_;
185 : };
186 :
187 :
188 1 : int TestSession() {
189 1 : int errs = 0;
190 1 : Packet pktOut;
191 1 : Packet pktIn;
192 1 : SharedVector vec;
193 :
194 : // Create a "loopback" session by using the same
195 : // FIFO for ingress and egress.
196 1 : Session cli;
197 1 : Session srv;
198 :
199 1 : if (cli.Init(NULL)) {
200 0 : printf("Initializing with NULL did not fail.\n");
201 0 : errs++;
202 : }
203 :
204 1 : cli.Init(new TestTransport(&vec, &vec));
205 1 : srv.Init(new TestTransport(&vec, &vec));
206 :
207 : // Check, Set,Clear,Get flags.
208 1 : cli.ClearFlags(static_cast<uint32_t>(-1));
209 1 : cli.SetFlags(Session::IGNORE_ACK | Session::DEBUG_RECV);
210 1 : if (cli.GetFlags() != (Session::IGNORE_ACK + Session::DEBUG_RECV)) {
211 0 : printf("SetFlag failed.\n");
212 0 : errs++;
213 : }
214 1 : cli.ClearFlags(Session::IGNORE_ACK | Session::DEBUG_SEND);
215 1 : if (cli.GetFlags() != Session::DEBUG_RECV) {
216 0 : printf("ClearFlag failed.\n");
217 0 : errs++;
218 : }
219 :
220 : // Check Send Packet of known value.
221 1 : const char *str = "1234";
222 :
223 1 : pktOut.AddString(str);
224 1 : cli.SendPacketOnly(&pktOut);
225 1 : srv.GetPacket(&pktIn);
226 1 : std::string out;
227 1 : pktIn.GetString(&out);
228 1 : if (out != str) {
229 0 : printf("Send Only failed.\n");
230 0 : errs++;
231 : }
232 :
233 : // Check send against golden transactions
234 1 : const char tx[] = { "$1234#ca+" };
235 1 : const char rx[] = { "+$OK#9a" };
236 1 : GoldenTransport gold(rx, tx, 2);
237 1 : Session uni;
238 1 : uni.Init(&gold);
239 :
240 1 : pktOut.Clear();
241 1 : pktOut.AddString(str);
242 1 : if (!uni.SendPacket(&pktOut)) {
243 0 : printf("Send failed.\n");
244 0 : errs++;
245 : }
246 1 : if (!uni.GetPacket(&pktIn)) {
247 0 : printf("Get failed.\n");
248 0 : errs++;
249 : }
250 1 : pktIn.GetString(&out);
251 1 : if (out != "OK") {
252 0 : printf("Send/Get failed.\n");
253 0 : errs++;
254 : }
255 :
256 : // Check that a closed Transport reports to session
257 1 : if (!uni.Connected()) {
258 0 : printf("Expecting uni to be connected.\n");
259 0 : errs++;
260 : }
261 1 : gold.Disconnect();
262 1 : uni.GetPacket(&pktIn);
263 1 : if (uni.Connected()) {
264 0 : printf("Expecting uni to be disconnected.\n");
265 0 : errs++;
266 : }
267 :
268 : // Check that a failed read/write reports DC
269 1 : DCSocketTransport dctrans;
270 1 : Session dctest;
271 1 : dctest.Init(&dctrans);
272 1 : if (!dctest.Connected()) {
273 0 : printf("Expecting dctest to be connected.\n");
274 0 : errs++;
275 : }
276 1 : dctest.GetPacket(&pktIn);
277 1 : if (dctest.Connected()) {
278 0 : printf("Expecting dctest to be disconnected.\n");
279 0 : errs++;
280 : }
281 :
282 1 : errs += gold.errs();
283 1 : return errs;
284 : }
285 :
|