GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_udp_wrap.cc Lines: 1 103 1.0 %
Date: 2021-09-08 04:14:13 Branches: 0 82 0.0 %

Line Branch Exec Source
1
#include "udp_wrap.h"
2
#include "async_wrap-inl.h"
3
#include "node_errors.h"
4
#include "node_sockaddr-inl.h"
5
6
#include <algorithm>
7
8
namespace node {
9
10
using errors::TryCatchScope;
11
using v8::Array;
12
using v8::Context;
13
using v8::FunctionCallbackInfo;
14
using v8::FunctionTemplate;
15
using v8::HandleScope;
16
using v8::Int32;
17
using v8::Local;
18
using v8::Object;
19
using v8::Value;
20
21
// JSUDPWrap is a testing utility used by test/common/udppair.js
22
// to simulate UDP traffic deterministically in Node.js tests.
23
class JSUDPWrap final : public UDPWrapBase, public AsyncWrap {
24
 public:
25
  JSUDPWrap(Environment* env, Local<Object> obj);
26
27
  int RecvStart() override;
28
  int RecvStop() override;
29
  ssize_t Send(uv_buf_t* bufs,
30
               size_t nbufs,
31
               const sockaddr* addr) override;
32
  SocketAddress GetPeerName() override;
33
  SocketAddress GetSockName() override;
34
  AsyncWrap* GetAsyncWrap() override { return this; }
35
36
  static void New(const FunctionCallbackInfo<Value>& args);
37
  static void EmitReceived(const FunctionCallbackInfo<Value>& args);
38
  static void OnSendDone(const FunctionCallbackInfo<Value>& args);
39
  static void OnAfterBind(const FunctionCallbackInfo<Value>& args);
40
41
  static void Initialize(Local<Object> target,
42
                         Local<Value> unused,
43
                         Local<Context> context,
44
                         void* priv);
45
  SET_NO_MEMORY_INFO()
46
  SET_MEMORY_INFO_NAME(JSUDPWrap)
47
  SET_SELF_SIZE(JSUDPWrap)
48
};
49
50
JSUDPWrap::JSUDPWrap(Environment* env, Local<Object> obj)
51
  : AsyncWrap(env, obj, PROVIDER_JSUDPWRAP) {
52
  MakeWeak();
53
54
  obj->SetAlignedPointerInInternalField(
55
      kUDPWrapBaseField, static_cast<UDPWrapBase*>(this));
56
}
57
58
int JSUDPWrap::RecvStart() {
59
  HandleScope scope(env()->isolate());
60
  Context::Scope context_scope(env()->context());
61
  TryCatchScope try_catch(env());
62
  Local<Value> value;
63
  int32_t value_int = UV_EPROTO;
64
  if (!MakeCallback(env()->onreadstart_string(), 0, nullptr).ToLocal(&value) ||
65
      !value->Int32Value(env()->context()).To(&value_int)) {
66
    if (try_catch.HasCaught() && !try_catch.HasTerminated())
67
      errors::TriggerUncaughtException(env()->isolate(), try_catch);
68
  }
69
  return value_int;
70
}
71
72
int JSUDPWrap::RecvStop() {
73
  HandleScope scope(env()->isolate());
74
  Context::Scope context_scope(env()->context());
75
  TryCatchScope try_catch(env());
76
  Local<Value> value;
77
  int32_t value_int = UV_EPROTO;
78
  if (!MakeCallback(env()->onreadstop_string(), 0, nullptr).ToLocal(&value) ||
79
      !value->Int32Value(env()->context()).To(&value_int)) {
80
    if (try_catch.HasCaught() && !try_catch.HasTerminated())
81
      errors::TriggerUncaughtException(env()->isolate(), try_catch);
82
  }
83
  return value_int;
84
}
85
86
ssize_t JSUDPWrap::Send(uv_buf_t* bufs,
87
                        size_t nbufs,
88
                        const sockaddr* addr) {
89
  HandleScope scope(env()->isolate());
90
  Context::Scope context_scope(env()->context());
91
  TryCatchScope try_catch(env());
92
  Local<Value> value;
93
  int64_t value_int = UV_EPROTO;
94
  size_t total_len = 0;
95
96
  MaybeStackBuffer<Local<Value>, 16> buffers(nbufs);
97
  for (size_t i = 0; i < nbufs; i++) {
98
    buffers[i] = Buffer::Copy(env(), bufs[i].base, bufs[i].len)
99
        .ToLocalChecked();
100
    total_len += bufs[i].len;
101
  }
102
103
  Local<Value> args[] = {
104
    listener()->CreateSendWrap(total_len)->object(),
105
    Array::New(env()->isolate(), buffers.out(), nbufs),
106
    AddressToJS(env(), addr)
107
  };
108
109
  if (!MakeCallback(env()->onwrite_string(), arraysize(args), args)
110
          .ToLocal(&value) ||
111
      !value->IntegerValue(env()->context()).To(&value_int)) {
112
    if (try_catch.HasCaught() && !try_catch.HasTerminated())
113
      errors::TriggerUncaughtException(env()->isolate(), try_catch);
114
  }
115
  return value_int;
116
}
117
118
SocketAddress JSUDPWrap::GetPeerName() {
119
  SocketAddress ret;
120
  CHECK(SocketAddress::New(AF_INET, "127.0.0.1", 1337, &ret));
121
  return ret;
122
}
123
124
SocketAddress JSUDPWrap::GetSockName() {
125
  SocketAddress ret;
126
  CHECK(SocketAddress::New(AF_INET, "127.0.0.1", 1337, &ret));
127
  return ret;
128
}
129
130
void JSUDPWrap::New(const FunctionCallbackInfo<Value>& args) {
131
  Environment* env = Environment::GetCurrent(args);
132
  CHECK(args.IsConstructCall());
133
  new JSUDPWrap(env, args.Holder());
134
}
135
136
void JSUDPWrap::EmitReceived(const FunctionCallbackInfo<Value>& args) {
137
  JSUDPWrap* wrap;
138
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
139
  Environment* env = wrap->env();
140
141
  ArrayBufferViewContents<char> buffer(args[0]);
142
  const char* data = buffer.data();
143
  int len = buffer.length();
144
145
  CHECK(args[1]->IsInt32());   // family
146
  CHECK(args[2]->IsString());  // address
147
  CHECK(args[3]->IsInt32());   // port
148
  CHECK(args[4]->IsInt32());   // flags
149
  int family = args[1].As<Int32>()->Value() == 4 ? AF_INET : AF_INET6;
150
  Utf8Value address(env->isolate(), args[2]);
151
  int port = args[3].As<Int32>()->Value();
152
  int flags = args[3].As<Int32>()->Value();
153
154
  sockaddr_storage addr;
155
  CHECK_EQ(sockaddr_for_family(family, *address, port, &addr), 0);
156
157
  // Repeatedly ask the stream's owner for memory, copy the data that we
158
  // just read from JS into those buffers and emit them as reads.
159
  while (len != 0) {
160
    uv_buf_t buf = wrap->listener()->OnAlloc(len);
161
    ssize_t avail = std::min<size_t>(buf.len, len);
162
    memcpy(buf.base, data, avail);
163
    data += avail;
164
    len -= static_cast<int>(avail);
165
    wrap->listener()->OnRecv(
166
        avail, buf, reinterpret_cast<sockaddr*>(&addr), flags);
167
  }
168
}
169
170
void JSUDPWrap::OnSendDone(const FunctionCallbackInfo<Value>& args) {
171
  JSUDPWrap* wrap;
172
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
173
174
  CHECK(args[0]->IsObject());
175
  CHECK(args[1]->IsInt32());
176
  ReqWrap<uv_udp_send_t>* req_wrap;
177
  ASSIGN_OR_RETURN_UNWRAP(&req_wrap, args[0].As<Object>());
178
  int status = args[1].As<Int32>()->Value();
179
180
  wrap->listener()->OnSendDone(req_wrap, status);
181
}
182
183
void JSUDPWrap::OnAfterBind(const FunctionCallbackInfo<Value>& args) {
184
  JSUDPWrap* wrap;
185
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
186
187
  wrap->listener()->OnAfterBind();
188
}
189
190
void JSUDPWrap::Initialize(Local<Object> target,
191
                           Local<Value> unused,
192
                           Local<Context> context,
193
                           void* priv) {
194
  Environment* env = Environment::GetCurrent(context);
195
196
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
197
  t->InstanceTemplate()
198
    ->SetInternalFieldCount(UDPWrapBase::kUDPWrapBaseField + 1);
199
  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
200
201
  UDPWrapBase::AddMethods(env, t);
202
  env->SetProtoMethod(t, "emitReceived", EmitReceived);
203
  env->SetProtoMethod(t, "onSendDone", OnSendDone);
204
  env->SetProtoMethod(t, "onAfterBind", OnAfterBind);
205
206
  env->SetConstructorFunction(target, "JSUDPWrap", t);
207
}
208
209
210
}  // namespace node
211
212
4917
NODE_MODULE_CONTEXT_AWARE_INTERNAL(js_udp_wrap, node::JSUDPWrap::Initialize)