OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "bin/dbg_connection.h" |
| 6 #include "bin/dartutils.h" |
| 7 #include "bin/fdutils.h" |
| 8 #include "bin/socket.h" |
| 9 #include "bin/thread.h" |
| 10 #include "bin/utils.h" |
| 11 |
| 12 #include "platform/globals.h" |
| 13 #include "platform/json.h" |
| 14 #include "platform/thread.h" |
| 15 #include "platform/utils.h" |
| 16 |
| 17 #include "include/dart_api.h" |
| 18 |
| 19 |
| 20 int DebuggerConnectionHandler::listener_fd_ = -1; |
| 21 int DebuggerConnectionHandler::debugger_fd_ = -1; |
| 22 MessageBuffer* DebuggerConnectionHandler::msgbuf_ = NULL; |
| 23 |
| 24 bool DebuggerConnectionHandler::handler_started_ = false; |
| 25 |
| 26 |
| 27 // TODO(hausner): Need better error handling. |
| 28 #define ASSERT_NOT_ERROR(handle) \ |
| 29 ASSERT(!Dart_IsError(handle)) |
| 30 |
| 31 |
| 32 class MessageBuffer { |
| 33 public: |
| 34 explicit MessageBuffer(int fd); |
| 35 ~MessageBuffer(); |
| 36 void ReadData(); |
| 37 bool IsValidMessage() const; |
| 38 void PopMessage(); |
| 39 int MessageId() const; |
| 40 char* buf() const { return buf_; } |
| 41 bool Alive() const { return connection_is_alive_; } |
| 42 |
| 43 private: |
| 44 static const int kInitialBufferSize = 256; |
| 45 char* buf_; |
| 46 int buf_length_; |
| 47 int fd_; |
| 48 int data_length_; |
| 49 bool connection_is_alive_; |
| 50 |
| 51 DISALLOW_COPY_AND_ASSIGN(MessageBuffer); |
| 52 }; |
| 53 |
| 54 |
| 55 MessageBuffer::MessageBuffer(int fd) |
| 56 : buf_(NULL), |
| 57 buf_length_(0), |
| 58 fd_(fd), |
| 59 data_length_(0), |
| 60 connection_is_alive_(true) { |
| 61 buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize)); |
| 62 if (buf_ == NULL) { |
| 63 FATAL("Failed to allocate message buffer\n"); |
| 64 } |
| 65 buf_length_ = kInitialBufferSize; |
| 66 buf_[0] = '\0'; |
| 67 data_length_ = 0; |
| 68 } |
| 69 |
| 70 |
| 71 MessageBuffer::~MessageBuffer() { |
| 72 free(buf_); |
| 73 buf_ = NULL; |
| 74 fd_ = -1; |
| 75 } |
| 76 |
| 77 |
| 78 bool MessageBuffer::IsValidMessage() const { |
| 79 if (data_length_ == 0) { |
| 80 return false; |
| 81 } |
| 82 dart::JSONReader msg_reader(buf_); |
| 83 return msg_reader.EndOfObject() != NULL; |
| 84 } |
| 85 |
| 86 |
| 87 int MessageBuffer::MessageId() const { |
| 88 dart::JSONReader r(buf_); |
| 89 r.Seek("id"); |
| 90 if (r.Type() == dart::JSONReader::kInteger) { |
| 91 return atoi(r.ValueChars()); |
| 92 } else { |
| 93 return -1; |
| 94 } |
| 95 } |
| 96 |
| 97 |
| 98 void MessageBuffer::ReadData() { |
| 99 ASSERT(data_length_ >= 0); |
| 100 ASSERT(data_length_ < buf_length_); |
| 101 int max_read = buf_length_ - data_length_ - 1; |
| 102 if (max_read == 0) { |
| 103 // TODO(hausner): |
| 104 // Buffer is full. What should we do if there is no valid message |
| 105 // in the buffer? This might be possible if the client sends a message |
| 106 // that's larger than the buffer, of if the client sends malformed |
| 107 // messages that keep piling up. |
| 108 ASSERT(IsValidMessage()); |
| 109 return; |
| 110 } |
| 111 // TODO(hausner): Handle error conditions returned by Read. We may |
| 112 // want to close the debugger connection if we get any errors. |
| 113 int bytes_read = Socket::Read(fd_, buf_ + data_length_, max_read); |
| 114 if (bytes_read == 0) { |
| 115 connection_is_alive_ = false; |
| 116 return; |
| 117 } |
| 118 ASSERT(bytes_read > 0); |
| 119 data_length_ += bytes_read; |
| 120 ASSERT(data_length_ < buf_length_); |
| 121 buf_[data_length_] = '\0'; |
| 122 } |
| 123 |
| 124 |
| 125 void MessageBuffer::PopMessage() { |
| 126 dart::JSONReader msg_reader(buf_); |
| 127 const char* end = msg_reader.EndOfObject(); |
| 128 if (end != NULL) { |
| 129 ASSERT(*end == '}'); |
| 130 end++; |
| 131 data_length_ = 0; |
| 132 while (*end != '\0') { |
| 133 buf_[data_length_] = *end++; |
| 134 data_length_++; |
| 135 } |
| 136 buf_[data_length_] = '\0'; |
| 137 ASSERT(data_length_ < buf_length_); |
| 138 } |
| 139 } |
| 140 |
| 141 |
| 142 static bool IsValidJSON(const char* msg) { |
| 143 dart::JSONReader r(msg); |
| 144 return r.EndOfObject() != NULL; |
| 145 } |
| 146 |
| 147 |
| 148 void DebuggerConnectionHandler::HandleResumeCmd() { |
| 149 int msg_id = msgbuf_->MessageId(); |
| 150 dart::TextBuffer msg(64); |
| 151 msg.Printf("{ \"id\": %d }", msg_id); |
| 152 FDUtils::WriteToBlocking(debugger_fd_, msg.buf(), msg.length()); |
| 153 // TODO(hausner): Error checking. Probably just shut down the debugger |
| 154 // session if we there is an error while writing. |
| 155 } |
| 156 |
| 157 |
| 158 void DebuggerConnectionHandler::HandleMessages() { |
| 159 for (;;) { |
| 160 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) { |
| 161 msgbuf_->ReadData(); |
| 162 } |
| 163 if (!msgbuf_->Alive()) { |
| 164 return; |
| 165 } |
| 166 dart::JSONReader r(msgbuf_->buf()); |
| 167 bool found = r.Seek("command"); |
| 168 if (r.Error()) { |
| 169 FATAL("Illegal JSON message received"); |
| 170 } |
| 171 if (!found) { |
| 172 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf()); |
| 173 msgbuf_->PopMessage(); |
| 174 } else if (r.IsStringLiteral("resume")) { |
| 175 HandleResumeCmd(); |
| 176 msgbuf_->PopMessage(); |
| 177 return; |
| 178 } else { |
| 179 printf("unrecognized command received: '%s'\n", msgbuf_->buf()); |
| 180 msgbuf_->PopMessage(); |
| 181 } |
| 182 } |
| 183 } |
| 184 |
| 185 |
| 186 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_Breakpoint bpt, |
| 187 Dart_StackTrace trace) { |
| 188 dart::TextBuffer msg(128); |
| 189 intptr_t trace_len = 0; |
| 190 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); |
| 191 ASSERT_NOT_ERROR(res); |
| 192 msg.Printf("{ \"command\" : \"paused\", \"params\" : "); |
| 193 msg.Printf("{ \"callFrames\" : [ "); |
| 194 for (int i = 0; i < trace_len; i++) { |
| 195 Dart_ActivationFrame frame; |
| 196 res = Dart_GetActivationFrame(trace, i, &frame); |
| 197 ASSERT_NOT_ERROR(res); |
| 198 Dart_Handle func_name; |
| 199 Dart_Handle script_url; |
| 200 intptr_t line_number = 0; |
| 201 res = Dart_ActivationFrameInfo( |
| 202 frame, &func_name, &script_url, &line_number); |
| 203 ASSERT_NOT_ERROR(res); |
| 204 ASSERT(Dart_IsString(func_name)); |
| 205 const char* func_name_chars; |
| 206 Dart_StringToCString(func_name, &func_name_chars); |
| 207 msg.Printf("%s { \"functionName\" : \"%s\" , ", |
| 208 i > 0 ? "," : "", |
| 209 func_name_chars); |
| 210 ASSERT(Dart_IsString(script_url)); |
| 211 const char* script_url_chars; |
| 212 Dart_StringToCString(script_url, &script_url_chars); |
| 213 msg.Printf("\"location\": { \"scriptId\": \"%s\", \"lineNumber\": %d }}", |
| 214 script_url_chars, line_number); |
| 215 } |
| 216 msg.Printf("]}}"); |
| 217 Socket::Write(debugger_fd_, msg.buf(), msg.length()); |
| 218 ASSERT(IsValidJSON(msg.buf())); |
| 219 } |
| 220 |
| 221 |
| 222 void DebuggerConnectionHandler::BreakpointHandler(Dart_Breakpoint bpt, |
| 223 Dart_StackTrace trace) { |
| 224 // TODO(hausner): rather than busy-waiting, block on the pipe to the |
| 225 // debugger thread and wait until a debugger connection has been |
| 226 // established. |
| 227 while (!IsConnected()) { |
| 228 printf("Waiting for debugger connection\n"); |
| 229 sleep(1); |
| 230 } |
| 231 SendBreakpointEvent(bpt, trace); |
| 232 HandleMessages(); |
| 233 if (!msgbuf_->Alive()) { |
| 234 CloseDbgConnection(); |
| 235 } |
| 236 } |
| 237 |
| 238 |
| 239 void DebuggerConnectionHandler::AcceptDbgConnection(int debugger_fd) { |
| 240 debugger_fd_ = debugger_fd; |
| 241 ASSERT(msgbuf_ == NULL); |
| 242 msgbuf_ = new MessageBuffer(debugger_fd_); |
| 243 } |
| 244 |
| 245 void DebuggerConnectionHandler::CloseDbgConnection() { |
| 246 if (debugger_fd_ >= 0) { |
| 247 // TODO(hausner): need a Socket::Close() function. |
| 248 } |
| 249 if (msgbuf_ != NULL) { |
| 250 delete msgbuf_; |
| 251 msgbuf_ = NULL; |
| 252 } |
| 253 // TODO(hausner): Need to tell the VM debugger object to remove all |
| 254 // breakpoints. |
| 255 } |
| 256 |
| 257 void DebuggerConnectionHandler::StartHandler(const char* address, |
| 258 int port_number) { |
| 259 if (handler_started_) { |
| 260 return; |
| 261 } |
| 262 ASSERT(listener_fd_ == -1); |
| 263 listener_fd_ = ServerSocket::CreateBindListen(address, port_number, 1); |
| 264 |
| 265 handler_started_ = true; |
| 266 DebuggerConnectionImpl::StartHandler(port_number); |
| 267 Dart_SetBreakpointHandler(BreakpointHandler); |
| 268 } |
| 269 |
| 270 |
| 271 DebuggerConnectionHandler::~DebuggerConnectionHandler() { |
| 272 CloseDbgConnection(); |
| 273 } |
OLD | NEW |