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