revise installing a license file
[platform/upstream/nodejs.git] / src / udp_wrap.cc
1 #include "udp_wrap.h"
2 #include "env.h"
3 #include "env-inl.h"
4 #include "node_buffer.h"
5 #include "handle_wrap.h"
6 #include "req-wrap.h"
7 #include "req-wrap-inl.h"
8 #include "util.h"
9 #include "util-inl.h"
10
11 #include <stdlib.h>
12
13
14 namespace node {
15
16 using v8::Context;
17 using v8::EscapableHandleScope;
18 using v8::External;
19 using v8::Function;
20 using v8::FunctionCallbackInfo;
21 using v8::FunctionTemplate;
22 using v8::HandleScope;
23 using v8::Integer;
24 using v8::Local;
25 using v8::Object;
26 using v8::PropertyAttribute;
27 using v8::PropertyCallbackInfo;
28 using v8::String;
29 using v8::Uint32;
30 using v8::Undefined;
31 using v8::Value;
32
33
34 class SendWrap : public ReqWrap<uv_udp_send_t> {
35  public:
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); }
39  private:
40   const bool have_callback_;
41 };
42
43
44 SendWrap::SendWrap(Environment* env,
45                    Local<Object> req_wrap_obj,
46                    bool have_callback)
47     : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP),
48       have_callback_(have_callback) {
49   Wrap(req_wrap_obj, this);
50 }
51
52
53 inline bool SendWrap::have_callback() const {
54   return have_callback_;
55 }
56
57
58 static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
59   CHECK(args.IsConstructCall());
60 }
61
62
63 UDPWrap::UDPWrap(Environment* env, Local<Object> object, AsyncWrap* parent)
64     : HandleWrap(env,
65                  object,
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
70 }
71
72
73 void UDPWrap::Initialize(Local<Object> target,
74                          Local<Value> unused,
75                          Local<Context> context) {
76   Environment* env = Environment::GetCurrent(context);
77
78   Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
79   t->InstanceTemplate()->SetInternalFieldCount(1);
80   t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"));
81
82   enum PropertyAttribute attributes =
83       static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
84   t->InstanceTemplate()->SetAccessor(env->fd_string(),
85                                      UDPWrap::GetFD,
86                                      nullptr,
87                                      env->as_external(),
88                                      v8::DEFAULT,
89                                      attributes);
90
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);
106
107   env->SetProtoMethod(t, "ref", HandleWrap::Ref);
108   env->SetProtoMethod(t, "unref", HandleWrap::Unref);
109
110   target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "UDP"), t->GetFunction());
111   env->set_udp_constructor_function(t->GetFunction());
112
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"),
119               swt->GetFunction());
120 }
121
122
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()) {
129     new UDPWrap(env,
130                 args.This(),
131                 static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
132   } else {
133     UNREACHABLE();
134   }
135 }
136
137
138 void UDPWrap::GetFD(Local<String>, const PropertyCallbackInfo<Value>& args) {
139 #if !defined(_WIN32)
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);
144 #endif
145 }
146
147
148 void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
149   UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
150
151   // bind(ip, port, flags)
152   CHECK_EQ(args.Length(), 3);
153
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)];
158   int err;
159
160   switch (family) {
161   case AF_INET:
162     err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
163     break;
164   case AF_INET6:
165     err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
166     break;
167   default:
168     CHECK(0 && "unexpected address family");
169     ABORT();
170   }
171
172   if (err == 0) {
173     err = uv_udp_bind(&wrap->handle_,
174                       reinterpret_cast<const sockaddr*>(&addr),
175                       flags);
176   }
177
178   args.GetReturnValue().Set(err);
179 }
180
181
182 void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
183   DoBind(args, AF_INET);
184 }
185
186
187 void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
188   DoBind(args, AF_INET6);
189 }
190
191
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);                                           \
199   }
200
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)
205
206 #undef X
207
208
209 void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
210                             uv_membership membership) {
211   UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
212
213   CHECK_EQ(args.Length(), 2);
214
215   node::Utf8Value address(args.GetIsolate(), args[0]);
216   node::Utf8Value iface(args.GetIsolate(), args[1]);
217
218   const char* iface_cstr = *iface;
219   if (args[1]->IsUndefined() || args[1]->IsNull()) {
220       iface_cstr = nullptr;
221   }
222
223   int err = uv_udp_set_membership(&wrap->handle_,
224                                   *address,
225                                   iface_cstr,
226                                   membership);
227   args.GetReturnValue().Set(err);
228 }
229
230
231 void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
232   SetMembership(args, UV_JOIN_GROUP);
233 }
234
235
236 void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
237   SetMembership(args, UV_LEAVE_GROUP);
238 }
239
240
241 void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
242   Environment* env = Environment::GetCurrent(args);
243
244   UDPWrap* wrap = Unwrap<UDPWrap>(args.Holder());
245
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());
254
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();
262
263   CHECK_LE(length, Buffer::Length(buffer_obj) - offset);
264
265   SendWrap* req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
266
267   uv_buf_t buf = uv_buf_init(Buffer::Data(buffer_obj) + offset,
268                              length);
269   char addr[sizeof(sockaddr_in6)];
270   int err;
271
272   switch (family) {
273   case AF_INET:
274     err = uv_ip4_addr(*address, port, reinterpret_cast<sockaddr_in*>(&addr));
275     break;
276   case AF_INET6:
277     err = uv_ip6_addr(*address, port, reinterpret_cast<sockaddr_in6*>(&addr));
278     break;
279   default:
280     CHECK(0 && "unexpected address family");
281     ABORT();
282   }
283
284   if (err == 0) {
285     err = uv_udp_send(&req_wrap->req_,
286                       &wrap->handle_,
287                       &buf,
288                       1,
289                       reinterpret_cast<const sockaddr*>(&addr),
290                       OnSend);
291   }
292
293   req_wrap->Dispatched();
294   if (err)
295     delete req_wrap;
296
297   args.GetReturnValue().Set(err);
298 }
299
300
301 void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
302   DoSend(args, AF_INET);
303 }
304
305
306 void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
307   DoSend(args, AF_INET6);
308 }
309
310
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)
316     err = 0;
317   args.GetReturnValue().Set(err);
318 }
319
320
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);
325 }
326
327
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);
337   }
338   delete req_wrap;
339 }
340
341
342 void UDPWrap::OnAlloc(uv_handle_t* handle,
343                       size_t suggested_size,
344                       uv_buf_t* buf) {
345   buf->base = static_cast<char*>(malloc(suggested_size));
346   buf->len = suggested_size;
347
348   if (buf->base == nullptr && suggested_size > 0) {
349     FatalError("node::UDPWrap::OnAlloc(uv_handle_t*, size_t, uv_buf_t*)",
350                "Out Of Memory");
351   }
352 }
353
354
355 void UDPWrap::OnRecv(uv_udp_t* handle,
356                      ssize_t nread,
357                      const uv_buf_t* buf,
358                      const struct sockaddr* addr,
359                      unsigned int flags) {
360   if (nread == 0 && addr == nullptr) {
361     if (buf->base != nullptr)
362       free(buf->base);
363     return;
364   }
365
366   UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
367   Environment* env = wrap->env();
368
369   HandleScope handle_scope(env->isolate());
370   Context::Scope context_scope(env->context());
371
372   Local<Object> wrap_obj = wrap->object();
373   Local<Value> argv[] = {
374     Integer::New(env->isolate(), nread),
375     wrap_obj,
376     Undefined(env->isolate()),
377     Undefined(env->isolate())
378   };
379
380   if (nread < 0) {
381     if (buf->base != nullptr)
382       free(buf->base);
383     wrap->MakeCallback(env->onmessage_string(), ARRAY_SIZE(argv), argv);
384     return;
385   }
386
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);
391 }
392
393
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));
400 }
401
402
403 uv_udp_t* UDPWrap::UVHandle() {
404   return &handle_;
405 }
406
407
408 }  // namespace node
409
410 NODE_MODULE_CONTEXT_AWARE_BUILTIN(udp_wrap, node::UDPWrap::Initialize)