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