• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "connect_wrap.h"
25 #include "connection_wrap.h"
26 #include "env-inl.h"
27 #include "handle_wrap.h"
28 #include "node_buffer.h"
29 #include "node_external_reference.h"
30 #include "node_internals.h"
31 #include "stream_base-inl.h"
32 #include "stream_wrap.h"
33 #include "util-inl.h"
34 
35 #include <cstdlib>
36 
37 
38 namespace node {
39 
40 using v8::Boolean;
41 using v8::Context;
42 using v8::EscapableHandleScope;
43 using v8::Function;
44 using v8::FunctionCallbackInfo;
45 using v8::FunctionTemplate;
46 using v8::Int32;
47 using v8::Integer;
48 using v8::Isolate;
49 using v8::Local;
50 using v8::MaybeLocal;
51 using v8::Object;
52 using v8::String;
53 using v8::Uint32;
54 using v8::Value;
55 
Instantiate(Environment * env,AsyncWrap * parent,TCPWrap::SocketType type)56 MaybeLocal<Object> TCPWrap::Instantiate(Environment* env,
57                                         AsyncWrap* parent,
58                                         TCPWrap::SocketType type) {
59   EscapableHandleScope handle_scope(env->isolate());
60   AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent);
61   CHECK_EQ(env->tcp_constructor_template().IsEmpty(), false);
62   Local<Function> constructor = env->tcp_constructor_template()
63                                     ->GetFunction(env->context())
64                                     .ToLocalChecked();
65   CHECK_EQ(constructor.IsEmpty(), false);
66   Local<Value> type_value = Int32::New(env->isolate(), type);
67   return handle_scope.EscapeMaybe(
68       constructor->NewInstance(env->context(), 1, &type_value));
69 }
70 
71 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)72 void TCPWrap::Initialize(Local<Object> target,
73                          Local<Value> unused,
74                          Local<Context> context,
75                          void* priv) {
76   Environment* env = Environment::GetCurrent(context);
77   Isolate* isolate = env->isolate();
78 
79   Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
80   t->InstanceTemplate()->SetInternalFieldCount(StreamBase::kInternalFieldCount);
81 
82   // Init properties
83   t->InstanceTemplate()->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "reading"),
84                              Boolean::New(env->isolate(), false));
85   t->InstanceTemplate()->Set(env->owner_symbol(), Null(env->isolate()));
86   t->InstanceTemplate()->Set(env->onconnection_string(), Null(env->isolate()));
87 
88   t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));
89 
90   SetProtoMethod(isolate, t, "open", Open);
91   SetProtoMethod(isolate, t, "bind", Bind);
92   SetProtoMethod(isolate, t, "listen", Listen);
93   SetProtoMethod(isolate, t, "connect", Connect);
94   SetProtoMethod(isolate, t, "bind6", Bind6);
95   SetProtoMethod(isolate, t, "connect6", Connect6);
96   SetProtoMethod(isolate,
97                  t,
98                  "getsockname",
99                  GetSockOrPeerName<TCPWrap, uv_tcp_getsockname>);
100   SetProtoMethod(isolate,
101                  t,
102                  "getpeername",
103                  GetSockOrPeerName<TCPWrap, uv_tcp_getpeername>);
104   SetProtoMethod(isolate, t, "setNoDelay", SetNoDelay);
105   SetProtoMethod(isolate, t, "setKeepAlive", SetKeepAlive);
106   SetProtoMethod(isolate, t, "reset", Reset);
107 
108 #ifdef _WIN32
109   SetProtoMethod(isolate, t, "setSimultaneousAccepts", SetSimultaneousAccepts);
110 #endif
111 
112   SetConstructorFunction(context, target, "TCP", t);
113   env->set_tcp_constructor_template(t);
114 
115   // Create FunctionTemplate for TCPConnectWrap.
116   Local<FunctionTemplate> cwt =
117       BaseObject::MakeLazilyInitializedJSTemplate(env);
118   cwt->Inherit(AsyncWrap::GetConstructorTemplate(env));
119   SetConstructorFunction(context, target, "TCPConnectWrap", cwt);
120 
121   // Define constants
122   Local<Object> constants = Object::New(env->isolate());
123   NODE_DEFINE_CONSTANT(constants, SOCKET);
124   NODE_DEFINE_CONSTANT(constants, SERVER);
125   NODE_DEFINE_CONSTANT(constants, UV_TCP_IPV6ONLY);
126   target->Set(context,
127               env->constants_string(),
128               constants).Check();
129 }
130 
RegisterExternalReferences(ExternalReferenceRegistry * registry)131 void TCPWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
132   registry->Register(New);
133   registry->Register(Open);
134   registry->Register(Bind);
135   registry->Register(Listen);
136   registry->Register(Connect);
137   registry->Register(Bind6);
138   registry->Register(Connect6);
139 
140   registry->Register(GetSockOrPeerName<TCPWrap, uv_tcp_getsockname>);
141   registry->Register(GetSockOrPeerName<TCPWrap, uv_tcp_getpeername>);
142   registry->Register(SetNoDelay);
143   registry->Register(SetKeepAlive);
144   registry->Register(Reset);
145 #ifdef _WIN32
146   registry->Register(SetSimultaneousAccepts);
147 #endif
148 }
149 
New(const FunctionCallbackInfo<Value> & args)150 void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
151   // This constructor should not be exposed to public javascript.
152   // Therefore we assert that we are not trying to call this as a
153   // normal function.
154   CHECK(args.IsConstructCall());
155   CHECK(args[0]->IsInt32());
156   Environment* env = Environment::GetCurrent(args);
157 
158   int type_value = args[0].As<Int32>()->Value();
159   TCPWrap::SocketType type = static_cast<TCPWrap::SocketType>(type_value);
160 
161   ProviderType provider;
162   switch (type) {
163     case SOCKET:
164       provider = PROVIDER_TCPWRAP;
165       break;
166     case SERVER:
167       provider = PROVIDER_TCPSERVERWRAP;
168       break;
169     default:
170       UNREACHABLE();
171   }
172 
173   new TCPWrap(env, args.This(), provider);
174 }
175 
176 
TCPWrap(Environment * env,Local<Object> object,ProviderType provider)177 TCPWrap::TCPWrap(Environment* env, Local<Object> object, ProviderType provider)
178     : ConnectionWrap(env, object, provider) {
179   int r = uv_tcp_init(env->event_loop(), &handle_);
180   CHECK_EQ(r, 0);  // How do we proxy this error up to javascript?
181                    // Suggestion: uv_tcp_init() returns void.
182 }
183 
184 
SetNoDelay(const FunctionCallbackInfo<Value> & args)185 void TCPWrap::SetNoDelay(const FunctionCallbackInfo<Value>& args) {
186   TCPWrap* wrap;
187   ASSIGN_OR_RETURN_UNWRAP(&wrap,
188                           args.Holder(),
189                           args.GetReturnValue().Set(UV_EBADF));
190   int enable = static_cast<int>(args[0]->IsTrue());
191   int err = uv_tcp_nodelay(&wrap->handle_, enable);
192   args.GetReturnValue().Set(err);
193 }
194 
195 
SetKeepAlive(const FunctionCallbackInfo<Value> & args)196 void TCPWrap::SetKeepAlive(const FunctionCallbackInfo<Value>& args) {
197   TCPWrap* wrap;
198   ASSIGN_OR_RETURN_UNWRAP(&wrap,
199                           args.Holder(),
200                           args.GetReturnValue().Set(UV_EBADF));
201   Environment* env = wrap->env();
202   int enable;
203   if (!args[0]->Int32Value(env->context()).To(&enable)) return;
204   unsigned int delay = static_cast<unsigned int>(args[1].As<Uint32>()->Value());
205   int err = uv_tcp_keepalive(&wrap->handle_, enable, delay);
206   args.GetReturnValue().Set(err);
207 }
208 
209 
210 #ifdef _WIN32
SetSimultaneousAccepts(const FunctionCallbackInfo<Value> & args)211 void TCPWrap::SetSimultaneousAccepts(const FunctionCallbackInfo<Value>& args) {
212   TCPWrap* wrap;
213   ASSIGN_OR_RETURN_UNWRAP(&wrap,
214                           args.Holder(),
215                           args.GetReturnValue().Set(UV_EBADF));
216   bool enable = args[0]->IsTrue();
217   int err = uv_tcp_simultaneous_accepts(&wrap->handle_, enable);
218   args.GetReturnValue().Set(err);
219 }
220 #endif
221 
222 
Open(const FunctionCallbackInfo<Value> & args)223 void TCPWrap::Open(const FunctionCallbackInfo<Value>& args) {
224   TCPWrap* wrap;
225   ASSIGN_OR_RETURN_UNWRAP(&wrap,
226                           args.Holder(),
227                           args.GetReturnValue().Set(UV_EBADF));
228   int64_t val;
229   if (!args[0]->IntegerValue(args.GetIsolate()->GetCurrentContext()).To(&val))
230     return;
231   int fd = static_cast<int>(val);
232   int err = uv_tcp_open(&wrap->handle_, fd);
233 
234   if (err == 0)
235     wrap->set_fd(fd);
236 
237   args.GetReturnValue().Set(err);
238 }
239 
240 template <typename T>
Bind(const FunctionCallbackInfo<Value> & args,int family,std::function<int (const char * ip_address,int port,T * addr)> uv_ip_addr)241 void TCPWrap::Bind(
242     const FunctionCallbackInfo<Value>& args,
243     int family,
244     std::function<int(const char* ip_address, int port, T* addr)> uv_ip_addr) {
245   TCPWrap* wrap;
246   ASSIGN_OR_RETURN_UNWRAP(&wrap,
247                           args.Holder(),
248                           args.GetReturnValue().Set(UV_EBADF));
249   Environment* env = wrap->env();
250   node::Utf8Value ip_address(env->isolate(), args[0]);
251   int port;
252   unsigned int flags = 0;
253   if (!args[1]->Int32Value(env->context()).To(&port)) return;
254   if (family == AF_INET6 &&
255       !args[2]->Uint32Value(env->context()).To(&flags)) {
256     return;
257   }
258 
259   T addr;
260   int err = uv_ip_addr(*ip_address, port, &addr);
261 
262   if (err == 0) {
263     err = uv_tcp_bind(&wrap->handle_,
264                       reinterpret_cast<const sockaddr*>(&addr),
265                       flags);
266   }
267   args.GetReturnValue().Set(err);
268 }
269 
Bind(const FunctionCallbackInfo<Value> & args)270 void TCPWrap::Bind(const FunctionCallbackInfo<Value>& args) {
271   Bind<sockaddr_in>(args, AF_INET, uv_ip4_addr);
272 }
273 
274 
Bind6(const FunctionCallbackInfo<Value> & args)275 void TCPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
276   Bind<sockaddr_in6>(args, AF_INET6, uv_ip6_addr);
277 }
278 
279 
Listen(const FunctionCallbackInfo<Value> & args)280 void TCPWrap::Listen(const FunctionCallbackInfo<Value>& args) {
281   TCPWrap* wrap;
282   ASSIGN_OR_RETURN_UNWRAP(&wrap,
283                           args.Holder(),
284                           args.GetReturnValue().Set(UV_EBADF));
285   Environment* env = wrap->env();
286   int backlog;
287   if (!args[0]->Int32Value(env->context()).To(&backlog)) return;
288   int err = uv_listen(reinterpret_cast<uv_stream_t*>(&wrap->handle_),
289                       backlog,
290                       OnConnection);
291   args.GetReturnValue().Set(err);
292 }
293 
294 
Connect(const FunctionCallbackInfo<Value> & args)295 void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
296   CHECK(args[2]->IsUint32());
297   // explicit cast to fit to libuv's type expectation
298   int port = static_cast<int>(args[2].As<Uint32>()->Value());
299   Connect<sockaddr_in>(args,
300                        [port](const char* ip_address, sockaddr_in* addr) {
301       return uv_ip4_addr(ip_address, port, addr);
302   });
303 }
304 
305 
Connect6(const FunctionCallbackInfo<Value> & args)306 void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
307   Environment* env = Environment::GetCurrent(args);
308   CHECK(args[2]->IsUint32());
309   int port;
310   if (!args[2]->Int32Value(env->context()).To(&port)) return;
311   Connect<sockaddr_in6>(args,
312                         [port](const char* ip_address, sockaddr_in6* addr) {
313       return uv_ip6_addr(ip_address, port, addr);
314   });
315 }
316 
317 template <typename T>
Connect(const FunctionCallbackInfo<Value> & args,std::function<int (const char * ip_address,T * addr)> uv_ip_addr)318 void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args,
319     std::function<int(const char* ip_address, T* addr)> uv_ip_addr) {
320   Environment* env = Environment::GetCurrent(args);
321 
322   TCPWrap* wrap;
323   ASSIGN_OR_RETURN_UNWRAP(&wrap,
324                           args.Holder(),
325                           args.GetReturnValue().Set(UV_EBADF));
326 
327   CHECK(args[0]->IsObject());
328   CHECK(args[1]->IsString());
329 
330   Local<Object> req_wrap_obj = args[0].As<Object>();
331   node::Utf8Value ip_address(env->isolate(), args[1]);
332 
333   T addr;
334   int err = uv_ip_addr(*ip_address, &addr);
335 
336   if (err == 0) {
337     AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(wrap);
338     ConnectWrap* req_wrap =
339         new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP);
340     err = req_wrap->Dispatch(uv_tcp_connect,
341                              &wrap->handle_,
342                              reinterpret_cast<const sockaddr*>(&addr),
343                              AfterConnect);
344     if (err) {
345       delete req_wrap;
346     } else {
347       CHECK(args[2]->Uint32Value(env->context()).IsJust());
348       int port = args[2]->Uint32Value(env->context()).FromJust();
349       TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(TRACING_CATEGORY_NODE2(net, native),
350                                         "connect",
351                                         req_wrap,
352                                         "ip",
353                                         TRACE_STR_COPY(*ip_address),
354                                         "port",
355                                         port);
356     }
357   }
358 
359   args.GetReturnValue().Set(err);
360 }
Reset(const FunctionCallbackInfo<Value> & args)361 void TCPWrap::Reset(const FunctionCallbackInfo<Value>& args) {
362   TCPWrap* wrap;
363   ASSIGN_OR_RETURN_UNWRAP(
364       &wrap, args.Holder(), args.GetReturnValue().Set(UV_EBADF));
365 
366   int err = wrap->Reset(args[0]);
367 
368   args.GetReturnValue().Set(err);
369 }
370 
Reset(Local<Value> close_callback)371 int TCPWrap::Reset(Local<Value> close_callback) {
372   if (state_ != kInitialized) return 0;
373 
374   int err = uv_tcp_close_reset(&handle_, OnClose);
375   state_ = kClosing;
376   if (!err & !close_callback.IsEmpty() && close_callback->IsFunction() &&
377       !persistent().IsEmpty()) {
378     object()
379         ->Set(env()->context(), env()->handle_onclose_symbol(), close_callback)
380         .Check();
381   }
382   return err;
383 }
384 
385 // also used by udp_wrap.cc
AddressToJS(Environment * env,const sockaddr * addr,Local<Object> info)386 MaybeLocal<Object> AddressToJS(Environment* env,
387                                const sockaddr* addr,
388                                Local<Object> info) {
389   EscapableHandleScope scope(env->isolate());
390   char ip[INET6_ADDRSTRLEN + UV_IF_NAMESIZE];
391   const sockaddr_in* a4;
392   const sockaddr_in6* a6;
393 
394   int port;
395 
396   if (info.IsEmpty())
397     info = Object::New(env->isolate());
398 
399   switch (addr->sa_family) {
400   case AF_INET6:
401     a6 = reinterpret_cast<const sockaddr_in6*>(addr);
402     uv_inet_ntop(AF_INET6, &a6->sin6_addr, ip, sizeof ip);
403     // Add an interface identifier to a link local address.
404     if (IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr) && a6->sin6_scope_id > 0) {
405       const size_t addrlen = strlen(ip);
406       CHECK_LT(addrlen, sizeof(ip));
407       ip[addrlen] = '%';
408       size_t scopeidlen = sizeof(ip) - addrlen - 1;
409       CHECK_GE(scopeidlen, UV_IF_NAMESIZE);
410       const int r = uv_if_indextoiid(a6->sin6_scope_id,
411                                      ip + addrlen + 1,
412                                      &scopeidlen);
413       if (r) {
414         env->ThrowUVException(r, "uv_if_indextoiid");
415         return {};
416       }
417     }
418     port = ntohs(a6->sin6_port);
419     info->Set(env->context(),
420               env->address_string(),
421               OneByteString(env->isolate(), ip)).Check();
422     info->Set(env->context(), env->family_string(), env->ipv6_string()).Check();
423     info->Set(env->context(),
424               env->port_string(),
425               Integer::New(env->isolate(), port)).Check();
426     break;
427 
428   case AF_INET:
429     a4 = reinterpret_cast<const sockaddr_in*>(addr);
430     uv_inet_ntop(AF_INET, &a4->sin_addr, ip, sizeof ip);
431     port = ntohs(a4->sin_port);
432     info->Set(env->context(),
433               env->address_string(),
434               OneByteString(env->isolate(), ip)).Check();
435     info->Set(env->context(), env->family_string(), env->ipv4_string()).Check();
436     info->Set(env->context(),
437               env->port_string(),
438               Integer::New(env->isolate(), port)).Check();
439     break;
440 
441   default:
442     info->Set(env->context(),
443               env->address_string(),
444               String::Empty(env->isolate())).Check();
445   }
446 
447   return scope.Escape(info);
448 }
449 
450 
451 }  // namespace node
452 
453 NODE_BINDING_CONTEXT_AWARE_INTERNAL(tcp_wrap, node::TCPWrap::Initialize)
454 NODE_BINDING_EXTERNAL_REFERENCE(tcp_wrap,
455                                 node::TCPWrap::RegisterExternalReferences)
456