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