Skip to content

Commit 187fe27

Browse files
Igor Zinkovskybnoordhuis
Igor Zinkovsky
authored andcommitted
stdio binding + javascript to enable process.stdin.listen()
1 parent de26171 commit 187fe27

10 files changed

+202
-12
lines changed

lib/net_uv.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ exports.Socket = Socket;
7979
exports.Stream = Socket; // Legacy naming.
8080

8181

82+
Socket.prototype.listen = function() {
83+
var self = this;
84+
self.on('connection', arguments[0]);
85+
listen(self, null, null);
86+
};
87+
88+
8289
Socket.prototype.setTimeout = function(msecs, callback) {
8390
if (msecs > 0) {
8491
timers.enroll(this, msecs);
@@ -535,8 +542,11 @@ function toPort(x) { return (x = Number(x)) >= 0 ? x : false; }
535542
function listen(self, address, port, addressType) {
536543
var r = 0;
537544

538-
// assign handle in listen, and clean up if bind or listen fails
539-
self._handle = (port == -1 && addressType == -1) ? new Pipe : new TCP;
545+
if (!self._handle) {
546+
// assign handle in listen, and clean up if bind or listen fails
547+
self._handle = (port == -1 && addressType == -1) ? new Pipe : new TCP;
548+
}
549+
540550
self._handle.socket = self;
541551
self._handle.onconnection = onconnection;
542552

src/handle_wrap.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ Handle<Value> HandleWrap::Close(const Arguments& args) {
5050

5151
HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
5252
handle__ = h;
53-
h->data = this;
53+
if (h) {
54+
h->data = this;
55+
}
5456

5557
HandleScope scope;
5658
assert(object_.IsEmpty());
@@ -60,6 +62,12 @@ HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
6062
}
6163

6264

65+
void HandleWrap::SetHandle(uv_handle_t* h) {
66+
handle__ = h;
67+
h->data = this;
68+
}
69+
70+
6371
HandleWrap::~HandleWrap() {
6472
assert(object_.IsEmpty());
6573
}

src/handle_wrap.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class HandleWrap {
3232
HandleWrap(v8::Handle<v8::Object> object, uv_handle_t* handle);
3333
virtual ~HandleWrap();
3434

35+
virtual void SetHandle(uv_handle_t* h);
3536
virtual void StateChange() {}
3637

3738
v8::Persistent<v8::Object> object_;

src/node_extensions.h

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ NODE_EXT_LIST_ITEM(node_timer_wrap)
4646
NODE_EXT_LIST_ITEM(node_tcp_wrap)
4747
NODE_EXT_LIST_ITEM(node_pipe_wrap)
4848
NODE_EXT_LIST_ITEM(node_cares_wrap)
49+
NODE_EXT_LIST_ITEM(node_stdio_wrap)
4950

5051
NODE_EXT_LIST_END
5152

src/pipe_wrap.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ using v8::Context;
3030
using v8::Arguments;
3131
using v8::Integer;
3232

33-
static Persistent<Function> constructor;
33+
Persistent<Function> pipeConstructor;
3434

3535

3636
// TODO share with TCPWrap?
@@ -61,9 +61,9 @@ class PipeWrap : StreamWrap {
6161
NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
6262
NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect);
6363

64-
constructor = Persistent<Function>::New(t->GetFunction());
64+
pipeConstructor = Persistent<Function>::New(t->GetFunction());
6565

66-
target->Set(String::NewSymbol("Pipe"), constructor);
66+
target->Set(String::NewSymbol("Pipe"), pipeConstructor);
6767
}
6868

6969
private:
@@ -137,7 +137,7 @@ class PipeWrap : StreamWrap {
137137
}
138138

139139
// Instanciate the client javascript object and handle.
140-
Local<Object> client_obj = constructor->NewInstance();
140+
Local<Object> client_obj = pipeConstructor->NewInstance();
141141

142142
// Unwrap the client javascript object.
143143
assert(client_obj->InternalFieldCount() > 0);

src/stdio_wrap.cc

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#include <node.h>
2+
#include <node_buffer.h>
3+
#include <req_wrap.h>
4+
#include <handle_wrap.h>
5+
#include <stream_wrap.h>
6+
7+
#define UNWRAP \
8+
assert(!args.Holder().IsEmpty()); \
9+
assert(args.Holder()->InternalFieldCount() > 0); \
10+
StdIOWrap* wrap = \
11+
static_cast<StdIOWrap*>(args.Holder()->GetPointerFromInternalField(0)); \
12+
if (!wrap) { \
13+
SetErrno(UV_EBADF); \
14+
return scope.Close(Integer::New(-1)); \
15+
}
16+
17+
namespace node {
18+
19+
using v8::Object;
20+
using v8::Handle;
21+
using v8::Local;
22+
using v8::Persistent;
23+
using v8::Value;
24+
using v8::HandleScope;
25+
using v8::FunctionTemplate;
26+
using v8::String;
27+
using v8::Function;
28+
using v8::TryCatch;
29+
using v8::Context;
30+
using v8::Arguments;
31+
using v8::Integer;
32+
using v8::Undefined;
33+
34+
extern Persistent<Function> tcpConstructor;
35+
extern Persistent<Function> pipeConstructor;
36+
static Persistent<Function> constructor;
37+
38+
39+
class StdIOWrap : StreamWrap {
40+
public:
41+
static void Initialize(Handle<Object> target) {
42+
StreamWrap::Initialize(target);
43+
44+
HandleScope scope;
45+
46+
Local<FunctionTemplate> t = FunctionTemplate::New(New);
47+
t->SetClassName(String::NewSymbol("StdIO"));
48+
49+
t->InstanceTemplate()->SetInternalFieldCount(1);
50+
51+
NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
52+
NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
53+
NODE_SET_PROTOTYPE_METHOD(t, "write", StreamWrap::Write);
54+
NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
55+
56+
constructor = Persistent<Function>::New(t->GetFunction());
57+
58+
target->Set(String::NewSymbol("StdIO"), constructor);
59+
}
60+
61+
private:
62+
static Handle<Value> New(const Arguments& args) {
63+
// This constructor should not be exposed to public javascript.
64+
// Therefore we assert that we are not trying to call this as a
65+
// normal function.
66+
assert(args.IsConstructCall());
67+
68+
uv_std_type stdHandleType = (uv_std_type)args[0]->Int32Value();
69+
70+
assert(stdHandleType == UV_STDIN || stdHandleType == UV_STDOUT || stdHandleType == UV_STDERR);
71+
72+
uv_stream_t* stdHandle = uv_std_handle(stdHandleType);
73+
if (stdHandle) {
74+
HandleScope scope;
75+
StdIOWrap* wrap = new StdIOWrap(args.This());
76+
assert(wrap);
77+
78+
wrap->handle_ = stdHandle;
79+
wrap->SetHandle((uv_handle_t*)stdHandle);
80+
wrap->UpdateWriteQueueSize();
81+
82+
return scope.Close(args.This());
83+
} else {
84+
return Undefined();
85+
}
86+
}
87+
88+
StdIOWrap(Handle<Object> object) : StreamWrap(object, NULL) {
89+
}
90+
91+
static Handle<Value> Listen(const Arguments& args) {
92+
HandleScope scope;
93+
94+
UNWRAP
95+
96+
int backlog = args[0]->Int32Value();
97+
98+
int r = uv_listen(wrap->handle_, SOMAXCONN, OnConnection);
99+
100+
// Error starting the pipe.
101+
if (r) SetErrno(uv_last_error().code);
102+
103+
return scope.Close(Integer::New(r));
104+
}
105+
106+
// TODO maybe share with TCPWrap?
107+
static void OnConnection(uv_stream_t* handle, int status) {
108+
HandleScope scope;
109+
Local<Object> client_obj;
110+
111+
StdIOWrap* wrap = static_cast<StdIOWrap*>(handle->data);
112+
assert(wrap->handle_ == handle);
113+
114+
// We should not be getting this callback if someone as already called
115+
// uv_close() on the handle.
116+
assert(wrap->object_.IsEmpty() == false);
117+
118+
if (status != 0) {
119+
// TODO Handle server error (set errno and call onconnection with NULL)
120+
assert(0);
121+
return;
122+
}
123+
124+
// Instanciate the client javascript object and handle.
125+
switch (handle->type) {
126+
case UV_TCP:
127+
client_obj = tcpConstructor->NewInstance();
128+
break;
129+
case UV_NAMED_PIPE:
130+
client_obj = pipeConstructor->NewInstance();
131+
break;
132+
default:
133+
assert(0);
134+
return;
135+
}
136+
137+
// Unwrap the client javascript object.
138+
assert(client_obj->InternalFieldCount() > 0);
139+
StreamWrap* client_wrap =
140+
static_cast<StreamWrap*>(client_obj->GetPointerFromInternalField(0));
141+
142+
int r = uv_accept(handle, client_wrap->GetStream());
143+
144+
// uv_accept should always work.
145+
assert(r == 0);
146+
147+
// Successful accept. Call the onconnection callback in JavaScript land.
148+
Local<Value> argv[1] = { client_obj };
149+
MakeCallback(wrap->object_, "onconnection", 1, argv);
150+
}
151+
152+
uv_stream_t* handle_;
153+
};
154+
155+
} // namespace node
156+
157+
NODE_MODULE(node_stdio_wrap, node::StdIOWrap::Initialize);

src/stream_wrap.cc

+10-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,16 @@ void StreamWrap::Initialize(Handle<Object> target) {
7171
StreamWrap::StreamWrap(Handle<Object> object, uv_stream_t* stream)
7272
: HandleWrap(object, (uv_handle_t*)stream) {
7373
stream_ = stream;
74-
stream->data = this;
74+
if (stream) {
75+
stream->data = this;
76+
}
77+
}
78+
79+
80+
void StreamWrap::SetHandle(uv_handle_t* h) {
81+
HandleWrap::SetHandle(h);
82+
stream_ = (uv_stream_t*)h;
83+
stream_->data = this;
7584
}
7685

7786

src/stream_wrap.h

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace node {
99

1010
class StreamWrap : public HandleWrap {
1111
public:
12+
uv_stream_t* GetStream() { return stream_; }
13+
1214
static void Initialize(v8::Handle<v8::Object> target);
1315

1416
// JavaScript functions
@@ -20,6 +22,7 @@ class StreamWrap : public HandleWrap {
2022
protected:
2123
StreamWrap(v8::Handle<v8::Object> object, uv_stream_t* stream);
2224
virtual ~StreamWrap() { }
25+
virtual void SetHandle(uv_handle_t* h);
2326
void StateChange() { }
2427
void UpdateWriteQueueSize();
2528

src/tcp_wrap.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ using v8::Context;
4545
using v8::Arguments;
4646
using v8::Integer;
4747

48-
static Persistent<Function> constructor;
48+
Persistent<Function> tcpConstructor;
4949

5050
static Persistent<String> family_symbol;
5151
static Persistent<String> address_symbol;
@@ -83,13 +83,13 @@ class TCPWrap : public StreamWrap {
8383
NODE_SET_PROTOTYPE_METHOD(t, "connect6", Connect6);
8484
NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName);
8585

86-
constructor = Persistent<Function>::New(t->GetFunction());
86+
tcpConstructor = Persistent<Function>::New(t->GetFunction());
8787

8888
family_symbol = NODE_PSYMBOL("family");
8989
address_symbol = NODE_PSYMBOL("address");
9090
port_symbol = NODE_PSYMBOL("port");
9191

92-
target->Set(String::NewSymbol("TCP"), constructor);
92+
target->Set(String::NewSymbol("TCP"), tcpConstructor);
9393
}
9494

9595
private:
@@ -221,7 +221,7 @@ class TCPWrap : public StreamWrap {
221221
}
222222

223223
// Instanciate the client javascript object and handle.
224-
Local<Object> client_obj = constructor->NewInstance();
224+
Local<Object> client_obj = tcpConstructor->NewInstance();
225225

226226
// Unwrap the client javascript object.
227227
assert(client_obj->InternalFieldCount() > 0);

wscript

+1
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,7 @@ def build(bld):
867867
src/tcp_wrap.cc
868868
src/pipe_wrap.cc
869869
src/cares_wrap.cc
870+
src/stdio_wrap.cc
870871
"""
871872

872873
if sys.platform.startswith("win32"):

0 commit comments

Comments
 (0)