GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/inspector_io.cc Lines: 0 145 0.0 %
Date: 2019-02-01 22:03:38 Branches: 0 50 0.0 %

Line Branch Exec Source
1
#include "inspector_io.h"
2
3
#include "inspector_socket_server.h"
4
#include "inspector/main_thread_interface.h"
5
#include "inspector/node_string.h"
6
#include "env-inl.h"
7
#include "debug_utils.h"
8
#include "node.h"
9
#include "node_crypto.h"
10
#include "node_mutex.h"
11
#include "v8-inspector.h"
12
#include "util.h"
13
#include "zlib.h"
14
15
#include <deque>
16
#include <string.h>
17
#include <vector>
18
19
namespace node {
20
namespace inspector {
21
namespace {
22
using v8_inspector::StringBuffer;
23
using v8_inspector::StringView;
24
25
std::string ScriptPath(uv_loop_t* loop, const std::string& script_name) {
26
  std::string script_path;
27
28
  if (!script_name.empty()) {
29
    uv_fs_t req;
30
    req.ptr = nullptr;
31
    if (0 == uv_fs_realpath(loop, &req, script_name.c_str(), nullptr)) {
32
      CHECK_NOT_NULL(req.ptr);
33
      script_path = std::string(static_cast<char*>(req.ptr));
34
    }
35
    uv_fs_req_cleanup(&req);
36
  }
37
38
  return script_path;
39
}
40
41
// UUID RFC: https://www.ietf.org/rfc/rfc4122.txt
42
// Used ver 4 - with numbers
43
std::string GenerateID() {
44
  uint16_t buffer[8];
45
  CHECK(crypto::EntropySource(reinterpret_cast<unsigned char*>(buffer),
46
                              sizeof(buffer)));
47
48
  char uuid[256];
49
  snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
50
           buffer[0],  // time_low
51
           buffer[1],  // time_mid
52
           buffer[2],  // time_low
53
           (buffer[3] & 0x0fff) | 0x4000,  // time_hi_and_version
54
           (buffer[4] & 0x3fff) | 0x8000,  // clk_seq_hi clk_seq_low
55
           buffer[5],  // node
56
           buffer[6],
57
           buffer[7]);
58
  return uuid;
59
}
60
61
class RequestToServer {
62
 public:
63
  RequestToServer(TransportAction action,
64
                  int session_id,
65
                  std::unique_ptr<v8_inspector::StringBuffer> message)
66
                  : action_(action),
67
                    session_id_(session_id),
68
                    message_(std::move(message)) {}
69
70
  void Dispatch(InspectorSocketServer* server) const {
71
    switch (action_) {
72
      case TransportAction::kKill:
73
        server->TerminateConnections();
74
        // Fallthrough
75
      case TransportAction::kStop:
76
        server->Stop();
77
        break;
78
      case TransportAction::kSendMessage:
79
        server->Send(
80
            session_id_,
81
            protocol::StringUtil::StringViewToUtf8(message_->string()));
82
        break;
83
    }
84
  }
85
86
 private:
87
  TransportAction action_;
88
  int session_id_;
89
  std::unique_ptr<v8_inspector::StringBuffer> message_;
90
};
91
92
class RequestQueueData {
93
 public:
94
  using MessageQueue = std::deque<RequestToServer>;
95
96
  explicit RequestQueueData(uv_loop_t* loop)
97
                            : handle_(std::make_shared<RequestQueue>(this)) {
98
    int err = uv_async_init(loop, &async_, [](uv_async_t* async) {
99
      RequestQueueData* wrapper =
100
          node::ContainerOf(&RequestQueueData::async_, async);
101
      wrapper->DoDispatch();
102
    });
103
    CHECK_EQ(0, err);
104
  }
105
106
  static void CloseAndFree(RequestQueueData* queue);
107
108
  void Post(int session_id,
109
            TransportAction action,
110
            std::unique_ptr<StringBuffer> message) {
111
    Mutex::ScopedLock scoped_lock(state_lock_);
112
    bool notify = messages_.empty();
113
    messages_.emplace_back(action, session_id, std::move(message));
114
    if (notify) {
115
      CHECK_EQ(0, uv_async_send(&async_));
116
      incoming_message_cond_.Broadcast(scoped_lock);
117
    }
118
  }
119
120
  void Wait() {
121
    Mutex::ScopedLock scoped_lock(state_lock_);
122
    if (messages_.empty()) {
123
      incoming_message_cond_.Wait(scoped_lock);
124
    }
125
  }
126
127
  void SetServer(InspectorSocketServer* server) {
128
    server_ = server;
129
  }
130
131
  std::shared_ptr<RequestQueue> handle() {
132
    return handle_;
133
  }
134
135
 private:
136
  ~RequestQueueData() = default;
137
138
  MessageQueue GetMessages() {
139
    Mutex::ScopedLock scoped_lock(state_lock_);
140
    MessageQueue messages;
141
    messages_.swap(messages);
142
    return messages;
143
  }
144
145
  void DoDispatch() {
146
    if (server_ == nullptr)
147
      return;
148
    for (const auto& request : GetMessages()) {
149
      request.Dispatch(server_);
150
    }
151
  }
152
153
  std::shared_ptr<RequestQueue> handle_;
154
  uv_async_t async_;
155
  InspectorSocketServer* server_ = nullptr;
156
  MessageQueue messages_;
157
  Mutex state_lock_;  // Locked before mutating the queue.
158
  ConditionVariable incoming_message_cond_;
159
};
160
}  // namespace
161
162
class RequestQueue {
163
 public:
164
  explicit RequestQueue(RequestQueueData* data) : data_(data) {}
165
166
  void Reset() {
167
    Mutex::ScopedLock scoped_lock(lock_);
168
    data_ = nullptr;
169
  }
170
171
  void Post(int session_id,
172
            TransportAction action,
173
            std::unique_ptr<StringBuffer> message) {
174
    Mutex::ScopedLock scoped_lock(lock_);
175
    if (data_ != nullptr)
176
      data_->Post(session_id, action, std::move(message));
177
  }
178
179
  void SetServer(InspectorSocketServer* server) {
180
    Mutex::ScopedLock scoped_lock(lock_);
181
    if (data_ != nullptr)
182
      data_->SetServer(server);
183
  }
184
185
  bool Expired() {
186
    Mutex::ScopedLock scoped_lock(lock_);
187
    return data_ == nullptr;
188
  }
189
190
 private:
191
  RequestQueueData* data_;
192
  Mutex lock_;
193
};
194
195
class IoSessionDelegate : public InspectorSessionDelegate {
196
 public:
197
  explicit IoSessionDelegate(std::shared_ptr<RequestQueue> queue, int id)
198
                             : request_queue_(queue), id_(id) { }
199
  void SendMessageToFrontend(const v8_inspector::StringView& message) override {
200
    request_queue_->Post(id_, TransportAction::kSendMessage,
201
                         StringBuffer::create(message));
202
  }
203
204
 private:
205
  std::shared_ptr<RequestQueue> request_queue_;
206
  int id_;
207
};
208
209
// Passed to InspectorSocketServer to handle WS inspector protocol events,
210
// mostly session start, message received, and session end.
211
class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
212
 public:
213
  InspectorIoDelegate(std::shared_ptr<RequestQueueData> queue,
214
                      std::shared_ptr<MainThreadHandle> main_threade,
215
                      const std::string& target_id,
216
                      const std::string& script_path,
217
                      const std::string& script_name);
218
  ~InspectorIoDelegate() {
219
  }
220
221
  void StartSession(int session_id, const std::string& target_id) override;
222
  void MessageReceived(int session_id, const std::string& message) override;
223
  void EndSession(int session_id) override;
224
225
  std::vector<std::string> GetTargetIds() override;
226
  std::string GetTargetTitle(const std::string& id) override;
227
  std::string GetTargetUrl(const std::string& id) override;
228
  void AssignServer(InspectorSocketServer* server) override {
229
    request_queue_->SetServer(server);
230
  }
231
232
 private:
233
  std::shared_ptr<RequestQueueData> request_queue_;
234
  std::shared_ptr<MainThreadHandle> main_thread_;
235
  std::unordered_map<int, std::unique_ptr<InspectorSession>> sessions_;
236
  const std::string script_name_;
237
  const std::string script_path_;
238
  const std::string target_id_;
239
};
240
241
// static
242
std::unique_ptr<InspectorIo> InspectorIo::Start(
243
    std::shared_ptr<MainThreadHandle> main_thread,
244
    const std::string& path,
245
    std::shared_ptr<HostPort> host_port) {
246
  auto io = std::unique_ptr<InspectorIo>(
247
      new InspectorIo(main_thread, path, host_port));
248
  if (io->request_queue_->Expired()) {  // Thread is not running
249
    return nullptr;
250
  }
251
  return io;
252
}
253
254
InspectorIo::InspectorIo(std::shared_ptr<MainThreadHandle> main_thread,
255
                         const std::string& path,
256
                         std::shared_ptr<HostPort> host_port)
257
    : main_thread_(main_thread),
258
      host_port_(host_port),
259
      thread_(),
260
      script_name_(path),
261
      id_(GenerateID()) {
262
  Mutex::ScopedLock scoped_lock(thread_start_lock_);
263
  CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadMain, this), 0);
264
  thread_start_condition_.Wait(scoped_lock);
265
}
266
267
InspectorIo::~InspectorIo() {
268
  request_queue_->Post(0, TransportAction::kKill, nullptr);
269
  int err = uv_thread_join(&thread_);
270
  CHECK_EQ(err, 0);
271
}
272
273
void InspectorIo::StopAcceptingNewConnections() {
274
  request_queue_->Post(0, TransportAction::kStop, nullptr);
275
}
276
277
// static
278
void InspectorIo::ThreadMain(void* io) {
279
  static_cast<InspectorIo*>(io)->ThreadMain();
280
}
281
282
void InspectorIo::ThreadMain() {
283
  uv_loop_t loop;
284
  loop.data = nullptr;
285
  int err = uv_loop_init(&loop);
286
  CHECK_EQ(err, 0);
287
  std::shared_ptr<RequestQueueData> queue(new RequestQueueData(&loop),
288
                                          RequestQueueData::CloseAndFree);
289
  std::string script_path = ScriptPath(&loop, script_name_);
290
  std::unique_ptr<InspectorIoDelegate> delegate(
291
      new InspectorIoDelegate(queue, main_thread_, id_,
292
                              script_path, script_name_));
293
  InspectorSocketServer server(std::move(delegate),
294
                               &loop,
295
                               host_port_->host().c_str(),
296
                               host_port_->port());
297
  request_queue_ = queue->handle();
298
  // Its lifetime is now that of the server delegate
299
  queue.reset();
300
  {
301
    Mutex::ScopedLock scoped_lock(thread_start_lock_);
302
    if (server.Start()) {
303
      host_port_->set_port(server.Port());
304
    }
305
    thread_start_condition_.Broadcast(scoped_lock);
306
  }
307
  uv_run(&loop, UV_RUN_DEFAULT);
308
  CheckedUvLoopClose(&loop);
309
}
310
311
std::vector<std::string> InspectorIo::GetTargetIds() const {
312
  return { id_ };
313
}
314
315
InspectorIoDelegate::InspectorIoDelegate(
316
    std::shared_ptr<RequestQueueData> queue,
317
    std::shared_ptr<MainThreadHandle> main_thread,
318
    const std::string& target_id,
319
    const std::string& script_path,
320
    const std::string& script_name)
321
    : request_queue_(queue), main_thread_(main_thread),
322
      script_name_(script_name), script_path_(script_path),
323
      target_id_(target_id) {}
324
325
void InspectorIoDelegate::StartSession(int session_id,
326
                                       const std::string& target_id) {
327
  auto session = main_thread_->Connect(
328
      std::unique_ptr<InspectorSessionDelegate>(
329
          new IoSessionDelegate(request_queue_->handle(), session_id)), true);
330
  if (session) {
331
    sessions_[session_id] = std::move(session);
332
    fprintf(stderr, "Debugger attached.\n");
333
  }
334
}
335
336
void InspectorIoDelegate::MessageReceived(int session_id,
337
                                          const std::string& message) {
338
  auto session = sessions_.find(session_id);
339
  if (session != sessions_.end())
340
    session->second->Dispatch(Utf8ToStringView(message)->string());
341
}
342
343
void InspectorIoDelegate::EndSession(int session_id) {
344
  sessions_.erase(session_id);
345
}
346
347
std::vector<std::string> InspectorIoDelegate::GetTargetIds() {
348
  return { target_id_ };
349
}
350
351
std::string InspectorIoDelegate::GetTargetTitle(const std::string& id) {
352
  return script_name_.empty() ? GetHumanReadableProcessName() : script_name_;
353
}
354
355
std::string InspectorIoDelegate::GetTargetUrl(const std::string& id) {
356
  return "file://" + script_path_;
357
}
358
359
// static
360
void RequestQueueData::CloseAndFree(RequestQueueData* queue) {
361
  queue->handle_->Reset();
362
  queue->handle_.reset();
363
  uv_close(reinterpret_cast<uv_handle_t*>(&queue->async_),
364
           [](uv_handle_t* handle) {
365
    uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
366
    RequestQueueData* wrapper =
367
        node::ContainerOf(&RequestQueueData::async_, async);
368
    delete wrapper;
369
  });
370
}
371
}  // namespace inspector
372
}  // namespace node