Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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