• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
GetAsyncWrap()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 
JSUDPWrap(Environment * env,Local<Object> obj)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 
RecvStart()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 
RecvStop()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 
Send(uv_buf_t * bufs,size_t nbufs,const sockaddr * addr)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 
GetPeerName()118 SocketAddress JSUDPWrap::GetPeerName() {
119   SocketAddress ret;
120   CHECK(SocketAddress::New(AF_INET, "127.0.0.1", 1337, &ret));
121   return ret;
122 }
123 
GetSockName()124 SocketAddress JSUDPWrap::GetSockName() {
125   SocketAddress ret;
126   CHECK(SocketAddress::New(AF_INET, "127.0.0.1", 1337, &ret));
127   return ret;
128 }
129 
New(const FunctionCallbackInfo<Value> & args)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 
EmitReceived(const FunctionCallbackInfo<Value> & args)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 -= avail;
165     wrap->listener()->OnRecv(
166         avail, buf, reinterpret_cast<sockaddr*>(&addr), flags);
167   }
168 }
169 
OnSendDone(const FunctionCallbackInfo<Value> & args)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 
OnAfterBind(const FunctionCallbackInfo<Value> & args)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 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)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 NODE_MODULE_CONTEXT_AWARE_INTERNAL(js_udp_wrap, node::JSUDPWrap::Initialize)
213