OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2011 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 <string> | |
8 #include <sstream> | |
9 | |
10 #include "debug_conn/debug_packet.h" | |
11 #include "debug_conn/debug_pipe.h" | |
12 #include "debug_conn/debug_socket.h" | |
13 #include "debug_conn/debug_stream.h" | |
14 #include "debug_conn/debug_util.h" | |
15 #include "native_client/src/trusted/debug_stub/debug_stub.h" | |
16 | |
17 using namespace nacl_debug_conn; | |
18 using std::string; | |
19 using std::stringstream; | |
20 | |
21 | |
22 DebugPipe::DebugPipe(DebugStream *io_ptr) | |
23 : io_(0), | |
24 seq_(0) { | |
25 io_ = io_ptr; | |
26 } | |
27 | |
28 DebugPipe::~DebugPipe() { | |
29 if (io_) { | |
30 delete io_; | |
31 io_ = 0; | |
32 } | |
33 } | |
34 | |
35 DebugStream *DebugPipe::GetIO() { | |
36 return io_; | |
37 } | |
38 | |
39 void DebugPipe::SetName(const char *name) { | |
40 name_ = name; | |
41 } | |
42 | |
43 const char *DebugPipe::GetName() const { | |
44 return name_.data(); | |
45 } | |
46 | |
47 bool DebugPipe::DataAvail() const { | |
48 if (io_) | |
49 return io_->DataAvail(); | |
50 | |
51 return false; | |
52 } | |
53 | |
54 | |
55 DebugPipe::DPResult DebugPipe::GetChar(char *ch) { | |
56 int32_t len = GetIO()->Read(ch, 1); | |
57 if (len == -1) | |
58 return DPR_ERROR; | |
59 | |
60 if (len == 0) | |
61 return DPR_NO_DATA; | |
62 | |
63 return DPR_OK; | |
64 } | |
65 | |
66 | |
67 DebugPipe::DPResult DebugPipe::SendPacket(DebugPacket *pkt) { | |
68 DebugPipe::DPResult res; | |
69 char ch; | |
70 | |
71 // If we are ignoring ACKs.. | |
72 if (GetFlags() & DPF_IGNORE_ACK) { | |
73 return SendPacketOnly(pkt); | |
74 } | |
75 | |
76 do { | |
77 res = SendPacketOnly(pkt); | |
78 // Verify we sent OK | |
79 if (res != DPR_OK) | |
80 break; | |
81 | |
82 // If ACKs are off, we are done. | |
83 if (GetFlags() & DPF_IGNORE_ACK) | |
84 break; | |
85 // Otherwise, poll for '+' | |
86 if (GetChar(&ch) == DPR_ERROR) | |
87 return DPR_ERROR; | |
88 // Retry if we didn't get a '+' | |
89 } while (ch != '+'); | |
90 | |
91 return res; | |
92 } | |
93 | |
94 DebugPipe::DPResult DebugPipe::SendPacketOnly(DebugPacket *pkt) { | |
95 const unsigned char *ptr = (const unsigned char*)(pkt->GetPayload()); | |
96 unsigned char ch; | |
97 stringstream outstr; | |
98 const char* curr_function = "DebugPipe::SendPacketOnly"; | |
99 unsigned char run_xsum = 0; | |
100 int32_t seq; | |
101 | |
102 if ((pkt->GetSequence(&seq) == false) && (GetFlags() & DPF_USE_SEQ)) { | |
103 pkt->SetSequence(seq_++); | |
104 } | |
105 debug_log_info("Inside %s\n", curr_function); | |
106 // Signal start of response | |
107 outstr << '$'; | |
108 | |
109 // Note: we are no longer looking for sequence numbers. | |
110 | |
111 // Send the main payload | |
112 int offs = 0; | |
113 while (ch = ptr[offs++]) { | |
114 outstr << ch; | |
115 run_xsum += ch; | |
116 } | |
117 | |
118 // Send XSUM as two nible 8bit value preceeded by '#' | |
119 outstr << '#'; | |
120 ch = debug_int_to_nibble(run_xsum >> 4); | |
121 outstr << ch; | |
122 ch = debug_int_to_nibble(run_xsum & 0xF); | |
123 outstr << ch; | |
124 delete[] ptr; | |
125 return SendStream(outstr.str().data()); | |
126 } | |
127 | |
128 DebugPipe::DPResult DebugPipe::SendStream(const char *out) { | |
129 int32_t len = static_cast<int32_t>(strlen(out)); | |
130 int32_t sent= 0; | |
131 | |
132 while (sent < len) { | |
133 char *cur = const_cast<char *>(&out[sent]); | |
134 int32_t tx = GetIO()->Write(cur, len - sent); | |
135 | |
136 if (tx <= 0) { | |
137 debug_log_warning("DebugPipe::SendStream %d bytes : '%s' failed.\n", | |
138 len, out); | |
139 return DPR_ERROR; | |
140 } | |
141 | |
142 sent += tx; | |
143 } | |
144 | |
145 if (GetFlags() & DPF_DEBUG_SEND) | |
146 debug_log_info("TX %s:%s\n", name_.c_str(), out); | |
147 return DPR_OK; | |
148 } | |
149 | |
150 | |
151 // Attempt to receive a packet | |
152 DebugPipe::DPResult DebugPipe::GetPacket(DebugPacket *pkt) { | |
153 const char *curr_function = "DebugPipe::GetPacket"; | |
154 char run_xsum, fin_xsum, ch; | |
155 stringstream in; | |
156 int has_seq, offs; | |
157 | |
158 // If nothing is waiting, return NONE | |
159 if (GetIO()->DataAvail() == DPR_NO_DATA) { | |
160 debug_log_warning("%s return DPR_NO_DATA\n", curr_function); | |
161 return DPR_NO_DATA; | |
162 } | |
163 | |
164 // Toss characters until we see a start of command | |
165 do { | |
166 if (GetChar(&ch) == DPR_ERROR) { | |
167 debug_log_warning("%s return DPR_ERROR\n", curr_function); | |
168 return DPR_ERROR; | |
169 } | |
170 in << ch; | |
171 } while (ch != '$'); | |
172 | |
173 retry: | |
174 has_seq = 1; | |
175 offs = 0; | |
176 | |
177 // If nothing is waiting, return NONE | |
178 if (GetIO()->DataAvail() == DPR_NO_DATA) { | |
179 debug_log_warning("%s return DPR_NO_DATA 2\n", curr_function); | |
180 return DPR_NO_DATA; | |
181 } | |
182 | |
183 // Clear the stream | |
184 pkt->Clear(); | |
185 | |
186 // Prepare XSUM calc | |
187 run_xsum = 0; | |
188 fin_xsum = 0; | |
189 | |
190 // Stream in the characters | |
191 while (1) { | |
192 if (GetChar(&ch) == DPR_ERROR) { | |
193 debug_log_warning("%s return DPR_ERROR 3\n", curr_function); | |
194 return DPR_ERROR; | |
195 } | |
196 | |
197 in << ch; | |
198 // Check SEQ statemachine xx: | |
199 switch(offs) { | |
200 case 0: | |
201 case 1: | |
202 if (debug_nibble_to_int(ch) == -1) | |
203 has_seq = 0; | |
204 break; | |
205 | |
206 case 2: | |
207 if (ch != ':') | |
208 has_seq = 0; | |
209 break; | |
210 } | |
211 offs++; | |
212 | |
213 // If we see a '#' we must be done with the data | |
214 if (ch == '#') | |
215 break; | |
216 | |
217 // If we see a '$' we must have missed the last cmd | |
218 if (ch == '$') { | |
219 debug_log_info("%s RX Missing $, retry.\n", curr_function); | |
220 goto retry; | |
221 } | |
222 // Keep a running XSUM | |
223 run_xsum += ch; | |
224 pkt->AddRawChar(ch); | |
225 } | |
226 | |
227 // Get two Nibble XSUM | |
228 if (GetChar(&ch) == DPR_ERROR) { | |
229 debug_log_warning("%s return DPR_ERROR 5\n", curr_function); | |
230 return DPR_ERROR; | |
231 } | |
232 in << ch; | |
233 fin_xsum = debug_nibble_to_int(ch) << 4; | |
234 | |
235 if (GetChar(&ch) == DPR_ERROR) | |
236 return DPR_ERROR; | |
237 in << ch; | |
238 fin_xsum |= debug_nibble_to_int(ch); | |
239 | |
240 if (GetFlags() & DPF_DEBUG_RECV) { | |
241 string str = in.str(); | |
242 debug_log_info("RX [%s] [%s]\n", | |
243 str.c_str(), | |
244 curr_function); | |
245 } | |
246 | |
247 // FIXME -- dead code below? No packets should have a sequence number | |
248 // Pull off the sequence number if we have one | |
249 if (has_seq) { | |
250 uint8_t seq; | |
251 char ch; | |
252 | |
253 pkt->GetByte(&seq); | |
254 pkt->SetSequence(seq); | |
255 pkt->GetRawChar(&ch); | |
256 debug_log_error("ERROR IN %s has seq is TRUE\n", curr_function); | |
257 if (ch != ':') { | |
258 debug_log_error("ERROR %s RX mismatched SEQ seq=%d ch=%d.\n", | |
259 curr_function, seq, ch); | |
260 return DPR_ERROR; | |
261 } | |
262 } | |
263 | |
264 // If the XSUMs don't match, signal bad packet | |
265 if (fin_xsum == run_xsum) { | |
266 char out[4] = { '+', 0, 0, 0}; | |
267 | |
268 // We are no longer checking for sequence number and adding one | |
269 // on if needed. | |
270 debug_log_info("%s calling SendStream [%s]\n", curr_function, out); | |
271 return SendStream(out); | |
272 } else { | |
273 // Resend a bad XSUM and look for retransmit | |
274 SendStream("-"); | |
275 debug_log_info("%s RX Bad XSUM, retry\n", curr_function); | |
276 goto retry; | |
277 } | |
278 | |
279 debug_log_info("%s returning DPR_OK at bottom\n", curr_function); | |
280 return DPR_OK; | |
281 } | |
282 | |
283 | |
OLD | NEW |