mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.1 KiB
158 lines
4.1 KiB
14 years ago
|
#include <node.h>
|
||
|
#include <node_buffer.h>
|
||
|
#include <req_wrap.h>
|
||
|
#include <handle_wrap.h>
|
||
|
#include <stream_wrap.h>
|
||
|
|
||
|
#define UNWRAP \
|
||
|
assert(!args.Holder().IsEmpty()); \
|
||
|
assert(args.Holder()->InternalFieldCount() > 0); \
|
||
|
StdIOWrap* wrap = \
|
||
|
static_cast<StdIOWrap*>(args.Holder()->GetPointerFromInternalField(0)); \
|
||
|
if (!wrap) { \
|
||
|
SetErrno(UV_EBADF); \
|
||
|
return scope.Close(Integer::New(-1)); \
|
||
|
}
|
||
|
|
||
|
namespace node {
|
||
|
|
||
|
using v8::Object;
|
||
|
using v8::Handle;
|
||
|
using v8::Local;
|
||
|
using v8::Persistent;
|
||
|
using v8::Value;
|
||
|
using v8::HandleScope;
|
||
|
using v8::FunctionTemplate;
|
||
|
using v8::String;
|
||
|
using v8::Function;
|
||
|
using v8::TryCatch;
|
||
|
using v8::Context;
|
||
|
using v8::Arguments;
|
||
|
using v8::Integer;
|
||
|
using v8::Undefined;
|
||
|
|
||
|
extern Persistent<Function> tcpConstructor;
|
||
|
extern Persistent<Function> pipeConstructor;
|
||
|
static Persistent<Function> constructor;
|
||
|
|
||
|
|
||
|
class StdIOWrap : StreamWrap {
|
||
|
public:
|
||
|
static void Initialize(Handle<Object> target) {
|
||
|
StreamWrap::Initialize(target);
|
||
|
|
||
|
HandleScope scope;
|
||
|
|
||
|
Local<FunctionTemplate> t = FunctionTemplate::New(New);
|
||
|
t->SetClassName(String::NewSymbol("StdIO"));
|
||
|
|
||
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||
|
|
||
|
NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
|
||
|
NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
|
||
|
NODE_SET_PROTOTYPE_METHOD(t, "write", StreamWrap::Write);
|
||
|
NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
|
||
|
|
||
|
constructor = Persistent<Function>::New(t->GetFunction());
|
||
|
|
||
|
target->Set(String::NewSymbol("StdIO"), constructor);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
static Handle<Value> New(const Arguments& args) {
|
||
|
// This constructor should not be exposed to public javascript.
|
||
|
// Therefore we assert that we are not trying to call this as a
|
||
|
// normal function.
|
||
|
assert(args.IsConstructCall());
|
||
|
|
||
|
uv_std_type stdHandleType = (uv_std_type)args[0]->Int32Value();
|
||
|
|
||
|
assert(stdHandleType == UV_STDIN || stdHandleType == UV_STDOUT || stdHandleType == UV_STDERR);
|
||
|
|
||
|
uv_stream_t* stdHandle = uv_std_handle(stdHandleType);
|
||
|
if (stdHandle) {
|
||
|
HandleScope scope;
|
||
|
StdIOWrap* wrap = new StdIOWrap(args.This());
|
||
|
assert(wrap);
|
||
|
|
||
|
wrap->handle_ = stdHandle;
|
||
|
wrap->SetHandle((uv_handle_t*)stdHandle);
|
||
|
wrap->UpdateWriteQueueSize();
|
||
|
|
||
|
return scope.Close(args.This());
|
||
|
} else {
|
||
|
return Undefined();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StdIOWrap(Handle<Object> object) : StreamWrap(object, NULL) {
|
||
|
}
|
||
|
|
||
|
static Handle<Value> Listen(const Arguments& args) {
|
||
|
HandleScope scope;
|
||
|
|
||
|
UNWRAP
|
||
|
|
||
|
int backlog = args[0]->Int32Value();
|
||
|
|
||
|
int r = uv_listen(wrap->handle_, SOMAXCONN, OnConnection);
|
||
|
|
||
|
// Error starting the pipe.
|
||
|
if (r) SetErrno(uv_last_error().code);
|
||
|
|
||
|
return scope.Close(Integer::New(r));
|
||
|
}
|
||
|
|
||
|
// TODO maybe share with TCPWrap?
|
||
|
static void OnConnection(uv_stream_t* handle, int status) {
|
||
|
HandleScope scope;
|
||
|
Local<Object> client_obj;
|
||
|
|
||
|
StdIOWrap* wrap = static_cast<StdIOWrap*>(handle->data);
|
||
|
assert(wrap->handle_ == handle);
|
||
|
|
||
|
// We should not be getting this callback if someone as already called
|
||
|
// uv_close() on the handle.
|
||
|
assert(wrap->object_.IsEmpty() == false);
|
||
|
|
||
|
if (status != 0) {
|
||
|
// TODO Handle server error (set errno and call onconnection with NULL)
|
||
|
assert(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Instanciate the client javascript object and handle.
|
||
|
switch (handle->type) {
|
||
|
case UV_TCP:
|
||
|
client_obj = tcpConstructor->NewInstance();
|
||
|
break;
|
||
|
case UV_NAMED_PIPE:
|
||
|
client_obj = pipeConstructor->NewInstance();
|
||
|
break;
|
||
|
default:
|
||
|
assert(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Unwrap the client javascript object.
|
||
|
assert(client_obj->InternalFieldCount() > 0);
|
||
|
StreamWrap* client_wrap =
|
||
|
static_cast<StreamWrap*>(client_obj->GetPointerFromInternalField(0));
|
||
|
|
||
|
int r = uv_accept(handle, client_wrap->GetStream());
|
||
|
|
||
|
// uv_accept should always work.
|
||
|
assert(r == 0);
|
||
|
|
||
|
// Successful accept. Call the onconnection callback in JavaScript land.
|
||
|
Local<Value> argv[1] = { client_obj };
|
||
|
MakeCallback(wrap->object_, "onconnection", 1, argv);
|
||
|
}
|
||
|
|
||
|
uv_stream_t* handle_;
|
||
|
};
|
||
|
|
||
|
} // namespace node
|
||
|
|
||
|
NODE_MODULE(node_stdio_wrap, node::StdIOWrap::Initialize);
|