mirror of https://github.com/lukechilds/node.git
4 changed files with 165 additions and 0 deletions
@ -0,0 +1,142 @@ |
|||||
|
#include <v8.h> |
||||
|
#include <uv.h> |
||||
|
#include <node.h> |
||||
|
|
||||
|
// Rules:
|
||||
|
//
|
||||
|
// - Do not throw from handle methods. Set errno.
|
||||
|
//
|
||||
|
// - MakeCallback may only be made directly off the event loop.
|
||||
|
// That is there can be no JavaScript stack frames underneith it.
|
||||
|
// (Is there anyway to assert that?)
|
||||
|
//
|
||||
|
// - No use of v8::WeakReferenceCallback. The close callback signifies that
|
||||
|
// we're done with a handle - external resources can be freed.
|
||||
|
//
|
||||
|
// - Reusable?
|
||||
|
//
|
||||
|
// - The uv_close_cb is used to free the c++ object. The close callback
|
||||
|
// is not made into javascript land.
|
||||
|
//
|
||||
|
// - uv_ref, uv_unref counts are managed at this layer to avoid needless
|
||||
|
// js/c++ boundary crossing. At the javascript layer that should all be
|
||||
|
// taken care of.
|
||||
|
|
||||
|
|
||||
|
#define UNWRAP \ |
||||
|
assert(!args.Holder().IsEmpty()); \ |
||||
|
assert(args.Holder()->InternalFieldCount() > 0); \ |
||||
|
TCPWrap* wrap = \ |
||||
|
static_cast<TCPWrap*>(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; |
||||
|
|
||||
|
|
||||
|
class TCPWrap { |
||||
|
public: |
||||
|
static void Initialize(Handle<Object> target) { |
||||
|
HandleScope scope; |
||||
|
|
||||
|
Local<FunctionTemplate> constructor = FunctionTemplate::New(New); |
||||
|
constructor->InstanceTemplate()->SetInternalFieldCount(1); |
||||
|
constructor->SetClassName(String::NewSymbol("TCP")); |
||||
|
|
||||
|
NODE_SET_PROTOTYPE_METHOD(constructor, "bind", Bind); |
||||
|
NODE_SET_PROTOTYPE_METHOD(constructor, "close", Close); |
||||
|
|
||||
|
target->Set(String::NewSymbol("TCP"), constructor->GetFunction()); |
||||
|
} |
||||
|
|
||||
|
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()); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
TCPWrap *wrap = new TCPWrap(args.This()); |
||||
|
assert(wrap); |
||||
|
|
||||
|
return scope.Close(args.This()); |
||||
|
} |
||||
|
|
||||
|
TCPWrap(Handle<Object> object) { |
||||
|
int r = uv_tcp_init(&handle_); |
||||
|
handle_.data = this; |
||||
|
assert(r == 0); // How do we proxy this error up to javascript?
|
||||
|
// Suggestion: uv_tcp_init() returns void.
|
||||
|
assert(object_.IsEmpty()); |
||||
|
assert(object->InternalFieldCount() > 0); |
||||
|
object_ = v8::Persistent<v8::Object>::New(object); |
||||
|
object_->SetPointerInInternalField(0, this); |
||||
|
} |
||||
|
|
||||
|
~TCPWrap() { |
||||
|
assert(!object_.IsEmpty()); |
||||
|
object_->SetPointerInInternalField(0, NULL); |
||||
|
object_.Dispose(); |
||||
|
} |
||||
|
|
||||
|
// Free the C++ object on the close callback.
|
||||
|
static void OnClose(uv_handle_t* handle) { |
||||
|
TCPWrap* wrap = static_cast<TCPWrap*>(handle->data); |
||||
|
delete wrap; |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> Bind(const Arguments& args) { |
||||
|
HandleScope scope; |
||||
|
|
||||
|
UNWRAP |
||||
|
|
||||
|
String::AsciiValue ip_address(args[0]->ToString()); |
||||
|
int port = args[1]->Int32Value(); |
||||
|
|
||||
|
struct sockaddr_in address = uv_ip4_addr(*ip_address, port); |
||||
|
int r = uv_bind(&wrap->handle_, address); |
||||
|
|
||||
|
// Error starting the tcp.
|
||||
|
if (r) SetErrno(uv_last_error().code); |
||||
|
|
||||
|
return scope.Close(Integer::New(r)); |
||||
|
} |
||||
|
|
||||
|
// TODO: share me?
|
||||
|
static Handle<Value> Close(const Arguments& args) { |
||||
|
HandleScope scope; |
||||
|
|
||||
|
UNWRAP |
||||
|
|
||||
|
int r = uv_close((uv_handle_t*) &wrap->handle_, OnClose); |
||||
|
|
||||
|
if (r) SetErrno(uv_last_error().code); |
||||
|
|
||||
|
return scope.Close(Integer::New(r)); |
||||
|
} |
||||
|
|
||||
|
uv_tcp_t handle_; |
||||
|
Persistent<Object> object_; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
} // namespace node
|
||||
|
|
||||
|
NODE_MODULE(node_tcp_wrap, node::TCPWrap::Initialize); |
@ -0,0 +1,18 @@ |
|||||
|
var common = require('../common'); |
||||
|
var assert = require('assert'); |
||||
|
|
||||
|
var TCP = process.binding('tcp_wrap').TCP; |
||||
|
|
||||
|
var handle = new TCP(); |
||||
|
|
||||
|
// Cannot bind to port 80 because of access rights.
|
||||
|
var r = handle.bind("0.0.0.0", 80); |
||||
|
assert.equal(-1, r); |
||||
|
console.log(errno); |
||||
|
assert.equal(errno, "EACCESS"); |
||||
|
|
||||
|
// Should be able to bind to the common.PORT
|
||||
|
var r = handle.bind("0.0.0.0", common.PORT); |
||||
|
assert.equal(0, r); |
||||
|
|
||||
|
handle.close(); |
Loading…
Reference in new issue