11cb0ef41Sopenharmony_ci#include "udp_wrap.h"
21cb0ef41Sopenharmony_ci#include "async_wrap-inl.h"
31cb0ef41Sopenharmony_ci#include "node_errors.h"
41cb0ef41Sopenharmony_ci#include "node_sockaddr-inl.h"
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#include <algorithm>
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// TODO(RaisinTen): Replace all uses with empty `v8::Maybe`s.
91cb0ef41Sopenharmony_ci#define JS_EXCEPTION_PENDING UV_EPROTO
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cinamespace node {
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciusing errors::TryCatchScope;
141cb0ef41Sopenharmony_ciusing v8::Array;
151cb0ef41Sopenharmony_ciusing v8::Context;
161cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
171cb0ef41Sopenharmony_ciusing v8::FunctionTemplate;
181cb0ef41Sopenharmony_ciusing v8::HandleScope;
191cb0ef41Sopenharmony_ciusing v8::Int32;
201cb0ef41Sopenharmony_ciusing v8::Isolate;
211cb0ef41Sopenharmony_ciusing v8::Local;
221cb0ef41Sopenharmony_ciusing v8::Object;
231cb0ef41Sopenharmony_ciusing v8::Value;
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// JSUDPWrap is a testing utility used by test/common/udppair.js
261cb0ef41Sopenharmony_ci// to simulate UDP traffic deterministically in Node.js tests.
271cb0ef41Sopenharmony_ciclass JSUDPWrap final : public UDPWrapBase, public AsyncWrap {
281cb0ef41Sopenharmony_ci public:
291cb0ef41Sopenharmony_ci  JSUDPWrap(Environment* env, Local<Object> obj);
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  int RecvStart() override;
321cb0ef41Sopenharmony_ci  int RecvStop() override;
331cb0ef41Sopenharmony_ci  ssize_t Send(uv_buf_t* bufs,
341cb0ef41Sopenharmony_ci               size_t nbufs,
351cb0ef41Sopenharmony_ci               const sockaddr* addr) override;
361cb0ef41Sopenharmony_ci  SocketAddress GetPeerName() override;
371cb0ef41Sopenharmony_ci  SocketAddress GetSockName() override;
381cb0ef41Sopenharmony_ci  AsyncWrap* GetAsyncWrap() override { return this; }
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  static void New(const FunctionCallbackInfo<Value>& args);
411cb0ef41Sopenharmony_ci  static void EmitReceived(const FunctionCallbackInfo<Value>& args);
421cb0ef41Sopenharmony_ci  static void OnSendDone(const FunctionCallbackInfo<Value>& args);
431cb0ef41Sopenharmony_ci  static void OnAfterBind(const FunctionCallbackInfo<Value>& args);
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  static void Initialize(Local<Object> target,
461cb0ef41Sopenharmony_ci                         Local<Value> unused,
471cb0ef41Sopenharmony_ci                         Local<Context> context,
481cb0ef41Sopenharmony_ci                         void* priv);
491cb0ef41Sopenharmony_ci  SET_NO_MEMORY_INFO()
501cb0ef41Sopenharmony_ci  SET_MEMORY_INFO_NAME(JSUDPWrap)
511cb0ef41Sopenharmony_ci  SET_SELF_SIZE(JSUDPWrap)
521cb0ef41Sopenharmony_ci};
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ciJSUDPWrap::JSUDPWrap(Environment* env, Local<Object> obj)
551cb0ef41Sopenharmony_ci  : AsyncWrap(env, obj, PROVIDER_JSUDPWRAP) {
561cb0ef41Sopenharmony_ci  MakeWeak();
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  obj->SetAlignedPointerInInternalField(
591cb0ef41Sopenharmony_ci      kUDPWrapBaseField, static_cast<UDPWrapBase*>(this));
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciint JSUDPWrap::RecvStart() {
631cb0ef41Sopenharmony_ci  HandleScope scope(env()->isolate());
641cb0ef41Sopenharmony_ci  Context::Scope context_scope(env()->context());
651cb0ef41Sopenharmony_ci  TryCatchScope try_catch(env());
661cb0ef41Sopenharmony_ci  Local<Value> value;
671cb0ef41Sopenharmony_ci  int32_t value_int = JS_EXCEPTION_PENDING;
681cb0ef41Sopenharmony_ci  if (!MakeCallback(env()->onreadstart_string(), 0, nullptr).ToLocal(&value) ||
691cb0ef41Sopenharmony_ci      !value->Int32Value(env()->context()).To(&value_int)) {
701cb0ef41Sopenharmony_ci    if (try_catch.HasCaught() && !try_catch.HasTerminated())
711cb0ef41Sopenharmony_ci      errors::TriggerUncaughtException(env()->isolate(), try_catch);
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci  return value_int;
741cb0ef41Sopenharmony_ci}
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ciint JSUDPWrap::RecvStop() {
771cb0ef41Sopenharmony_ci  HandleScope scope(env()->isolate());
781cb0ef41Sopenharmony_ci  Context::Scope context_scope(env()->context());
791cb0ef41Sopenharmony_ci  TryCatchScope try_catch(env());
801cb0ef41Sopenharmony_ci  Local<Value> value;
811cb0ef41Sopenharmony_ci  int32_t value_int = JS_EXCEPTION_PENDING;
821cb0ef41Sopenharmony_ci  if (!MakeCallback(env()->onreadstop_string(), 0, nullptr).ToLocal(&value) ||
831cb0ef41Sopenharmony_ci      !value->Int32Value(env()->context()).To(&value_int)) {
841cb0ef41Sopenharmony_ci    if (try_catch.HasCaught() && !try_catch.HasTerminated())
851cb0ef41Sopenharmony_ci      errors::TriggerUncaughtException(env()->isolate(), try_catch);
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci  return value_int;
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_cissize_t JSUDPWrap::Send(uv_buf_t* bufs,
911cb0ef41Sopenharmony_ci                        size_t nbufs,
921cb0ef41Sopenharmony_ci                        const sockaddr* addr) {
931cb0ef41Sopenharmony_ci  HandleScope scope(env()->isolate());
941cb0ef41Sopenharmony_ci  Context::Scope context_scope(env()->context());
951cb0ef41Sopenharmony_ci  TryCatchScope try_catch(env());
961cb0ef41Sopenharmony_ci  Local<Value> value;
971cb0ef41Sopenharmony_ci  int64_t value_int = JS_EXCEPTION_PENDING;
981cb0ef41Sopenharmony_ci  size_t total_len = 0;
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  MaybeStackBuffer<Local<Value>, 16> buffers(nbufs);
1011cb0ef41Sopenharmony_ci  for (size_t i = 0; i < nbufs; i++) {
1021cb0ef41Sopenharmony_ci    buffers[i] = Buffer::Copy(env(), bufs[i].base, bufs[i].len)
1031cb0ef41Sopenharmony_ci        .ToLocalChecked();
1041cb0ef41Sopenharmony_ci    total_len += bufs[i].len;
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  Local<Object> address;
1081cb0ef41Sopenharmony_ci  if (!AddressToJS(env(), addr).ToLocal(&address)) return value_int;
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  Local<Value> args[] = {
1111cb0ef41Sopenharmony_ci    listener()->CreateSendWrap(total_len)->object(),
1121cb0ef41Sopenharmony_ci    Array::New(env()->isolate(), buffers.out(), nbufs),
1131cb0ef41Sopenharmony_ci    address,
1141cb0ef41Sopenharmony_ci  };
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  if (!MakeCallback(env()->onwrite_string(), arraysize(args), args)
1171cb0ef41Sopenharmony_ci          .ToLocal(&value) ||
1181cb0ef41Sopenharmony_ci      !value->IntegerValue(env()->context()).To(&value_int)) {
1191cb0ef41Sopenharmony_ci    if (try_catch.HasCaught() && !try_catch.HasTerminated())
1201cb0ef41Sopenharmony_ci      errors::TriggerUncaughtException(env()->isolate(), try_catch);
1211cb0ef41Sopenharmony_ci  }
1221cb0ef41Sopenharmony_ci  return value_int;
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ciSocketAddress JSUDPWrap::GetPeerName() {
1261cb0ef41Sopenharmony_ci  SocketAddress ret;
1271cb0ef41Sopenharmony_ci  CHECK(SocketAddress::New(AF_INET, "127.0.0.1", 1337, &ret));
1281cb0ef41Sopenharmony_ci  return ret;
1291cb0ef41Sopenharmony_ci}
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ciSocketAddress JSUDPWrap::GetSockName() {
1321cb0ef41Sopenharmony_ci  SocketAddress ret;
1331cb0ef41Sopenharmony_ci  CHECK(SocketAddress::New(AF_INET, "127.0.0.1", 1337, &ret));
1341cb0ef41Sopenharmony_ci  return ret;
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_civoid JSUDPWrap::New(const FunctionCallbackInfo<Value>& args) {
1381cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1391cb0ef41Sopenharmony_ci  CHECK(args.IsConstructCall());
1401cb0ef41Sopenharmony_ci  new JSUDPWrap(env, args.Holder());
1411cb0ef41Sopenharmony_ci}
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_civoid JSUDPWrap::EmitReceived(const FunctionCallbackInfo<Value>& args) {
1441cb0ef41Sopenharmony_ci  JSUDPWrap* wrap;
1451cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
1461cb0ef41Sopenharmony_ci  Environment* env = wrap->env();
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci  ArrayBufferViewContents<char> buffer(args[0]);
1491cb0ef41Sopenharmony_ci  const char* data = buffer.data();
1501cb0ef41Sopenharmony_ci  int len = buffer.length();
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  CHECK(args[1]->IsInt32());   // family
1531cb0ef41Sopenharmony_ci  CHECK(args[2]->IsString());  // address
1541cb0ef41Sopenharmony_ci  CHECK(args[3]->IsInt32());   // port
1551cb0ef41Sopenharmony_ci  CHECK(args[4]->IsInt32());   // flags
1561cb0ef41Sopenharmony_ci  int family = args[1].As<Int32>()->Value() == 4 ? AF_INET : AF_INET6;
1571cb0ef41Sopenharmony_ci  Utf8Value address(env->isolate(), args[2]);
1581cb0ef41Sopenharmony_ci  int port = args[3].As<Int32>()->Value();
1591cb0ef41Sopenharmony_ci  int flags = args[3].As<Int32>()->Value();
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  sockaddr_storage addr;
1621cb0ef41Sopenharmony_ci  CHECK_EQ(sockaddr_for_family(family, *address, port, &addr), 0);
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  // Repeatedly ask the stream's owner for memory, copy the data that we
1651cb0ef41Sopenharmony_ci  // just read from JS into those buffers and emit them as reads.
1661cb0ef41Sopenharmony_ci  while (len != 0) {
1671cb0ef41Sopenharmony_ci    uv_buf_t buf = wrap->listener()->OnAlloc(len);
1681cb0ef41Sopenharmony_ci    ssize_t avail = std::min<size_t>(buf.len, len);
1691cb0ef41Sopenharmony_ci    memcpy(buf.base, data, avail);
1701cb0ef41Sopenharmony_ci    data += avail;
1711cb0ef41Sopenharmony_ci    len -= static_cast<int>(avail);
1721cb0ef41Sopenharmony_ci    wrap->listener()->OnRecv(
1731cb0ef41Sopenharmony_ci        avail, buf, reinterpret_cast<sockaddr*>(&addr), flags);
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci}
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_civoid JSUDPWrap::OnSendDone(const FunctionCallbackInfo<Value>& args) {
1781cb0ef41Sopenharmony_ci  JSUDPWrap* wrap;
1791cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  CHECK(args[0]->IsObject());
1821cb0ef41Sopenharmony_ci  CHECK(args[1]->IsInt32());
1831cb0ef41Sopenharmony_ci  ReqWrap<uv_udp_send_t>* req_wrap;
1841cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&req_wrap, args[0].As<Object>());
1851cb0ef41Sopenharmony_ci  int status = args[1].As<Int32>()->Value();
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  wrap->listener()->OnSendDone(req_wrap, status);
1881cb0ef41Sopenharmony_ci}
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_civoid JSUDPWrap::OnAfterBind(const FunctionCallbackInfo<Value>& args) {
1911cb0ef41Sopenharmony_ci  JSUDPWrap* wrap;
1921cb0ef41Sopenharmony_ci  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  wrap->listener()->OnAfterBind();
1951cb0ef41Sopenharmony_ci}
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_civoid JSUDPWrap::Initialize(Local<Object> target,
1981cb0ef41Sopenharmony_ci                           Local<Value> unused,
1991cb0ef41Sopenharmony_ci                           Local<Context> context,
2001cb0ef41Sopenharmony_ci                           void* priv) {
2011cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(context);
2021cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
2051cb0ef41Sopenharmony_ci  t->InstanceTemplate()
2061cb0ef41Sopenharmony_ci    ->SetInternalFieldCount(UDPWrapBase::kUDPWrapBaseField + 1);
2071cb0ef41Sopenharmony_ci  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  UDPWrapBase::AddMethods(env, t);
2101cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "emitReceived", EmitReceived);
2111cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "onSendDone", OnSendDone);
2121cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "onAfterBind", OnAfterBind);
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  SetConstructorFunction(context, target, "JSUDPWrap", t);
2151cb0ef41Sopenharmony_ci}
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci}  // namespace node
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(js_udp_wrap, node::JSUDPWrap::Initialize)
221