diff options
Diffstat (limited to 'src/tcp_wrap.cc')
-rw-r--r-- | src/tcp_wrap.cc | 474 |
1 files changed, 241 insertions, 233 deletions
diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 9c0786c1a8..3ba5ef055c 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -3,6 +3,7 @@ #include <req_wrap.h> #include <handle_wrap.h> #include <stream_wrap.h> +#include <tcp_wrap.h> // Temporary hack: libuv should provide uv_inet_pton and uv_inet_ntop. #if defined(__MINGW32__) || defined(_MSC_VER) @@ -45,8 +46,7 @@ using v8::Context; using v8::Arguments; using v8::Integer; -Persistent<Function> tcpConstructor; - +static Persistent<Function> tcpConstructor; static Persistent<String> family_symbol; static Persistent<String> address_symbol; static Persistent<String> port_symbol; @@ -55,314 +55,322 @@ static Persistent<String> port_symbol; typedef class ReqWrap<uv_connect_t> ConnectWrap; -class TCPWrap : public StreamWrap { - public: +Local<Object> TCPWrap::Instantiate() { + HandleScope scope; + return scope.Close(tcpConstructor->NewInstance()); +} - static void Initialize(Handle<Object> target) { - HandleWrap::Initialize(target); - StreamWrap::Initialize(target); - HandleScope scope; +void TCPWrap::Initialize(Handle<Object> target) { + HandleWrap::Initialize(target); + StreamWrap::Initialize(target); - Local<FunctionTemplate> t = FunctionTemplate::New(New); - t->SetClassName(String::NewSymbol("TCP")); + HandleScope scope; - t->InstanceTemplate()->SetInternalFieldCount(1); + Local<FunctionTemplate> t = FunctionTemplate::New(New); + t->SetClassName(String::NewSymbol("TCP")); - NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); + 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, "shutdown", StreamWrap::Shutdown); + NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); - NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind); - NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen); - NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect); - NODE_SET_PROTOTYPE_METHOD(t, "bind6", Bind6); - NODE_SET_PROTOTYPE_METHOD(t, "connect6", Connect6); - NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName); - NODE_SET_PROTOTYPE_METHOD(t, "getpeername", GetPeerName); + 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, "shutdown", StreamWrap::Shutdown); - tcpConstructor = Persistent<Function>::New(t->GetFunction()); + NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind); + NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen); + NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect); + NODE_SET_PROTOTYPE_METHOD(t, "bind6", Bind6); + NODE_SET_PROTOTYPE_METHOD(t, "connect6", Connect6); + NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName); + NODE_SET_PROTOTYPE_METHOD(t, "getpeername", GetPeerName); - family_symbol = NODE_PSYMBOL("family"); - address_symbol = NODE_PSYMBOL("address"); - port_symbol = NODE_PSYMBOL("port"); + tcpConstructor = Persistent<Function>::New(t->GetFunction()); - target->Set(String::NewSymbol("TCP"), tcpConstructor); - } + family_symbol = NODE_PSYMBOL("family"); + address_symbol = NODE_PSYMBOL("address"); + port_symbol = NODE_PSYMBOL("port"); - 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()); + target->Set(String::NewSymbol("TCP"), tcpConstructor); +} - HandleScope scope; - TCPWrap* wrap = new TCPWrap(args.This()); - assert(wrap); - return scope.Close(args.This()); - } +Handle<Value> TCPWrap::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()); - TCPWrap(Handle<Object> object) : StreamWrap(object, - (uv_stream_t*) &handle_) { - int r = uv_tcp_init(uv_default_loop(), &handle_); - assert(r == 0); // How do we proxy this error up to javascript? - // Suggestion: uv_tcp_init() returns void. - UpdateWriteQueueSize(); - } + HandleScope scope; + TCPWrap* wrap = new TCPWrap(args.This()); + assert(wrap); - ~TCPWrap() { - assert(object_.IsEmpty()); - } + return scope.Close(args.This()); +} + + +TCPWrap::TCPWrap(Handle<Object> object) + : StreamWrap(object, (uv_stream_t*) &handle_) { + int r = uv_tcp_init(uv_default_loop(), &handle_); + assert(r == 0); // How do we proxy this error up to javascript? + // Suggestion: uv_tcp_init() returns void. + UpdateWriteQueueSize(); +} + + +TCPWrap::~TCPWrap() { + assert(object_.IsEmpty()); +} - static Handle<Value> GetSockName(const Arguments& args) { - HandleScope scope; - struct sockaddr_storage address; - int family; - int port; - char ip[INET6_ADDRSTRLEN]; - - UNWRAP - - int addrlen = sizeof(address); - int r = uv_tcp_getsockname(&wrap->handle_, - reinterpret_cast<sockaddr*>(&address), - &addrlen); - - Local<Object> sockname = Object::New(); - if (r != 0) { - SetErrno(uv_last_error(uv_default_loop()).code); - } else { - family = address.ss_family; - if (family == AF_INET) { - struct sockaddr_in* addrin = (struct sockaddr_in*)&address; - uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, INET6_ADDRSTRLEN); - port = ntohs(addrin->sin_port); - } else if (family == AF_INET6) { - struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)&address; - uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, INET6_ADDRSTRLEN); - port = ntohs(addrin6->sin6_port); - } - - sockname->Set(port_symbol, Integer::New(port)); - sockname->Set(family_symbol, Integer::New(family)); - sockname->Set(address_symbol, String::New(ip)); + +Handle<Value> TCPWrap::GetSockName(const Arguments& args) { + HandleScope scope; + struct sockaddr_storage address; + int family; + int port; + char ip[INET6_ADDRSTRLEN]; + + UNWRAP + + int addrlen = sizeof(address); + int r = uv_tcp_getsockname(&wrap->handle_, + reinterpret_cast<sockaddr*>(&address), + &addrlen); + + Local<Object> sockname = Object::New(); + if (r != 0) { + SetErrno(uv_last_error(uv_default_loop()).code); + } else { + family = address.ss_family; + if (family == AF_INET) { + struct sockaddr_in* addrin = (struct sockaddr_in*)&address; + uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, INET6_ADDRSTRLEN); + port = ntohs(addrin->sin_port); + } else if (family == AF_INET6) { + struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)&address; + uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, INET6_ADDRSTRLEN); + port = ntohs(addrin6->sin6_port); } - return scope.Close(sockname); + sockname->Set(port_symbol, Integer::New(port)); + sockname->Set(family_symbol, Integer::New(family)); + sockname->Set(address_symbol, String::New(ip)); } - - static Handle<Value> GetPeerName(const Arguments& args) { - HandleScope scope; - struct sockaddr_storage address; - int family; - int port; - char ip[INET6_ADDRSTRLEN]; - - UNWRAP - - int addrlen = sizeof(address); - int r = uv_tcp_getpeername(&wrap->handle_, - reinterpret_cast<sockaddr*>(&address), - &addrlen); - - Local<Object> sockname = Object::New(); - if (r != 0) { - SetErrno(uv_last_error(uv_default_loop()).code); - } else { - family = address.ss_family; - if (family == AF_INET) { - struct sockaddr_in* addrin = (struct sockaddr_in*)&address; - uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, INET6_ADDRSTRLEN); - port = ntohs(addrin->sin_port); - } else if (family == AF_INET6) { - struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)&address; - uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, INET6_ADDRSTRLEN); - port = ntohs(addrin6->sin6_port); - } - - sockname->Set(port_symbol, Integer::New(port)); - sockname->Set(family_symbol, Integer::New(family)); - sockname->Set(address_symbol, String::New(ip)); + return scope.Close(sockname); +} + + +Handle<Value> TCPWrap::GetPeerName(const Arguments& args) { + HandleScope scope; + struct sockaddr_storage address; + int family; + int port; + char ip[INET6_ADDRSTRLEN]; + + UNWRAP + + int addrlen = sizeof(address); + int r = uv_tcp_getpeername(&wrap->handle_, + reinterpret_cast<sockaddr*>(&address), + &addrlen); + + Local<Object> sockname = Object::New(); + if (r != 0) { + SetErrno(uv_last_error(uv_default_loop()).code); + } else { + family = address.ss_family; + if (family == AF_INET) { + struct sockaddr_in* addrin = (struct sockaddr_in*)&address; + uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, INET6_ADDRSTRLEN); + port = ntohs(addrin->sin_port); + } else if (family == AF_INET6) { + struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)&address; + uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, INET6_ADDRSTRLEN); + port = ntohs(addrin6->sin6_port); } - return scope.Close(sockname); + sockname->Set(port_symbol, Integer::New(port)); + sockname->Set(family_symbol, Integer::New(family)); + sockname->Set(address_symbol, String::New(ip)); } + return scope.Close(sockname); +} - static Handle<Value> Bind(const Arguments& args) { - HandleScope scope; - UNWRAP +Handle<Value> TCPWrap::Bind(const Arguments& args) { + HandleScope scope; - String::AsciiValue ip_address(args[0]->ToString()); - int port = args[1]->Int32Value(); + UNWRAP - struct sockaddr_in address = uv_ip4_addr(*ip_address, port); - int r = uv_tcp_bind(&wrap->handle_, address); + String::AsciiValue ip_address(args[0]->ToString()); + int port = args[1]->Int32Value(); - // Error starting the tcp. - if (r) SetErrno(uv_last_error(uv_default_loop()).code); + struct sockaddr_in address = uv_ip4_addr(*ip_address, port); + int r = uv_tcp_bind(&wrap->handle_, address); - return scope.Close(Integer::New(r)); - } + // Error starting the tcp. + if (r) SetErrno(uv_last_error(uv_default_loop()).code); - static Handle<Value> Bind6(const Arguments& args) { - HandleScope scope; + return scope.Close(Integer::New(r)); +} - UNWRAP - String::AsciiValue ip6_address(args[0]->ToString()); - int port = args[1]->Int32Value(); +Handle<Value> TCPWrap::Bind6(const Arguments& args) { + HandleScope scope; - struct sockaddr_in6 address = uv_ip6_addr(*ip6_address, port); - int r = uv_tcp_bind6(&wrap->handle_, address); + UNWRAP - // Error starting the tcp. - if (r) SetErrno(uv_last_error(uv_default_loop()).code); + String::AsciiValue ip6_address(args[0]->ToString()); + int port = args[1]->Int32Value(); - return scope.Close(Integer::New(r)); - } + struct sockaddr_in6 address = uv_ip6_addr(*ip6_address, port); + int r = uv_tcp_bind6(&wrap->handle_, address); - static Handle<Value> Listen(const Arguments& args) { - HandleScope scope; + // Error starting the tcp. + if (r) SetErrno(uv_last_error(uv_default_loop()).code); - UNWRAP + return scope.Close(Integer::New(r)); +} - int backlog = args[0]->Int32Value(); - int r = uv_listen((uv_stream_t*)&wrap->handle_, backlog, OnConnection); +Handle<Value> TCPWrap::Listen(const Arguments& args) { + HandleScope scope; - // Error starting the tcp. - if (r) SetErrno(uv_last_error(uv_default_loop()).code); + UNWRAP - return scope.Close(Integer::New(r)); - } + int backlog = args[0]->Int32Value(); - static void OnConnection(uv_stream_t* handle, int status) { - HandleScope scope; + int r = uv_listen((uv_stream_t*)&wrap->handle_, backlog, OnConnection); - TCPWrap* wrap = static_cast<TCPWrap*>(handle->data); - assert(&wrap->handle_ == (uv_tcp_t*)handle); + // Error starting the tcp. + if (r) SetErrno(uv_last_error(uv_default_loop()).code); - // We should not be getting this callback if someone as already called - // uv_close() on the handle. - assert(wrap->object_.IsEmpty() == false); + return scope.Close(Integer::New(r)); +} - Handle<Value> argv[1]; - if (status == 0) { - // Instantiate the client javascript object and handle. - Local<Object> client_obj = tcpConstructor->NewInstance(); +void TCPWrap::OnConnection(uv_stream_t* handle, int status) { + HandleScope scope; - // Unwrap the client javascript object. - assert(client_obj->InternalFieldCount() > 0); - TCPWrap* client_wrap = - static_cast<TCPWrap*>(client_obj->GetPointerFromInternalField(0)); + TCPWrap* wrap = static_cast<TCPWrap*>(handle->data); + assert(&wrap->handle_ == (uv_tcp_t*)handle); - int r = uv_accept(handle, (uv_stream_t*)&client_wrap->handle_); + // We should not be getting this callback if someone as already called + // uv_close() on the handle. + assert(wrap->object_.IsEmpty() == false); - // uv_accept should always work. - assert(r == 0); + Handle<Value> argv[1]; - // Successful accept. Call the onconnection callback in JavaScript land. - argv[0] = client_obj; - } else { - SetErrno(uv_last_error(uv_default_loop()).code); - argv[0] = v8::Null(); - } + if (status == 0) { + // Instantiate the client javascript object and handle. + Local<Object> client_obj = Instantiate(); - MakeCallback(wrap->object_, "onconnection", 1, argv); - } + // Unwrap the client javascript object. + assert(client_obj->InternalFieldCount() > 0); + TCPWrap* client_wrap = + static_cast<TCPWrap*>(client_obj->GetPointerFromInternalField(0)); - static void AfterConnect(uv_connect_t* req, int status) { - ConnectWrap* req_wrap = (ConnectWrap*) req->data; - TCPWrap* wrap = (TCPWrap*) req->handle->data; + int r = uv_accept(handle, (uv_stream_t*)&client_wrap->handle_); - HandleScope scope; + // uv_accept should always work. + assert(r == 0); - // The wrap and request objects should still be there. - assert(req_wrap->object_.IsEmpty() == false); - assert(wrap->object_.IsEmpty() == false); + // Successful accept. Call the onconnection callback in JavaScript land. + argv[0] = client_obj; + } else { + SetErrno(uv_last_error(uv_default_loop()).code); + argv[0] = v8::Null(); + } - if (status) { - SetErrno(uv_last_error(uv_default_loop()).code); - } + MakeCallback(wrap->object_, "onconnection", 1, argv); +} - Local<Value> argv[3] = { - Integer::New(status), - Local<Value>::New(wrap->object_), - Local<Value>::New(req_wrap->object_) - }; - MakeCallback(req_wrap->object_, "oncomplete", 3, argv); +void TCPWrap::AfterConnect(uv_connect_t* req, int status) { + ConnectWrap* req_wrap = (ConnectWrap*) req->data; + TCPWrap* wrap = (TCPWrap*) req->handle->data; - delete req_wrap; + HandleScope scope; + + // The wrap and request objects should still be there. + assert(req_wrap->object_.IsEmpty() == false); + assert(wrap->object_.IsEmpty() == false); + + if (status) { + SetErrno(uv_last_error(uv_default_loop()).code); } - static Handle<Value> Connect(const Arguments& args) { - HandleScope scope; + Local<Value> argv[3] = { + Integer::New(status), + Local<Value>::New(wrap->object_), + Local<Value>::New(req_wrap->object_) + }; - UNWRAP + MakeCallback(req_wrap->object_, "oncomplete", 3, argv); - String::AsciiValue ip_address(args[0]->ToString()); - int port = args[1]->Int32Value(); + delete req_wrap; +} - struct sockaddr_in address = uv_ip4_addr(*ip_address, port); - // I hate when people program C++ like it was C, and yet I do it too. - // I'm too lazy to come up with the perfect class hierarchy here. Let's - // just do some type munging. - ConnectWrap* req_wrap = new ConnectWrap(); - - int r = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, address, - AfterConnect); +Handle<Value> TCPWrap::Connect(const Arguments& args) { + HandleScope scope; - req_wrap->Dispatched(); + UNWRAP - if (r) { - SetErrno(uv_last_error(uv_default_loop()).code); - delete req_wrap; - return scope.Close(v8::Null()); - } else { - return scope.Close(req_wrap->object_); - } - } + String::AsciiValue ip_address(args[0]->ToString()); + int port = args[1]->Int32Value(); - static Handle<Value> Connect6(const Arguments& args) { - HandleScope scope; + struct sockaddr_in address = uv_ip4_addr(*ip_address, port); - UNWRAP + // I hate when people program C++ like it was C, and yet I do it too. + // I'm too lazy to come up with the perfect class hierarchy here. Let's + // just do some type munging. + ConnectWrap* req_wrap = new ConnectWrap(); + + int r = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, address, + AfterConnect); - String::AsciiValue ip_address(args[0]->ToString()); - int port = args[1]->Int32Value(); + req_wrap->Dispatched(); - struct sockaddr_in6 address = uv_ip6_addr(*ip_address, port); + if (r) { + SetErrno(uv_last_error(uv_default_loop()).code); + delete req_wrap; + return scope.Close(v8::Null()); + } else { + return scope.Close(req_wrap->object_); + } +} - ConnectWrap* req_wrap = new ConnectWrap(); - int r = uv_tcp_connect6(&req_wrap->req_, &wrap->handle_, address, - AfterConnect); +Handle<Value> TCPWrap::Connect6(const Arguments& args) { + HandleScope scope; - req_wrap->Dispatched(); + UNWRAP - if (r) { - SetErrno(uv_last_error(uv_default_loop()).code); - delete req_wrap; - return scope.Close(v8::Null()); - } else { - return scope.Close(req_wrap->object_); - } - } + String::AsciiValue ip_address(args[0]->ToString()); + int port = args[1]->Int32Value(); + + struct sockaddr_in6 address = uv_ip6_addr(*ip_address, port); + ConnectWrap* req_wrap = new ConnectWrap(); - uv_tcp_t handle_; -}; + int r = uv_tcp_connect6(&req_wrap->req_, &wrap->handle_, address, + AfterConnect); + + req_wrap->Dispatched(); + + if (r) { + SetErrno(uv_last_error(uv_default_loop()).code); + delete req_wrap; + return scope.Close(v8::Null()); + } else { + return scope.Close(req_wrap->object_); + } +} } // namespace node |