Coverage Report

Created: 2025-08-28 09:57

/src/node/src/pipe_wrap.cc
Line
Count
Source (jump to first uncovered line)
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 "pipe_wrap.h"
23
24
#include "async_wrap.h"
25
#include "connect_wrap.h"
26
#include "connection_wrap.h"
27
#include "env-inl.h"
28
#include "handle_wrap.h"
29
#include "node.h"
30
#include "node_buffer.h"
31
#include "node_external_reference.h"
32
#include "stream_base-inl.h"
33
#include "stream_wrap.h"
34
#include "util-inl.h"
35
36
namespace node {
37
38
using v8::Context;
39
using v8::EscapableHandleScope;
40
using v8::Function;
41
using v8::FunctionCallbackInfo;
42
using v8::FunctionTemplate;
43
using v8::Int32;
44
using v8::Isolate;
45
using v8::Local;
46
using v8::MaybeLocal;
47
using v8::Object;
48
using v8::Value;
49
50
MaybeLocal<Object> PipeWrap::Instantiate(Environment* env,
51
                                         AsyncWrap* parent,
52
0
                                         PipeWrap::SocketType type) {
53
0
  EscapableHandleScope handle_scope(env->isolate());
54
0
  AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent);
55
0
  CHECK_EQ(false, env->pipe_constructor_template().IsEmpty());
56
0
  Local<Function> constructor = env->pipe_constructor_template()
57
0
                                    ->GetFunction(env->context())
58
0
                                    .ToLocalChecked();
59
0
  CHECK_EQ(false, constructor.IsEmpty());
60
0
  Local<Value> type_value = Int32::New(env->isolate(), type);
61
0
  return handle_scope.EscapeMaybe(
62
0
      constructor->NewInstance(env->context(), 1, &type_value));
63
0
}
64
65
void PipeWrap::Initialize(Local<Object> target,
66
                          Local<Value> unused,
67
                          Local<Context> context,
68
82.9k
                          void* priv) {
69
82.9k
  Environment* env = Environment::GetCurrent(context);
70
82.9k
  Isolate* isolate = env->isolate();
71
72
82.9k
  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
73
82.9k
  t->InstanceTemplate()->SetInternalFieldCount(StreamBase::kInternalFieldCount);
74
75
82.9k
  t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));
76
77
82.9k
  SetProtoMethod(isolate, t, "bind", Bind);
78
82.9k
  SetProtoMethod(isolate, t, "listen", Listen);
79
82.9k
  SetProtoMethod(isolate, t, "connect", Connect);
80
82.9k
  SetProtoMethod(isolate, t, "open", Open);
81
82
#ifdef _WIN32
83
  SetProtoMethod(isolate, t, "setPendingInstances", SetPendingInstances);
84
#endif
85
86
82.9k
  SetProtoMethod(isolate, t, "fchmod", Fchmod);
87
88
82.9k
  SetConstructorFunction(context, target, "Pipe", t);
89
82.9k
  env->set_pipe_constructor_template(t);
90
91
  // Create FunctionTemplate for PipeConnectWrap.
92
82.9k
  auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env);
93
82.9k
  cwt->Inherit(AsyncWrap::GetConstructorTemplate(env));
94
82.9k
  SetConstructorFunction(context, target, "PipeConnectWrap", cwt);
95
96
  // Define constants
97
82.9k
  Local<Object> constants = Object::New(env->isolate());
98
82.9k
  NODE_DEFINE_CONSTANT(constants, SOCKET);
99
82.9k
  NODE_DEFINE_CONSTANT(constants, SERVER);
100
82.9k
  NODE_DEFINE_CONSTANT(constants, IPC);
101
82.9k
  NODE_DEFINE_CONSTANT(constants, UV_READABLE);
102
82.9k
  NODE_DEFINE_CONSTANT(constants, UV_WRITABLE);
103
82.9k
  target->Set(context, env->constants_string(), constants).Check();
104
82.9k
}
105
106
0
void PipeWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
107
0
  registry->Register(New);
108
0
  registry->Register(Bind);
109
0
  registry->Register(Listen);
110
0
  registry->Register(Connect);
111
0
  registry->Register(Open);
112
#ifdef _WIN32
113
  registry->Register(SetPendingInstances);
114
#endif
115
0
  registry->Register(Fchmod);
116
0
}
117
118
82.3k
void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
119
  // This constructor should not be exposed to public javascript.
120
  // Therefore we assert that we are not trying to call this as a
121
  // normal function.
122
82.3k
  CHECK(args.IsConstructCall());
123
82.3k
  CHECK(args[0]->IsInt32());
124
82.3k
  Environment* env = Environment::GetCurrent(args);
125
126
82.3k
  int type_value = args[0].As<Int32>()->Value();
127
82.3k
  PipeWrap::SocketType type = static_cast<PipeWrap::SocketType>(type_value);
128
129
82.3k
  bool ipc;
130
82.3k
  ProviderType provider;
131
82.3k
  switch (type) {
132
82.3k
    case SOCKET:
133
82.3k
      provider = PROVIDER_PIPEWRAP;
134
82.3k
      ipc = false;
135
82.3k
      break;
136
0
    case SERVER:
137
0
      provider = PROVIDER_PIPESERVERWRAP;
138
0
      ipc = false;
139
0
      break;
140
0
    case IPC:
141
0
      provider = PROVIDER_PIPEWRAP;
142
0
      ipc = true;
143
0
      break;
144
0
    default:
145
0
      UNREACHABLE();
146
82.3k
  }
147
148
82.3k
  new PipeWrap(env, args.This(), provider, ipc);
149
82.3k
}
150
151
PipeWrap::PipeWrap(Environment* env,
152
                   Local<Object> object,
153
                   ProviderType provider,
154
                   bool ipc)
155
82.3k
    : ConnectionWrap(env, object, provider) {
156
82.3k
  int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
157
82.3k
  CHECK_EQ(r, 0);  // How do we proxy this error up to javascript?
158
                   // Suggestion: uv_pipe_init() returns void.
159
82.3k
}
160
161
0
void PipeWrap::Bind(const FunctionCallbackInfo<Value>& args) {
162
0
  PipeWrap* wrap;
163
0
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
164
0
  node::Utf8Value name(args.GetIsolate(), args[0]);
165
0
  int err = uv_pipe_bind2(&wrap->handle_, *name, name.length(), 0);
166
0
  args.GetReturnValue().Set(err);
167
0
}
168
169
#ifdef _WIN32
170
void PipeWrap::SetPendingInstances(const FunctionCallbackInfo<Value>& args) {
171
  PipeWrap* wrap;
172
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
173
  CHECK(args[0]->IsInt32());
174
  int instances = args[0].As<Int32>()->Value();
175
  uv_pipe_pending_instances(&wrap->handle_, instances);
176
}
177
#endif
178
179
0
void PipeWrap::Fchmod(const v8::FunctionCallbackInfo<v8::Value>& args) {
180
0
  PipeWrap* wrap;
181
0
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
182
0
  CHECK(args[0]->IsInt32());
183
0
  int mode = args[0].As<Int32>()->Value();
184
0
  int err = uv_pipe_chmod(&wrap->handle_, mode);
185
0
  args.GetReturnValue().Set(err);
186
0
}
187
188
0
void PipeWrap::Listen(const FunctionCallbackInfo<Value>& args) {
189
0
  PipeWrap* wrap;
190
0
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
191
0
  Environment* env = wrap->env();
192
0
  int backlog;
193
0
  if (!args[0]->Int32Value(env->context()).To(&backlog)) return;
194
0
  int err = uv_listen(
195
0
      reinterpret_cast<uv_stream_t*>(&wrap->handle_), backlog, OnConnection);
196
0
  args.GetReturnValue().Set(err);
197
0
}
198
199
82.3k
void PipeWrap::Open(const FunctionCallbackInfo<Value>& args) {
200
82.3k
  Environment* env = Environment::GetCurrent(args);
201
202
82.3k
  PipeWrap* wrap;
203
82.3k
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
204
205
82.3k
  int fd;
206
82.3k
  if (!args[0]->Int32Value(env->context()).To(&fd)) return;
207
208
82.3k
  int err = uv_pipe_open(&wrap->handle_, fd);
209
82.3k
  if (err == 0) wrap->set_fd(fd);
210
211
82.3k
  args.GetReturnValue().Set(err);
212
82.3k
}
213
214
0
void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) {
215
0
  Environment* env = Environment::GetCurrent(args);
216
217
0
  PipeWrap* wrap;
218
0
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
219
220
0
  CHECK(args[0]->IsObject());
221
0
  CHECK(args[1]->IsString());
222
223
0
  Local<Object> req_wrap_obj = args[0].As<Object>();
224
0
  node::Utf8Value name(env->isolate(), args[1]);
225
226
0
  ConnectWrap* req_wrap =
227
0
      new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP);
228
0
  int err = req_wrap->Dispatch(
229
0
      uv_pipe_connect2, &wrap->handle_, *name, name.length(), 0, AfterConnect);
230
0
  if (err) {
231
0
    delete req_wrap;
232
0
  } else {
233
0
    const char* path_type = (*name)[0] == '\0' ? "abstract socket" : "file";
234
0
    const char* pipe_path = (*name)[0] == '\0' ? (*name) + 1 : *name;
235
0
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(TRACING_CATEGORY_NODE2(net, native),
236
0
                                      "connect",
237
0
                                      req_wrap,
238
0
                                      "path_type",
239
0
                                      path_type,
240
0
                                      "pipe_path",
241
0
                                      TRACE_STR_COPY(pipe_path));
242
0
  }
243
244
0
  args.GetReturnValue().Set(err);
245
0
}
246
247
}  // namespace node
248
249
NODE_BINDING_CONTEXT_AWARE_INTERNAL(pipe_wrap, node::PipeWrap::Initialize)
250
NODE_BINDING_EXTERNAL_REFERENCE(pipe_wrap,
251
                                node::PipeWrap::RegisterExternalReferences)