• 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 "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