1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include "node_buffer.h"
25 #include "handle_wrap.h"
34 using v8::FunctionCallbackInfo;
35 using v8::FunctionTemplate;
37 using v8::HandleScope;
42 using v8::PropertyAttribute;
43 using v8::PropertyCallbackInfo;
50 class SendWrap : public ReqWrap<uv_udp_send_t> {
52 SendWrap(Local<Object> req_wrap_obj, bool have_callback);
53 inline bool have_callback() const;
55 const bool have_callback_;
59 static Persistent<Function> constructor;
60 static Cached<String> buffer_sym;
61 static Cached<String> oncomplete_sym;
62 static Cached<String> onmessage_sym;
65 SendWrap::SendWrap(Local<Object> req_wrap_obj, bool have_callback)
66 : ReqWrap<uv_udp_send_t>(req_wrap_obj)
67 , have_callback_(have_callback) {
71 inline bool SendWrap::have_callback() const {
72 return have_callback_;
76 UDPWrap::UDPWrap(Handle<Object> object)
77 : HandleWrap(object, reinterpret_cast<uv_handle_t*>(&handle_)) {
78 int r = uv_udp_init(uv_default_loop(), &handle_);
79 assert(r == 0); // can't fail anyway
87 void UDPWrap::Initialize(Handle<Object> target) {
88 HandleScope scope(node_isolate);
90 buffer_sym = FIXED_ONE_BYTE_STRING(node_isolate, "buffer");
91 oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
92 onmessage_sym = FIXED_ONE_BYTE_STRING(node_isolate, "onmessage");
94 Local<FunctionTemplate> t = FunctionTemplate::New(New);
95 t->InstanceTemplate()->SetInternalFieldCount(1);
96 t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "UDP"));
98 enum PropertyAttribute attributes =
99 static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
100 t->InstanceTemplate()->SetAccessor(FIXED_ONE_BYTE_STRING(node_isolate, "fd"),
107 NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
108 NODE_SET_PROTOTYPE_METHOD(t, "send", Send);
109 NODE_SET_PROTOTYPE_METHOD(t, "bind6", Bind6);
110 NODE_SET_PROTOTYPE_METHOD(t, "send6", Send6);
111 NODE_SET_PROTOTYPE_METHOD(t, "close", Close);
112 NODE_SET_PROTOTYPE_METHOD(t, "recvStart", RecvStart);
113 NODE_SET_PROTOTYPE_METHOD(t, "recvStop", RecvStop);
114 NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName);
115 NODE_SET_PROTOTYPE_METHOD(t, "addMembership", AddMembership);
116 NODE_SET_PROTOTYPE_METHOD(t, "dropMembership", DropMembership);
117 NODE_SET_PROTOTYPE_METHOD(t, "setMulticastTTL", SetMulticastTTL);
118 NODE_SET_PROTOTYPE_METHOD(t, "setMulticastLoopback", SetMulticastLoopback);
119 NODE_SET_PROTOTYPE_METHOD(t, "setBroadcast", SetBroadcast);
120 NODE_SET_PROTOTYPE_METHOD(t, "setTTL", SetTTL);
122 NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);
123 NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
125 constructor.Reset(node_isolate, t->GetFunction());
126 target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "UDP"), t->GetFunction());
130 void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
131 HandleScope scope(node_isolate);
132 assert(args.IsConstructCall());
133 new UDPWrap(args.This());
137 void UDPWrap::GetFD(Local<String>, const PropertyCallbackInfo<Value>& args) {
139 HandleScope scope(node_isolate);
141 int fd = (wrap == NULL) ? -1 : wrap->handle_.io_watcher.fd;
142 args.GetReturnValue().Set(fd);
147 void UDPWrap::DoBind(const FunctionCallbackInfo<Value>& args, int family) {
148 HandleScope scope(node_isolate);
153 // bind(ip, port, flags)
154 assert(args.Length() == 3);
156 String::Utf8Value address(args[0]);
157 const int port = args[1]->Uint32Value();
158 const int flags = args[2]->Uint32Value();
162 err = uv_udp_bind(&wrap->handle_, uv_ip4_addr(*address, port), flags);
165 err = uv_udp_bind6(&wrap->handle_, uv_ip6_addr(*address, port), flags);
168 assert(0 && "unexpected address family");
172 args.GetReturnValue().Set(err);
176 void UDPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
177 DoBind(args, AF_INET);
181 void UDPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
182 DoBind(args, AF_INET6);
186 #define X(name, fn) \
187 void UDPWrap::name(const FunctionCallbackInfo<Value>& args) { \
188 HandleScope scope(node_isolate); \
190 assert(args.Length() == 1); \
191 int flag = args[0]->Int32Value(); \
192 int err = fn(&wrap->handle_, flag); \
193 args.GetReturnValue().Set(err); \
196 X(SetTTL, uv_udp_set_ttl)
197 X(SetBroadcast, uv_udp_set_broadcast)
198 X(SetMulticastTTL, uv_udp_set_multicast_ttl)
199 X(SetMulticastLoopback, uv_udp_set_multicast_loop)
204 void UDPWrap::SetMembership(const FunctionCallbackInfo<Value>& args,
205 uv_membership membership) {
206 HandleScope scope(node_isolate);
209 assert(args.Length() == 2);
211 String::Utf8Value address(args[0]);
212 String::Utf8Value iface(args[1]);
214 const char* iface_cstr = *iface;
215 if (args[1]->IsUndefined() || args[1]->IsNull()) {
219 int err = uv_udp_set_membership(&wrap->handle_,
223 args.GetReturnValue().Set(err);
227 void UDPWrap::AddMembership(const FunctionCallbackInfo<Value>& args) {
228 SetMembership(args, UV_JOIN_GROUP);
232 void UDPWrap::DropMembership(const FunctionCallbackInfo<Value>& args) {
233 SetMembership(args, UV_LEAVE_GROUP);
237 void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
238 HandleScope scope(node_isolate);
243 // send(req, buffer, offset, length, port, address)
244 assert(args[0]->IsObject());
245 assert(Buffer::HasInstance(args[1]));
246 assert(args[2]->IsUint32());
247 assert(args[3]->IsUint32());
248 assert(args[4]->IsUint32());
249 assert(args[5]->IsString());
250 assert(args[6]->IsBoolean());
252 Local<Object> req_wrap_obj = args[0].As<Object>();
253 Local<Object> buffer_obj = args[1].As<Object>();
254 size_t offset = args[2]->Uint32Value();
255 size_t length = args[3]->Uint32Value();
256 const unsigned short port = args[4]->Uint32Value();
257 String::Utf8Value address(args[5]);
258 const bool have_callback = args[6]->IsTrue();
260 assert(offset < Buffer::Length(buffer_obj));
261 assert(length <= Buffer::Length(buffer_obj) - offset);
263 SendWrap* req_wrap = new SendWrap(req_wrap_obj, have_callback);
264 req_wrap->object()->SetHiddenValue(buffer_sym, buffer_obj);
266 uv_buf_t buf = uv_buf_init(Buffer::Data(buffer_obj) + offset,
271 err = uv_udp_send(&req_wrap->req_,
275 uv_ip4_addr(*address, port),
279 err = uv_udp_send6(&req_wrap->req_,
283 uv_ip6_addr(*address, port),
287 assert(0 && "unexpected address family");
291 req_wrap->Dispatched();
292 if (err) delete req_wrap;
294 args.GetReturnValue().Set(err);
298 void UDPWrap::Send(const FunctionCallbackInfo<Value>& args) {
299 DoSend(args, AF_INET);
303 void UDPWrap::Send6(const FunctionCallbackInfo<Value>& args) {
304 DoSend(args, AF_INET6);
308 void UDPWrap::RecvStart(const FunctionCallbackInfo<Value>& args) {
309 HandleScope scope(node_isolate);
312 int err = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
313 // UV_EALREADY means that the socket is already bound but that's okay
314 if (err == UV_EALREADY) err = 0;
315 args.GetReturnValue().Set(err);
319 void UDPWrap::RecvStop(const FunctionCallbackInfo<Value>& args) {
320 HandleScope scope(node_isolate);
323 int r = uv_udp_recv_stop(&wrap->handle_);
324 args.GetReturnValue().Set(r);
328 void UDPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
329 HandleScope scope(node_isolate);
330 struct sockaddr_storage address;
333 assert(args[0]->IsObject());
334 Local<Object> obj = args[0].As<Object>();
336 int addrlen = sizeof(address);
337 int err = uv_udp_getsockname(&wrap->handle_,
338 reinterpret_cast<sockaddr*>(&address),
342 const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
343 AddressToJS(addr, obj);
346 args.GetReturnValue().Set(err);
350 // TODO(bnoordhuis) share with StreamWrap::AfterWrite() in stream_wrap.cc
351 void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
352 SendWrap* req_wrap = static_cast<SendWrap*>(req->data);
353 if (req_wrap->have_callback()) {
354 HandleScope scope(node_isolate);
355 Local<Object> req_wrap_obj = req_wrap->object();
356 Local<Value> arg = Integer::New(status, node_isolate);
357 MakeCallback(req_wrap_obj, oncomplete_sym, 1, &arg);
363 uv_buf_t UDPWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) {
364 char* data = static_cast<char*>(malloc(suggested_size));
365 if (data == NULL && suggested_size > 0) {
366 FatalError("node::UDPWrap::OnAlloc(uv_handle_t*, size_t)",
369 return uv_buf_init(data, suggested_size);
373 void UDPWrap::OnRecv(uv_udp_t* handle,
376 struct sockaddr* addr,
379 if (buf.base != NULL)
384 UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
386 HandleScope scope(node_isolate);
387 Local<Object> wrap_obj = wrap->object();
388 Local<Value> argv[] = {
389 Integer::New(nread, node_isolate),
396 if (buf.base != NULL)
398 MakeCallback(wrap_obj, onmessage_sym, ARRAY_SIZE(argv), argv);
402 buf.base = static_cast<char*>(realloc(buf.base, nread));
404 argv[2] = Buffer::Use(buf.base, nread);
405 argv[3] = AddressToJS(addr);
406 MakeCallback(wrap_obj, onmessage_sym, ARRAY_SIZE(argv), argv);
410 UDPWrap* UDPWrap::Unwrap(Local<Object> obj) {
411 assert(!obj.IsEmpty());
412 assert(obj->InternalFieldCount() > 0);
413 return static_cast<UDPWrap*>(obj->GetAlignedPointerFromInternalField(0));
417 Local<Object> UDPWrap::Instantiate() {
418 // If this assert fires then Initialize hasn't been called yet.
419 assert(constructor.IsEmpty() == false);
420 return NewInstance(constructor);
424 uv_udp_t* UDPWrap::UVHandle() {
431 NODE_MODULE(node_udp_wrap, node::UDPWrap::Initialize)