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