Merge remote-tracking branch 'origin/v0.8'
[platform/upstream/nodejs.git] / src / udp_wrap.cc
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
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:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
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.
21
22 #include "node.h"
23 #include "node_buffer.h"
24 #include "slab_allocator.h"
25 #include "req_wrap.h"
26 #include "handle_wrap.h"
27 #include "udp_wrap.h"
28
29 #include <stdlib.h>
30
31 #define SLAB_SIZE (1024 * 1024)
32
33
34 namespace node {
35
36 using v8::AccessorInfo;
37 using v8::Arguments;
38 using v8::False;
39 using v8::Function;
40 using v8::FunctionTemplate;
41 using v8::Handle;
42 using v8::HandleScope;
43 using v8::Integer;
44 using v8::Local;
45 using v8::Null;
46 using v8::Object;
47 using v8::Persistent;
48 using v8::PropertyAttribute;
49 using v8::String;
50 using v8::True;
51 using v8::Value;
52
53 typedef ReqWrap<uv_udp_send_t> SendWrap;
54
55 // see tcp_wrap.cc
56 Local<Object> AddressToJS(const sockaddr* addr);
57
58 static Persistent<Function> constructor;
59 static Persistent<String> buffer_sym;
60 static Persistent<String> oncomplete_sym;
61 static Persistent<String> onmessage_sym;
62 static SlabAllocator* slab_allocator;
63
64
65 static void DeleteSlabAllocator(void*) {
66   delete slab_allocator;
67   slab_allocator = NULL;
68 }
69
70
71 UDPWrap::UDPWrap(Handle<Object> object): HandleWrap(object,
72                                                     (uv_handle_t*)&handle_) {
73   int r = uv_udp_init(uv_default_loop(), &handle_);
74   assert(r == 0); // can't fail anyway
75   handle_.data = reinterpret_cast<void*>(this);
76 }
77
78
79 UDPWrap::~UDPWrap() {
80 }
81
82
83 void UDPWrap::Initialize(Handle<Object> target) {
84   HandleWrap::Initialize(target);
85
86   slab_allocator = new SlabAllocator(SLAB_SIZE);
87   AtExit(DeleteSlabAllocator, NULL);
88
89   HandleScope scope;
90
91   buffer_sym = NODE_PSYMBOL("buffer");
92   oncomplete_sym = NODE_PSYMBOL("oncomplete");
93   onmessage_sym = NODE_PSYMBOL("onmessage");
94
95   Local<FunctionTemplate> t = FunctionTemplate::New(New);
96   t->InstanceTemplate()->SetInternalFieldCount(1);
97   t->SetClassName(String::NewSymbol("UDP"));
98
99   enum PropertyAttribute attributes =
100       static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
101   t->InstanceTemplate()->SetAccessor(String::New("fd"),
102                                      UDPWrap::GetFD,
103                                      NULL,
104                                      Handle<Value>(),
105                                      v8::DEFAULT,
106                                      attributes);
107
108   NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
109   NODE_SET_PROTOTYPE_METHOD(t, "send", Send);
110   NODE_SET_PROTOTYPE_METHOD(t, "bind6", Bind6);
111   NODE_SET_PROTOTYPE_METHOD(t, "send6", Send6);
112   NODE_SET_PROTOTYPE_METHOD(t, "close", Close);
113   NODE_SET_PROTOTYPE_METHOD(t, "recvStart", RecvStart);
114   NODE_SET_PROTOTYPE_METHOD(t, "recvStop", RecvStop);
115   NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName);
116   NODE_SET_PROTOTYPE_METHOD(t, "addMembership", AddMembership);
117   NODE_SET_PROTOTYPE_METHOD(t, "dropMembership", DropMembership);
118   NODE_SET_PROTOTYPE_METHOD(t, "setMulticastTTL", SetMulticastTTL);
119   NODE_SET_PROTOTYPE_METHOD(t, "setMulticastLoopback", SetMulticastLoopback);
120   NODE_SET_PROTOTYPE_METHOD(t, "setBroadcast", SetBroadcast);
121   NODE_SET_PROTOTYPE_METHOD(t, "setTTL", SetTTL);
122
123   NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);
124   NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
125
126   constructor = Persistent<Function>::New(
127       Persistent<FunctionTemplate>::New(t)->GetFunction());
128   target->Set(String::NewSymbol("UDP"), constructor);
129 }
130
131
132 Handle<Value> UDPWrap::New(const Arguments& args) {
133   HandleScope scope;
134
135   assert(args.IsConstructCall());
136   new UDPWrap(args.This());
137
138   return scope.Close(args.This());
139 }
140
141
142 Handle<Value> UDPWrap::GetFD(Local<String>, const AccessorInfo& args) {
143 #if defined(_WIN32)
144   return v8::Null();
145 #else
146   HandleScope scope;
147   UNWRAP(UDPWrap)
148   int fd = (wrap == NULL) ? -1 : wrap->handle_.io_watcher.fd;
149   return scope.Close(Integer::New(fd));
150 #endif
151 }
152
153
154 Handle<Value> UDPWrap::DoBind(const Arguments& args, int family) {
155   HandleScope scope;
156   int r;
157
158   UNWRAP(UDPWrap)
159
160   // bind(ip, port, flags)
161   assert(args.Length() == 3);
162
163   String::Utf8Value address(args[0]);
164   const int port = args[1]->Uint32Value();
165   const int flags = args[2]->Uint32Value();
166
167   switch (family) {
168   case AF_INET:
169     r = uv_udp_bind(&wrap->handle_, uv_ip4_addr(*address, port), flags);
170     break;
171   case AF_INET6:
172     r = uv_udp_bind6(&wrap->handle_, uv_ip6_addr(*address, port), flags);
173     break;
174   default:
175     assert(0 && "unexpected address family");
176     abort();
177   }
178
179   if (r)
180     SetErrno(uv_last_error(uv_default_loop()));
181
182   return scope.Close(Integer::New(r));
183 }
184
185
186 Handle<Value> UDPWrap::Bind(const Arguments& args) {
187   return DoBind(args, AF_INET);
188 }
189
190
191 Handle<Value> UDPWrap::Bind6(const Arguments& args) {
192   return DoBind(args, AF_INET6);
193 }
194
195
196 #define X(name, fn)                                                           \
197   Handle<Value> UDPWrap::name(const Arguments& args) {                        \
198     HandleScope scope;                                                        \
199     UNWRAP(UDPWrap)                                                           \
200     assert(args.Length() == 1);                                               \
201     int flag = args[0]->Int32Value();                                         \
202     int r = fn(&wrap->handle_, flag);                                         \
203     if (r) SetErrno(uv_last_error(uv_default_loop()));                        \
204     return scope.Close(Integer::New(r));                                      \
205   }
206
207 X(SetTTL, uv_udp_set_ttl)
208 X(SetBroadcast, uv_udp_set_broadcast)
209 X(SetMulticastTTL, uv_udp_set_multicast_ttl)
210 X(SetMulticastLoopback, uv_udp_set_multicast_loop)
211
212 #undef X
213
214
215 Handle<Value> UDPWrap::SetMembership(const Arguments& args,
216                                      uv_membership membership) {
217   HandleScope scope;
218   UNWRAP(UDPWrap)
219
220   assert(args.Length() == 2);
221
222   String::Utf8Value address(args[0]);
223   String::Utf8Value iface(args[1]);
224
225   const char* iface_cstr = *iface;
226   if (args[1]->IsUndefined() || args[1]->IsNull()) {
227       iface_cstr = NULL;
228   }
229
230   int r = uv_udp_set_membership(&wrap->handle_, *address, iface_cstr,
231                                 membership);
232
233   if (r)
234     SetErrno(uv_last_error(uv_default_loop()));
235
236   return scope.Close(Integer::New(r));
237 }
238
239
240 Handle<Value> UDPWrap::AddMembership(const Arguments& args) {
241   return SetMembership(args, UV_JOIN_GROUP);
242 }
243
244
245 Handle<Value> UDPWrap::DropMembership(const Arguments& args) {
246   return SetMembership(args, UV_LEAVE_GROUP);
247 }
248
249
250 Handle<Value> UDPWrap::DoSend(const Arguments& args, int family) {
251   HandleScope scope;
252   int r;
253
254   // send(buffer, offset, length, port, address)
255   assert(args.Length() == 5);
256
257   UNWRAP(UDPWrap)
258
259   assert(Buffer::HasInstance(args[0]));
260   Local<Object> buffer_obj = args[0]->ToObject();
261
262   size_t offset = args[1]->Uint32Value();
263   size_t length = args[2]->Uint32Value();
264   assert(offset < Buffer::Length(buffer_obj));
265   assert(length <= Buffer::Length(buffer_obj) - offset);
266
267   SendWrap* req_wrap = new SendWrap();
268   req_wrap->object_->SetHiddenValue(buffer_sym, buffer_obj);
269
270   uv_buf_t buf = uv_buf_init(Buffer::Data(buffer_obj) + offset,
271                              length);
272
273   const unsigned short port = args[3]->Uint32Value();
274   String::Utf8Value address(args[4]);
275
276   switch (family) {
277   case AF_INET:
278     r = uv_udp_send(&req_wrap->req_, &wrap->handle_, &buf, 1,
279                     uv_ip4_addr(*address, port), OnSend);
280     break;
281   case AF_INET6:
282     r = uv_udp_send6(&req_wrap->req_, &wrap->handle_, &buf, 1,
283                      uv_ip6_addr(*address, port), OnSend);
284     break;
285   default:
286     assert(0 && "unexpected address family");
287     abort();
288   }
289
290   req_wrap->Dispatched();
291
292   if (r) {
293     SetErrno(uv_last_error(uv_default_loop()));
294     delete req_wrap;
295     return Null();
296   }
297   else {
298     return scope.Close(req_wrap->object_);
299   }
300 }
301
302
303 Handle<Value> UDPWrap::Send(const Arguments& args) {
304   return DoSend(args, AF_INET);
305 }
306
307
308 Handle<Value> UDPWrap::Send6(const Arguments& args) {
309   return DoSend(args, AF_INET6);
310 }
311
312
313 Handle<Value> UDPWrap::RecvStart(const Arguments& args) {
314   HandleScope scope;
315
316   UNWRAP(UDPWrap)
317
318   // UV_EALREADY means that the socket is already bound but that's okay
319   int r = uv_udp_recv_start(&wrap->handle_, OnAlloc, OnRecv);
320   if (r && uv_last_error(uv_default_loop()).code != UV_EALREADY) {
321     SetErrno(uv_last_error(uv_default_loop()));
322     return False();
323   }
324
325   return True();
326 }
327
328
329 Handle<Value> UDPWrap::RecvStop(const Arguments& args) {
330   HandleScope scope;
331
332   UNWRAP(UDPWrap)
333
334   int r = uv_udp_recv_stop(&wrap->handle_);
335
336   return scope.Close(Integer::New(r));
337 }
338
339
340 Handle<Value> UDPWrap::GetSockName(const Arguments& args) {
341   HandleScope scope;
342   struct sockaddr_storage address;
343
344   UNWRAP(UDPWrap)
345
346   int addrlen = sizeof(address);
347   int r = uv_udp_getsockname(&wrap->handle_,
348                              reinterpret_cast<sockaddr*>(&address),
349                              &addrlen);
350
351   if (r) {
352     SetErrno(uv_last_error(uv_default_loop()));
353     return Null();
354   }
355
356   const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
357   return scope.Close(AddressToJS(addr));
358 }
359
360
361 // TODO share with StreamWrap::AfterWrite() in stream_wrap.cc
362 void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
363   HandleScope scope;
364
365   assert(req != NULL);
366
367   SendWrap* req_wrap = reinterpret_cast<SendWrap*>(req->data);
368   UDPWrap* wrap = reinterpret_cast<UDPWrap*>(req->handle->data);
369
370   assert(req_wrap->object_.IsEmpty() == false);
371   assert(wrap->object_.IsEmpty() == false);
372
373   if (status) {
374     SetErrno(uv_last_error(uv_default_loop()));
375   }
376
377   Local<Value> argv[4] = {
378     Integer::New(status),
379     Local<Value>::New(wrap->object_),
380     Local<Value>::New(req_wrap->object_),
381     req_wrap->object_->GetHiddenValue(buffer_sym),
382   };
383
384   MakeCallback(req_wrap->object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
385   delete req_wrap;
386 }
387
388
389 uv_buf_t UDPWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) {
390   UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
391   char* buf = slab_allocator->Allocate(wrap->object_, suggested_size);
392   return uv_buf_init(buf, suggested_size);
393 }
394
395
396 void UDPWrap::OnRecv(uv_udp_t* handle,
397                      ssize_t nread,
398                      uv_buf_t buf,
399                      struct sockaddr* addr,
400                      unsigned flags) {
401   HandleScope scope;
402
403   UDPWrap* wrap = reinterpret_cast<UDPWrap*>(handle->data);
404   Local<Object> slab = slab_allocator->Shrink(wrap->object_,
405                                               buf.base,
406                                               nread < 0 ? 0 : nread);
407   if (nread == 0) return;
408
409   if (nread < 0) {
410     Local<Value> argv[] = { Local<Object>::New(wrap->object_) };
411     SetErrno(uv_last_error(uv_default_loop()));
412     MakeCallback(wrap->object_, onmessage_sym, ARRAY_SIZE(argv), argv);
413     return;
414   }
415
416   Local<Value> argv[] = {
417     Local<Object>::New(wrap->object_),
418     slab,
419     Integer::NewFromUnsigned(buf.base - Buffer::Data(slab)),
420     Integer::NewFromUnsigned(nread),
421     AddressToJS(addr)
422   };
423   MakeCallback(wrap->object_, onmessage_sym, ARRAY_SIZE(argv), argv);
424 }
425
426
427 UDPWrap* UDPWrap::Unwrap(Local<Object> obj) {
428   assert(!obj.IsEmpty());
429   assert(obj->InternalFieldCount() > 0);
430   return static_cast<UDPWrap*>(obj->GetPointerFromInternalField(0));
431 }
432
433
434 Local<Object> UDPWrap::Instantiate() {
435   // If this assert fires then Initialize hasn't been called yet.
436   assert(constructor.IsEmpty() == false);
437
438   HandleScope scope;
439   Local<Object> obj = constructor->NewInstance();
440
441   return scope.Close(obj);
442 }
443
444
445 uv_udp_t* UDPWrap::UVHandle() {
446   return &handle_;
447 }
448
449
450 } // namespace node
451
452 NODE_MODULE(node_udp_wrap, node::UDPWrap::Initialize)