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: 165 165 100.0 %
Date: 2019-05-05 22:32:45 Branches: 36 50 72.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 "base_object-inl.h"
7
#include "env-inl.h"
8
#include "debug_utils.h"
9
#include "node.h"
10
#include "node_crypto.h"
11
#include "node_internals.h"
12
#include "node_mutex.h"
13
#include "v8-inspector.h"
14
#include "util.h"
15
#include "zlib.h"
16
17
#include <deque>
18
#include <cstring>
19
#include <vector>
20
21
namespace node {
22
namespace inspector {
23
namespace {
24
using v8_inspector::StringBuffer;
25
using v8_inspector::StringView;
26
27
74
std::string ScriptPath(uv_loop_t* loop, const std::string& script_name) {
28
74
  std::string script_path;
29
30
74
  if (!script_name.empty()) {
31
    uv_fs_t req;
32
59
    req.ptr = nullptr;
33
59
    if (0 == uv_fs_realpath(loop, &req, script_name.c_str(), nullptr)) {
34
58
      CHECK_NOT_NULL(req.ptr);
35
58
      script_path = std::string(static_cast<char*>(req.ptr));
36
    }
37
59
    uv_fs_req_cleanup(&req);
38
  }
39
40
74
  return script_path;
41
}
42
43
// UUID RFC: https://www.ietf.org/rfc/rfc4122.txt
44
// Used ver 4 - with numbers
45
74
std::string GenerateID() {
46
  uint16_t buffer[8];
47
74
  CHECK(crypto::EntropySource(reinterpret_cast<unsigned char*>(buffer),
48
                              sizeof(buffer)));
49
50
  char uuid[256];
51
  snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
52
74
           buffer[0],  // time_low
53
74
           buffer[1],  // time_mid
54
74
           buffer[2],  // time_low
55
74
           (buffer[3] & 0x0fff) | 0x4000,  // time_hi_and_version
56
74
           (buffer[4] & 0x3fff) | 0x8000,  // clk_seq_hi clk_seq_low
57
74
           buffer[5],  // node
58
74
           buffer[6],
59
592
           buffer[7]);
60
74
  return uuid;
61
}
62
63
877
class RequestToServer {
64
 public:
65
877
  RequestToServer(TransportAction action,
66
                  int session_id,
67
                  std::unique_ptr<v8_inspector::StringBuffer> message)
68
                  : action_(action),
69
                    session_id_(session_id),
70
877
                    message_(std::move(message)) {}
71
72
874
  void Dispatch(InspectorSocketServer* server) const {
73

874
    switch (action_) {
74
      case TransportAction::kKill:
75
4
        server->TerminateConnections();
76
        // Fallthrough
77
      case TransportAction::kStop:
78
73
        server->Stop();
79
73
        break;
80
      case TransportAction::kSendMessage:
81
        server->Send(
82
            session_id_,
83
801
            protocol::StringUtil::StringViewToUtf8(message_->string()));
84
801
        break;
85
    }
86
874
  }
87
88
 private:
89
  TransportAction action_;
90
  int session_id_;
91
  std::unique_ptr<v8_inspector::StringBuffer> message_;
92
};
93
94
class RequestQueueData {
95
 public:
96
  using MessageQueue = std::deque<RequestToServer>;
97
98
74
  explicit RequestQueueData(uv_loop_t* loop)
99
74
                            : handle_(std::make_shared<RequestQueue>(this)) {
100
1730
    int err = uv_async_init(loop, &async_, [](uv_async_t* async) {
101
      RequestQueueData* wrapper =
102
828
          node::ContainerOf(&RequestQueueData::async_, async);
103
828
      wrapper->DoDispatch();
104
1804
    });
105
74
    CHECK_EQ(0, err);
106
74
  }
107
108
  static void CloseAndFree(RequestQueueData* queue);
109
110
877
  void Post(int session_id,
111
            TransportAction action,
112
            std::unique_ptr<StringBuffer> message) {
113
877
    Mutex::ScopedLock scoped_lock(state_lock_);
114
877
    bool notify = messages_.empty();
115
877
    messages_.emplace_back(action, session_id, std::move(message));
116
877
    if (notify) {
117
831
      CHECK_EQ(0, uv_async_send(&async_));
118
831
      incoming_message_cond_.Broadcast(scoped_lock);
119
877
    }
120
877
  }
121
122
  void Wait() {
123
    Mutex::ScopedLock scoped_lock(state_lock_);
124
    if (messages_.empty()) {
125
      incoming_message_cond_.Wait(scoped_lock);
126
    }
127
  }
128
129
74
  void SetServer(InspectorSocketServer* server) {
130
74
    server_ = server;
131
74
  }
132
133
87
  std::shared_ptr<RequestQueue> handle() {
134
87
    return handle_;
135
  }
136
137
 private:
138
74
  ~RequestQueueData() = default;
139
140
828
  MessageQueue GetMessages() {
141
828
    Mutex::ScopedLock scoped_lock(state_lock_);
142
828
    MessageQueue messages;
143
828
    messages_.swap(messages);
144
828
    return messages;
145
  }
146
147
828
  void DoDispatch() {
148
828
    if (server_ == nullptr)
149
828
      return;
150
1702
    for (const auto& request : GetMessages()) {
151
874
      request.Dispatch(server_);
152
828
    }
153
  }
154
155
  std::shared_ptr<RequestQueue> handle_;
156
  uv_async_t async_;
157
  InspectorSocketServer* server_ = nullptr;
158
  MessageQueue messages_;
159
  Mutex state_lock_;  // Locked before mutating the queue.
160
  ConditionVariable incoming_message_cond_;
161
};
162
}  // namespace
163
164
41
class RequestQueue {
165
 public:
166
74
  explicit RequestQueue(RequestQueueData* data) : data_(data) {}
167
168
74
  void Reset() {
169
74
    Mutex::ScopedLock scoped_lock(lock_);
170
74
    data_ = nullptr;
171
74
  }
172
173
911
  void Post(int session_id,
174
            TransportAction action,
175
            std::unique_ptr<StringBuffer> message) {
176
911
    Mutex::ScopedLock scoped_lock(lock_);
177
911
    if (data_ != nullptr)
178
877
      data_->Post(session_id, action, std::move(message));
179
911
  }
180
181
  void SetServer(InspectorSocketServer* server) {
182
    Mutex::ScopedLock scoped_lock(lock_);
183
    if (data_ != nullptr)
184
      data_->SetServer(server);
185
  }
186
187
74
  bool Expired() {
188
74
    Mutex::ScopedLock scoped_lock(lock_);
189
74
    return data_ == nullptr;
190
  }
191
192
 private:
193
  RequestQueueData* data_;
194
  Mutex lock_;
195
};
196
197
26
class IoSessionDelegate : public InspectorSessionDelegate {
198
 public:
199
13
  explicit IoSessionDelegate(std::shared_ptr<RequestQueue> queue, int id)
200
13
                             : request_queue_(queue), id_(id) { }
201
801
  void SendMessageToFrontend(const v8_inspector::StringView& message) override {
202
    request_queue_->Post(id_, TransportAction::kSendMessage,
203
801
                         StringBuffer::create(message));
204
801
  }
205
206
 private:
207
  std::shared_ptr<RequestQueue> request_queue_;
208
  int id_;
209
};
210
211
// Passed to InspectorSocketServer to handle WS inspector protocol events,
212
// mostly session start, message received, and session end.
213
class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
214
 public:
215
  InspectorIoDelegate(std::shared_ptr<RequestQueueData> queue,
216
                      std::shared_ptr<MainThreadHandle> main_threade,
217
                      const std::string& target_id,
218
                      const std::string& script_path,
219
                      const std::string& script_name);
220
148
  ~InspectorIoDelegate() override = default;
221
222
  void StartSession(int session_id, const std::string& target_id) override;
223
  void MessageReceived(int session_id, const std::string& message) override;
224
  void EndSession(int session_id) override;
225
226
  std::vector<std::string> GetTargetIds() override;
227
  std::string GetTargetTitle(const std::string& id) override;
228
  std::string GetTargetUrl(const std::string& id) override;
229
74
  void AssignServer(InspectorSocketServer* server) override {
230
74
    request_queue_->SetServer(server);
231
74
  }
232
233
 private:
234
  std::shared_ptr<RequestQueueData> request_queue_;
235
  std::shared_ptr<MainThreadHandle> main_thread_;
236
  std::unordered_map<int, std::unique_ptr<InspectorSession>> sessions_;
237
  const std::string script_name_;
238
  const std::string script_path_;
239
  const std::string target_id_;
240
};
241
242
// static
243
74
std::unique_ptr<InspectorIo> InspectorIo::Start(
244
    std::shared_ptr<MainThreadHandle> main_thread,
245
    const std::string& path,
246
    std::shared_ptr<HostPort> host_port) {
247
  auto io = std::unique_ptr<InspectorIo>(
248
74
      new InspectorIo(main_thread, path, host_port));
249
74
  if (io->request_queue_->Expired()) {  // Thread is not running
250
1
    return nullptr;
251
  }
252
73
  return io;
253
}
254
255
74
InspectorIo::InspectorIo(std::shared_ptr<MainThreadHandle> main_thread,
256
                         const std::string& path,
257
                         std::shared_ptr<HostPort> host_port)
258
    : main_thread_(main_thread),
259
      host_port_(host_port),
260
      thread_(),
261
      script_name_(path),
262
74
      id_(GenerateID()) {
263
74
  Mutex::ScopedLock scoped_lock(thread_start_lock_);
264
74
  CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadMain, this), 0);
265
74
  thread_start_condition_.Wait(scoped_lock);
266
74
}
267
268
82
InspectorIo::~InspectorIo() {
269
41
  request_queue_->Post(0, TransportAction::kKill, nullptr);
270
41
  int err = uv_thread_join(&thread_);
271
41
  CHECK_EQ(err, 0);
272
41
}
273
274
69
void InspectorIo::StopAcceptingNewConnections() {
275
69
  request_queue_->Post(0, TransportAction::kStop, nullptr);
276
69
}
277
278
// static
279
74
void InspectorIo::ThreadMain(void* io) {
280
74
  static_cast<InspectorIo*>(io)->ThreadMain();
281
74
}
282
283
74
void InspectorIo::ThreadMain() {
284
  uv_loop_t loop;
285
74
  loop.data = nullptr;
286
74
  int err = uv_loop_init(&loop);
287
74
  CHECK_EQ(err, 0);
288
74
  std::shared_ptr<RequestQueueData> queue(new RequestQueueData(&loop),
289
148
                                          RequestQueueData::CloseAndFree);
290
148
  std::string script_path = ScriptPath(&loop, script_name_);
291
  std::unique_ptr<InspectorIoDelegate> delegate(
292
      new InspectorIoDelegate(queue, main_thread_, id_,
293
148
                              script_path, script_name_));
294
74
  InspectorSocketServer server(std::move(delegate),
295
                               &loop,
296
74
                               host_port_->host(),
297
222
                               host_port_->port());
298
74
  request_queue_ = queue->handle();
299
  // Its lifetime is now that of the server delegate
300
74
  queue.reset();
301
  {
302
74
    Mutex::ScopedLock scoped_lock(thread_start_lock_);
303
74
    if (server.Start()) {
304
73
      host_port_->set_port(server.Port());
305
    }
306
74
    thread_start_condition_.Broadcast(scoped_lock);
307
  }
308
74
  uv_run(&loop, UV_RUN_DEFAULT);
309
148
  CheckedUvLoopClose(&loop);
310
74
}
311
312
3
std::vector<std::string> InspectorIo::GetTargetIds() const {
313
3
  return { id_ };
314
}
315
316
74
InspectorIoDelegate::InspectorIoDelegate(
317
    std::shared_ptr<RequestQueueData> queue,
318
    std::shared_ptr<MainThreadHandle> main_thread,
319
    const std::string& target_id,
320
    const std::string& script_path,
321
    const std::string& script_name)
322
    : request_queue_(queue), main_thread_(main_thread),
323
      script_name_(script_name), script_path_(script_path),
324
74
      target_id_(target_id) {}
325
326
13
void InspectorIoDelegate::StartSession(int session_id,
327
                                       const std::string& target_id) {
328
  auto session = main_thread_->Connect(
329
      std::unique_ptr<InspectorSessionDelegate>(
330
13
          new IoSessionDelegate(request_queue_->handle(), session_id)), true);
331
13
  if (session) {
332
13
    sessions_[session_id] = std::move(session);
333
13
    fprintf(stderr, "Debugger attached.\n");
334
13
  }
335
13
}
336
337
113
void InspectorIoDelegate::MessageReceived(int session_id,
338
                                          const std::string& message) {
339
113
  auto session = sessions_.find(session_id);
340
113
  if (session != sessions_.end())
341
113
    session->second->Dispatch(Utf8ToStringView(message)->string());
342
113
}
343
344
13
void InspectorIoDelegate::EndSession(int session_id) {
345
13
  sessions_.erase(session_id);
346
13
}
347
348
101
std::vector<std::string> InspectorIoDelegate::GetTargetIds() {
349
101
  return { target_id_ };
350
}
351
352
15
std::string InspectorIoDelegate::GetTargetTitle(const std::string& id) {
353
15
  return script_name_.empty() ? GetHumanReadableProcessName() : script_name_;
354
}
355
356
15
std::string InspectorIoDelegate::GetTargetUrl(const std::string& id) {
357
15
  return "file://" + script_path_;
358
}
359
360
// static
361
74
void RequestQueueData::CloseAndFree(RequestQueueData* queue) {
362
74
  queue->handle_->Reset();
363
74
  queue->handle_.reset();
364
  uv_close(reinterpret_cast<uv_handle_t*>(&queue->async_),
365
222
           [](uv_handle_t* handle) {
366
74
    uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
367
    RequestQueueData* wrapper =
368
74
        node::ContainerOf(&RequestQueueData::async_, async);
369
74
    delete wrapper;
370
296
  });
371
74
}
372
}  // namespace inspector
373
}  // namespace node