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