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