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