4 #include "node_buffer.h"
5 #include "handle_wrap.h"
7 #include "req-wrap-inl.h"
17 using v8::EscapableHandleScope;
20 using v8::FunctionCallbackInfo;
21 using v8::FunctionTemplate;
22 using v8::HandleScope;
26 using v8::PropertyAttribute;
27 using v8::PropertyCallbackInfo;
34 class SendWrap : public ReqWrap<uv_udp_send_t> {
36 SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
37 inline bool have_callback() const;
38 size_t self_size() const override { return sizeof(*this); }
40 const bool have_callback_;
44 SendWrap::SendWrap(Environment* env,
45 Local<Object> req_wrap_obj,
47 : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP),
48 have_callback_(have_callback) {
49 Wrap(req_wrap_obj, this);
53 inline bool SendWrap::have_callback() const {
54 return have_callback_;
58 static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
59 CHECK(args.IsConstructCall());
63 UDPWrap::UDPWrap(Environment* env, Local<Object> object, AsyncWrap* parent)
66 reinterpret_cast<uv_handle_t*>(&handle_),
67 AsyncWrap::PROVIDER_UDPWRAP) {
68 int r = uv_udp_init(env->event_loop(), &handle_);
69 CHECK_EQ(r, 0); // can't fail anyway
73 void UDPWrap::Initialize(Local<Object> target,
75 Local<Context> context) {
76 Environment* env = Environment::GetCurrent(context);
78 Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
79 t->InstanceTemplate()->SetInternalFieldCount(1);
80 t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"));
82 enum PropertyAttribute attributes =
83 static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
84 t->InstanceTemplate()->SetAccessor(env->fd_string(),
91 env->SetProtoMethod(t, "bind", Bind);
92 env->SetProtoMethod(t, "send", Send);
93 env->SetProtoMethod(t, "bind6", Bind6);
94 env->SetProtoMethod(t, "send6", Send6);
95 env->SetProtoMethod(t, "close", Close);
96 env->SetProtoMethod(t, "recvStart", RecvStart);
97 env->SetProtoMethod(t, "recvStop", RecvStop);
98 env->SetProtoMethod(t, "getsockname",
99 GetSockOrPeerName<UDPWrap, uv_udp_getsockname>);
100 env->SetProtoMethod(t, "addMembership", AddMembership);
101 env->SetProtoMethod(t, "dropMembership", DropMembership);
102 env->SetProtoMethod(t, "setMulticastTTL", SetMulticastTTL);
103 env->SetProtoMethod(t, "setMulticastLoopback", SetMulticastLoopback);
104 env->SetProtoMethod(t, "setBroadcast", SetBroadcast);
105 env->SetProtoMethod(t, "setTTL", SetTTL);
107 env->SetProtoMethod(t, "ref", HandleWrap::Ref);
108 env->SetProtoMethod(t, "unref", HandleWrap::Unref);
110 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction());
111 env->set_udp_constructor_function(t->GetFunction());
113 // Create FunctionTemplate for SendWrap
114 Local<FunctionTemplate> swt =
115 FunctionTemplate::New(env->isolate(), NewSendWrap);
116 swt->InstanceTemplate()->SetInternalFieldCount(1);
117 swt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"));
118 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"),
123 void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
124 CHECK(args.IsConstructCall());
125 Environment* env = Environment::GetCurrent(args);
126 if (args.Length() == 0) {
127 new UDPWrap(env, args.This(), nullptr);
128 } else if (args[0]->IsExternal()) {
131 static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
138 void UDPWrap::GetFD(Local<String>, const PropertyCallbackInfo<Value>& args) {
140 HandleScope scope(args.GetIsolate());
141 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
142 int fd = (wrap == nullptr) ? -1 : wrap->handle_.io_watcher.fd;
143 args.GetReturnValue().Set(fd);
148 void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
149 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
151 // bind(ip, port, flags)
152 CHECK_EQ(args.Length(), 3);
154 node::Utf8Value address(args.GetIsolate(), args[0]);
155 const int port = args[1]->Uint32Value();
156 const int flags = args[2]->Uint32Value();
157 char addr[sizeof(sockaddr_in6)];
162 err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
165 err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
168 CHECK(0 && "unexpected address family");
173 err = uv_udp_bind(&wrap->handle_,
174 reinterpret_cast<const sockaddr*>(&addr),
178 args.GetReturnValue().Set(err);
182 void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
183 DoBind(args, AF_INET);
187 void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
188 DoBind(args, AF_INET6);
192 #define X(name, fn) \
193 void UDPWrap::name(const FunctionCallbackInfo<Value>& args) { \
194 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder()); \
195 CHECK_EQ(args.Length(), 1); \
196 int flag = args[0]->Int32Value(); \
197 int err = fn(&wrap->handle_, flag); \
198 args.GetReturnValue().Set(err); \
201 X(SetTTL, uv_udp_set_ttl)
202 X(SetBroadcast, uv_udp_set_broadcast)
203 X(SetMulticastTTL, uv_udp_set_multicast_ttl)
204 X(SetMulticastLoopback, uv_udp_set_multicast_loop)
209 void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
210 uv_membership membership) {
211 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
213 CHECK_EQ(args.Length(), 2);
215 node::Utf8Value address(args.GetIsolate(), args[0]);
216 node::Utf8Value iface(args.GetIsolate(), args[1]);
218 const char* iface_cstr = *iface;
219 if (args[1]->IsUndefined() || args[1]->IsNull()) {
220 iface_cstr = nullptr;
223 int err = uv_udp_set_membership(&wrap->handle_,
227 args.GetReturnValue().Set(err);
231 void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
232 SetMembership(args, UV_JOIN_GROUP);
236 void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
237 SetMembership(args, UV_LEAVE_GROUP);
241 void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
242 Environment* env = Environment::GetCurrent(args);
244 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
246 // send(req, buffer, offset, length, port, address)
247 CHECK(args[0]->IsObject());
248 CHECK(Buffer::HasInstance(args[1]));
249 CHECK(args[2]->IsUint32());
250 CHECK(args[3]->IsUint32());
251 CHECK(args[4]->IsUint32());
252 CHECK(args[5]->IsString());
253 CHECK(args[6]->IsBoolean());
255 Local<Object> req_wrap_obj = args[0].As<Object>();
256 Local<Object> buffer_obj = args[1].As<Object>();
257 size_t offset = args[2]->Uint32Value();
258 size_t length = args[3]->Uint32Value();
259 const unsigned short port = args[4]->Uint32Value();
260 node::Utf8Value address(env->isolate(), args[5]);
261 const bool have_callback = args[6]->IsTrue();
263 CHECK_LE(length, Buffer::Length(buffer_obj) - offset);
265 SendWrap* req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
267 uv_buf_t buf = uv_buf_init(Buffer::Data(buffer_obj) + offset,
269 char addr[sizeof(sockaddr_in6)];
274 err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
277 err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
280 CHECK(0 && "unexpected address family");
285 err = uv_udp_send(&req_wrap->req_,
289 reinterpret_cast<const sockaddr*>(&addr),
293 req_wrap->Dispatched();
297 args.GetReturnValue().Set(err);
301 void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
302 DoSend(args, AF_INET);
306 void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
307 DoSend(args, AF_INET6);
311 void UDPWrap::RecvStart(const FunctionCallbackInfo<Value>& args) {
312 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
313 int err = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
314 // UV_EALREADY means that the socket is already bound but that's okay
315 if (err == UV_EALREADY)
317 args.GetReturnValue().Set(err);
321 void UDPWrap::RecvStop(const FunctionCallbackInfo<Value>& args) {
322 UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
323 int r = uv_udp_recv_stop(&wrap->handle_);
324 args.GetReturnValue().Set(r);
328 // TODO(bnoordhuis) share with StreamWrap::AfterWrite() in stream_wrap.cc
329 void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
330 SendWrap* req_wrap = static_cast<SendWrap*>(req->data);
331 if (req_wrap->have_callback()) {
332 Environment* env = req_wrap->env();
333 HandleScope handle_scope(env->isolate());
334 Context::Scope context_scope(env->context());
335 Local<Value> arg = Integer::New(env->isolate(), status);
336 req_wrap->MakeCallback(env->oncomplete_string(), 1, &arg);
342 void UDPWrap::OnAlloc(uv_handle_t* handle,
343 size_t suggested_size,
345 buf->base = static_cast<char*>(malloc(suggested_size));
346 buf->len = suggested_size;
348 if (buf->base == nullptr && suggested_size > 0) {
349 FatalError("node::UDPWrap::OnAlloc(uv_handle_t*, size_t, uv_buf_t*)",
355 void UDPWrap::OnRecv(uv_udp_t* handle,
358 const struct sockaddr* addr,
359 unsigned int flags) {
360 if (nread == 0 && addr == nullptr) {
361 if (buf->base != nullptr)
366 UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
367 Environment* env = wrap->env();
369 HandleScope handle_scope(env->isolate());
370 Context::Scope context_scope(env->context());
372 Local<Object> wrap_obj = wrap->object();
373 Local<Value> argv[] = {
374 Integer::New(env->isolate(), nread),
376 Undefined(env->isolate()),
377 Undefined(env->isolate())
381 if (buf->base != nullptr)
383 wrap->MakeCallback(env->onmessage_string(), ARRAY_SIZE(argv), argv);
387 char* base = static_cast<char*>(realloc(buf->base, nread));
388 argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
389 argv[3] = AddressToJS(env, addr);
390 wrap->MakeCallback(env->onmessage_string(), ARRAY_SIZE(argv), argv);
394 Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
395 // If this assert fires then Initialize hasn't been called yet.
396 CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
397 EscapableHandleScope scope(env->isolate());
398 Local<Value> ptr = External::New(env->isolate(), parent);
399 return scope.Escape(env->udp_constructor_function()->NewInstance(1, &ptr));
403 uv_udp_t* UDPWrap::UVHandle() {
410 NODE_MODULE_CONTEXT_AWARE_BUILTIN(udp_wrap, node::UDPWrap::Initialize)