src: deduplicate CHECK_EQ/CHECK_NE macros
[platform/upstream/nodejs.git] / src / tcp_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 "tcp_wrap.h"
23
24 #include "env.h"
25 #include "env-inl.h"
26 #include "handle_wrap.h"
27 #include "node_buffer.h"
28 #include "node_wrap.h"
29 #include "req_wrap.h"
30 #include "stream_wrap.h"
31 #include "util.h"
32 #include "util-inl.h"
33
34 #include <stdlib.h>
35
36
37 namespace node {
38
39 using v8::Context;
40 using v8::EscapableHandleScope;
41 using v8::Function;
42 using v8::FunctionCallbackInfo;
43 using v8::FunctionTemplate;
44 using v8::Handle;
45 using v8::HandleScope;
46 using v8::Integer;
47 using v8::Local;
48 using v8::Object;
49 using v8::PropertyAttribute;
50 using v8::String;
51 using v8::Undefined;
52 using v8::Value;
53
54 typedef class ReqWrap<uv_connect_t> ConnectWrap;
55
56
57 Local<Object> TCPWrap::Instantiate(Environment* env) {
58   EscapableHandleScope handle_scope(env->isolate());
59   assert(env->tcp_constructor_template().IsEmpty() == false);
60   Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
61   assert(constructor.IsEmpty() == false);
62   Local<Object> instance = constructor->NewInstance();
63   assert(instance.IsEmpty() == false);
64   return handle_scope.Escape(instance);
65 }
66
67
68 void TCPWrap::Initialize(Handle<Object> target,
69                          Handle<Value> unused,
70                          Handle<Context> context) {
71   Environment* env = Environment::GetCurrent(context);
72
73   Local<FunctionTemplate> t = FunctionTemplate::New(env->isolate(), New);
74   t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP"));
75   t->InstanceTemplate()->SetInternalFieldCount(1);
76
77   enum PropertyAttribute attributes =
78       static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
79   t->InstanceTemplate()->SetAccessor(env->fd_string(),
80                                      StreamWrap::GetFD,
81                                      NULL,
82                                      Handle<Value>(),
83                                      v8::DEFAULT,
84                                      attributes);
85
86   NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close);
87
88   NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);
89   NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
90
91   NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
92   NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
93   NODE_SET_PROTOTYPE_METHOD(t, "shutdown", StreamWrap::Shutdown);
94
95   NODE_SET_PROTOTYPE_METHOD(t, "writeBuffer", StreamWrap::WriteBuffer);
96   NODE_SET_PROTOTYPE_METHOD(t,
97                             "writeAsciiString",
98                             StreamWrap::WriteAsciiString);
99   NODE_SET_PROTOTYPE_METHOD(t, "writeUtf8String", StreamWrap::WriteUtf8String);
100   NODE_SET_PROTOTYPE_METHOD(t, "writeUcs2String", StreamWrap::WriteUcs2String);
101   NODE_SET_PROTOTYPE_METHOD(t, "writev", StreamWrap::Writev);
102
103   NODE_SET_PROTOTYPE_METHOD(t, "open", Open);
104   NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
105   NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
106   NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect);
107   NODE_SET_PROTOTYPE_METHOD(t, "bind6", Bind6);
108   NODE_SET_PROTOTYPE_METHOD(t, "connect6", Connect6);
109   NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName);
110   NODE_SET_PROTOTYPE_METHOD(t, "getpeername", GetPeerName);
111   NODE_SET_PROTOTYPE_METHOD(t, "setNoDelay", SetNoDelay);
112   NODE_SET_PROTOTYPE_METHOD(t, "setKeepAlive", SetKeepAlive);
113
114 #ifdef _WIN32
115   NODE_SET_PROTOTYPE_METHOD(t,
116                             "setSimultaneousAccepts",
117                             SetSimultaneousAccepts);
118 #endif
119
120   target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCP"), t->GetFunction());
121   env->set_tcp_constructor_template(t);
122 }
123
124
125 uv_tcp_t* TCPWrap::UVHandle() {
126   return &handle_;
127 }
128
129
130 void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
131   // This constructor should not be exposed to public javascript.
132   // Therefore we assert that we are not trying to call this as a
133   // normal function.
134   assert(args.IsConstructCall());
135   HandleScope handle_scope(args.GetIsolate());
136   Environment* env = Environment::GetCurrent(args.GetIsolate());
137   TCPWrap* wrap = new TCPWrap(env, args.This());
138   assert(wrap);
139 }
140
141
142 TCPWrap::TCPWrap(Environment* env, Handle<Object> object)
143     : StreamWrap(env,
144                  object,
145                  reinterpret_cast<uv_stream_t*>(&handle_),
146                  AsyncWrap::PROVIDER_TCPWRAP) {
147   int r = uv_tcp_init(env->event_loop(), &handle_);
148   assert(r == 0);  // How do we proxy this error up to javascript?
149                    // Suggestion: uv_tcp_init() returns void.
150   UpdateWriteQueueSize();
151 }
152
153
154 TCPWrap::~TCPWrap() {
155   assert(persistent().IsEmpty());
156 }
157
158
159 void TCPWrap::GetSockName(const FunctionCallbackInfo<Value>& args) {
160   HandleScope handle_scope(args.GetIsolate());
161   Environment* env = Environment::GetCurrent(args.GetIsolate());
162   struct sockaddr_storage address;
163
164   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
165
166   assert(args[0]->IsObject());
167   Local<Object> out = args[0].As<Object>();
168
169   int addrlen = sizeof(address);
170   int err = uv_tcp_getsockname(&wrap->handle_,
171                                reinterpret_cast<sockaddr*>(&address),
172                                &addrlen);
173   if (err == 0) {
174     const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
175     AddressToJS(env, addr, out);
176   }
177
178   args.GetReturnValue().Set(err);
179 }
180
181
182 void TCPWrap::GetPeerName(const FunctionCallbackInfo<Value>& args) {
183   HandleScope handle_scope(args.GetIsolate());
184   Environment* env = Environment::GetCurrent(args.GetIsolate());
185   struct sockaddr_storage address;
186
187   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
188
189   assert(args[0]->IsObject());
190   Local<Object> out = args[0].As<Object>();
191
192   int addrlen = sizeof(address);
193   int err = uv_tcp_getpeername(&wrap->handle_,
194                                reinterpret_cast<sockaddr*>(&address),
195                                &addrlen);
196   if (err == 0) {
197     const sockaddr* addr = reinterpret_cast<const sockaddr*>(&address);
198     AddressToJS(env, addr, out);
199   }
200
201   args.GetReturnValue().Set(err);
202 }
203
204
205 void TCPWrap::SetNoDelay(const FunctionCallbackInfo<Value>& args) {
206   Environment* env = Environment::GetCurrent(args.GetIsolate());
207   HandleScope scope(env->isolate());
208
209   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
210
211   int enable = static_cast<int>(args[0]->BooleanValue());
212   int err = uv_tcp_nodelay(&wrap->handle_, enable);
213   args.GetReturnValue().Set(err);
214 }
215
216
217 void TCPWrap::SetKeepAlive(const FunctionCallbackInfo<Value>& args) {
218   Environment* env = Environment::GetCurrent(args.GetIsolate());
219   HandleScope scope(env->isolate());
220
221   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
222
223   int enable = args[0]->Int32Value();
224   unsigned int delay = args[1]->Uint32Value();
225
226   int err = uv_tcp_keepalive(&wrap->handle_, enable, delay);
227   args.GetReturnValue().Set(err);
228 }
229
230
231 #ifdef _WIN32
232 void TCPWrap::SetSimultaneousAccepts(const FunctionCallbackInfo<Value>& args) {
233   Environment* env = Environment::GetCurrent(args.GetIsolate());
234   HandleScope scope(env->isolate());
235
236   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
237
238   bool enable = args[0]->BooleanValue();
239   int err = uv_tcp_simultaneous_accepts(&wrap->handle_, enable);
240   args.GetReturnValue().Set(err);
241 }
242 #endif
243
244
245 void TCPWrap::Open(const FunctionCallbackInfo<Value>& args) {
246   Environment* env = Environment::GetCurrent(args.GetIsolate());
247   HandleScope scope(env->isolate());
248   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
249   int fd = args[0]->IntegerValue();
250   uv_tcp_open(&wrap->handle_, fd);
251 }
252
253
254 void TCPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
255   Environment* env = Environment::GetCurrent(args.GetIsolate());
256   HandleScope scope(env->isolate());
257
258   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
259
260   String::Utf8Value ip_address(args[0]);
261   int port = args[1]->Int32Value();
262
263   sockaddr_in addr;
264   int err = uv_ip4_addr(*ip_address, port, &addr);
265   if (err == 0) {
266     err = uv_tcp_bind(&wrap->handle_,
267                       reinterpret_cast<const sockaddr*>(&addr),
268                       0);
269   }
270
271   args.GetReturnValue().Set(err);
272 }
273
274
275 void TCPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
276   Environment* env = Environment::GetCurrent(args.GetIsolate());
277   HandleScope scope(env->isolate());
278
279   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
280
281   String::Utf8Value ip6_address(args[0]);
282   int port = args[1]->Int32Value();
283
284   sockaddr_in6 addr;
285   int err = uv_ip6_addr(*ip6_address, port, &addr);
286   if (err == 0) {
287     err = uv_tcp_bind(&wrap->handle_,
288                       reinterpret_cast<const sockaddr*>(&addr),
289                       0);
290   }
291
292   args.GetReturnValue().Set(err);
293 }
294
295
296 void TCPWrap::Listen(const FunctionCallbackInfo<Value>& args) {
297   Environment* env = Environment::GetCurrent(args.GetIsolate());
298   HandleScope scope(env->isolate());
299
300   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
301
302   int backlog = args[0]->Int32Value();
303   int err = uv_listen(reinterpret_cast<uv_stream_t*>(&wrap->handle_),
304                       backlog,
305                       OnConnection);
306   args.GetReturnValue().Set(err);
307 }
308
309
310 void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
311   TCPWrap* tcp_wrap = static_cast<TCPWrap*>(handle->data);
312   assert(&tcp_wrap->handle_ == reinterpret_cast<uv_tcp_t*>(handle));
313   Environment* env = tcp_wrap->env();
314
315   HandleScope handle_scope(env->isolate());
316   Context::Scope context_scope(env->context());
317
318   // We should not be getting this callback if someone as already called
319   // uv_close() on the handle.
320   assert(tcp_wrap->persistent().IsEmpty() == false);
321
322   Local<Value> argv[2] = {
323     Integer::New(env->isolate(), status),
324     Undefined(env->isolate())
325   };
326
327   if (status == 0) {
328     // Instantiate the client javascript object and handle.
329     Local<Object> client_obj = Instantiate(env);
330
331     // Unwrap the client javascript object.
332     TCPWrap* wrap = Unwrap<TCPWrap>(client_obj);
333     uv_stream_t* client_handle = reinterpret_cast<uv_stream_t*>(&wrap->handle_);
334     if (uv_accept(handle, client_handle))
335       return;
336
337     // Successful accept. Call the onconnection callback in JavaScript land.
338     argv[1] = client_obj;
339   }
340
341   tcp_wrap->MakeCallback(env->onconnection_string(), ARRAY_SIZE(argv), argv);
342 }
343
344
345 void TCPWrap::AfterConnect(uv_connect_t* req, int status) {
346   ConnectWrap* req_wrap = static_cast<ConnectWrap*>(req->data);
347   TCPWrap* wrap = static_cast<TCPWrap*>(req->handle->data);
348   assert(req_wrap->env() == wrap->env());
349   Environment* env = wrap->env();
350
351   HandleScope handle_scope(env->isolate());
352   Context::Scope context_scope(env->context());
353
354   // The wrap and request objects should still be there.
355   assert(req_wrap->persistent().IsEmpty() == false);
356   assert(wrap->persistent().IsEmpty() == false);
357
358   Local<Object> req_wrap_obj = req_wrap->object();
359   Local<Value> argv[5] = {
360     Integer::New(env->isolate(), status),
361     wrap->object(),
362     req_wrap_obj,
363     v8::True(env->isolate()),
364     v8::True(env->isolate())
365   };
366
367   req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
368
369   delete req_wrap;
370 }
371
372
373 void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
374   HandleScope handle_scope(args.GetIsolate());
375   Environment* env = Environment::GetCurrent(args.GetIsolate());
376
377   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
378
379   assert(args[0]->IsObject());
380   assert(args[1]->IsString());
381   assert(args[2]->Uint32Value());
382
383   Local<Object> req_wrap_obj = args[0].As<Object>();
384   String::Utf8Value ip_address(args[1]);
385   int port = args[2]->Uint32Value();
386
387   sockaddr_in addr;
388   int err = uv_ip4_addr(*ip_address, port, &addr);
389
390   if (err == 0) {
391     ConnectWrap* req_wrap = new ConnectWrap(env,
392                                             req_wrap_obj,
393                                             AsyncWrap::PROVIDER_CONNECTWRAP);
394     err = uv_tcp_connect(&req_wrap->req_,
395                          &wrap->handle_,
396                          reinterpret_cast<const sockaddr*>(&addr),
397                          AfterConnect);
398     req_wrap->Dispatched();
399     if (err)
400       delete req_wrap;
401   }
402
403   args.GetReturnValue().Set(err);
404 }
405
406
407 void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
408   HandleScope handle_scope(args.GetIsolate());
409   Environment* env = Environment::GetCurrent(args.GetIsolate());
410
411   TCPWrap* wrap = Unwrap<TCPWrap>(args.This());
412
413   assert(args[0]->IsObject());
414   assert(args[1]->IsString());
415   assert(args[2]->Uint32Value());
416
417   Local<Object> req_wrap_obj = args[0].As<Object>();
418   String::Utf8Value ip_address(args[1]);
419   int port = args[2]->Int32Value();
420
421   sockaddr_in6 addr;
422   int err = uv_ip6_addr(*ip_address, port, &addr);
423
424   if (err == 0) {
425     ConnectWrap* req_wrap = new ConnectWrap(env,
426                                             req_wrap_obj,
427                                             AsyncWrap::PROVIDER_CONNECTWRAP);
428     err = uv_tcp_connect(&req_wrap->req_,
429                          &wrap->handle_,
430                          reinterpret_cast<const sockaddr*>(&addr),
431                          AfterConnect);
432     req_wrap->Dispatched();
433     if (err)
434       delete req_wrap;
435   }
436
437   args.GetReturnValue().Set(err);
438 }
439
440
441 // also used by udp_wrap.cc
442 Local<Object> AddressToJS(Environment* env,
443                           const sockaddr* addr,
444                           Local<Object> info) {
445   EscapableHandleScope scope(env->isolate());
446   char ip[INET6_ADDRSTRLEN];
447   const sockaddr_in *a4;
448   const sockaddr_in6 *a6;
449   int port;
450
451   if (info.IsEmpty())
452     info = Object::New(env->isolate());
453
454   switch (addr->sa_family) {
455   case AF_INET6:
456     a6 = reinterpret_cast<const sockaddr_in6*>(addr);
457     uv_inet_ntop(AF_INET6, &a6->sin6_addr, ip, sizeof ip);
458     port = ntohs(a6->sin6_port);
459     info->Set(env->address_string(), OneByteString(env->isolate(), ip));
460     info->Set(env->family_string(), env->ipv6_string());
461     info->Set(env->port_string(), Integer::New(env->isolate(), port));
462     break;
463
464   case AF_INET:
465     a4 = reinterpret_cast<const sockaddr_in*>(addr);
466     uv_inet_ntop(AF_INET, &a4->sin_addr, ip, sizeof ip);
467     port = ntohs(a4->sin_port);
468     info->Set(env->address_string(), OneByteString(env->isolate(), ip));
469     info->Set(env->family_string(), env->ipv4_string());
470     info->Set(env->port_string(), Integer::New(env->isolate(), port));
471     break;
472
473   default:
474     info->Set(env->address_string(), String::Empty(env->isolate()));
475   }
476
477   return scope.Escape(info);
478 }
479
480
481 }  // namespace node
482
483 NODE_MODULE_CONTEXT_AWARE_BUILTIN(tcp_wrap, node::TCPWrap::Initialize)