diff --git a/src/net.cc b/src/net.cc index b381ed99c7..28a24c4aa6 100644 --- a/src/net.cc +++ b/src/net.cc @@ -12,83 +12,49 @@ using namespace v8; -static Persistent readyState_str; - -static Persistent readyStateCONNECTING; -static Persistent readyStateOPEN; -static Persistent readyStateCLOSED; +static struct addrinfo tcp_hints = +/* ai_flags */ { AI_PASSIVE +/* ai_family */ , AF_UNSPEC +/* ai_socktype */ , SOCK_STREAM +/* ai_protocol */ , 0 +/* ai_addrlen */ , 0 +/* ai_addr */ , 0 +/* ai_canonname */ , 0 +/* ai_next */ , 0 + }; -enum encoding {UTF8, RAW}; class Socket { public: Socket (Handle obj, double timeout); ~Socket (); - int ConnectTCP (char *port, char *host); - void Write (Handle arg); - void Disconnect (); - void SetEncoding (enum encoding); void SetTimeout (double); - void OnConnect (); - void OnRead (const void *buf, size_t count); - void OnDrain (); - void OnError (oi_error e); - void OnClose (); + static Handle New (const Arguments& args); + static Handle Write (const Arguments& args); + static Handle Close (const Arguments& args); + static Handle ConnectTCP (const Arguments& args); + + static void OnConnect (oi_socket *socket); + static void OnRead (oi_socket *s, const void *buf, size_t count); + static void OnDrain (oi_socket *s); + static void OnError (oi_socket *s, oi_error e); + static void OnClose (oi_socket *s); + static void OnTimeout (oi_socket *s); private: + static Socket* Unwrap (Handle handle); + static void MakeWeak (Persistent _, void *data); + enum {UTF8, RAW} encoding_; oi_socket socket_; struct addrinfo *address_; - Persistent js_object_; + Persistent handle_; }; -static void -on_connect (oi_socket *socket) -{ - Socket *s = static_cast (socket->data); - s->OnConnect(); -} - -static void -on_read (oi_socket *socket, const void *buf, size_t count) -{ - Socket *s = static_cast (socket->data); - s->OnRead(buf, count); -} - -static void -on_drain (oi_socket *socket) -{ - Socket *s = static_cast (socket->data); - s->OnDrain(); -} - -static void -on_error (oi_socket *socket, oi_error e) -{ - Socket *s = static_cast (socket->data); - s->OnError(e); -} - -static void -on_timeout (oi_socket *socket) -{ - Socket *s = static_cast (socket->data); - s->OnTimeout(e); -} - -static void -on_close (oi_socket *socket) -{ - Socket *s = static_cast (socket->data); - s->OnClose(); -} - - -static Handle -NewSocket (const Arguments& args) +Handle +Socket::New(const Arguments& args) { if (args.Length() > 1) return Undefined(); @@ -97,7 +63,7 @@ NewSocket (const Arguments& args) // Default options double timeout = 60.0; // in seconds - enum {RAW, UTF8} encoding = RAW; + enum {UTF8, RAW} encoding ; // Set options from argument. if (args.Length() == 1 && args[0]->IsObject()) { @@ -120,30 +86,30 @@ NewSocket (const Arguments& args) } } - Socket *s = new Socket(args.This(), timeout); + Socket *s = new Socket(args.Holder(), timeout); if(s == NULL) return Undefined(); // XXX raise error? return args.This(); } -static Socket* -Unwrapsocket (Handle obj) +Socket* +Socket::Unwrap (Handle handle) { HandleScope scope; - Handle field = Handle::Cast(obj->GetInternalField(0)); + Handle field = Handle::Cast(handle->GetInternalField(0)); Socket* socket = static_cast(field->Value()); return socket; } -static Handle -SocketConnectTCPCallback (const Arguments& args) +Handle +Socket::ConnectTCP (const Arguments& args) { if (args.Length() < 1) return Undefined(); HandleScope scope; - Socket *socket = Unwrapsocket(args.Holder()); + Socket *socket = Socket::Unwrap(args.Holder()); String::AsciiValue port(args[0]); @@ -153,171 +119,137 @@ SocketConnectTCPCallback (const Arguments& args) host = *host_v; } - int r = socket->ConnectTCP(*port, host); + int r; + + /* FIXME Blocking DNS resolution. */ + printf("resolving host: %s, port: %s\n", host, *port); + r = getaddrinfo (host, *port, &tcp_hints, &socket->address_); + if(r != 0) { + perror("getaddrinfo"); + return Undefined(); + } + + r = oi_socket_connect (&socket->socket_, socket->address_); + if(r != 0) { + perror("oi_socket_connect"); + return Undefined(); + } + oi_socket_attach (&socket->socket_, node_loop()); + + freeaddrinfo(socket->address_); + socket->address_ = NULL; // TODO raise error if r != 0 return Undefined(); } -static Handle -SocketWriteCallback (const Arguments& args) +Handle +Socket::Close (const Arguments& args) { HandleScope scope; - Socket *socket = Unwrapsocket(args.Holder()); - socket->Write(args[0]); + Socket *socket = Socket::Unwrap(args.Holder()); + oi_socket_close(&socket->socket_); return Undefined(); } -static Handle -SocketCloseCallback (const Arguments& args) -{ - HandleScope scope; - Socket *socket = Unwrapsocket(args.Holder()); - socket->Disconnect(); - return Undefined(); -} - -static void -DestroySocket (Persistent _, void *data) +void +Socket::MakeWeak (Persistent _, void *data) { Socket *s = static_cast (data); delete s; } -Socket::Socket(Handle js_object, double timeout) +Socket::Socket(Handle handle, double timeout) { oi_socket_init(&socket_, timeout); - socket_.on_connect = on_connect; - socket_.on_read = on_read; - socket_.on_drain = on_drain; - socket_.on_error = on_error; - socket_.on_close = on_close; - socket_.on_timeout = on_timeout; + socket_.on_connect = Socket::OnConnect; + socket_.on_read = Socket::OnRead; + socket_.on_drain = Socket::OnDrain; + socket_.on_error = Socket::OnError; + socket_.on_close = Socket::OnClose; + socket_.on_timeout = Socket::OnTimeout; socket_.data = this; HandleScope scope; - js_object_ = Persistent::New(js_object); - js_object_->SetInternalField (0, External::New(this)); - js_object_.MakeWeak (this, DestroySocket); + handle_ = Persistent::New(handle); + handle_->SetInternalField (0, External::New(this)); + handle_.MakeWeak (this, Socket::MakeWeak); + + encoding_ = UTF8; } Socket::~Socket () { - Disconnect(); + oi_socket_close(&socket_); oi_socket_detach(&socket_); - js_object_.Dispose(); - js_object_.Clear(); // necessary? + handle_.Dispose(); + handle_.Clear(); // necessary? } -static struct addrinfo tcp_hints = -/* ai_flags */ { AI_PASSIVE -/* ai_family */ , AF_UNSPEC -/* ai_socktype */ , SOCK_STREAM -/* ai_protocol */ , 0 -/* ai_addrlen */ , 0 -/* ai_addr */ , 0 -/* ai_canonname */ , 0 -/* ai_next */ , 0 - }; - -int -Socket::ConnectTCP(char *port, char *host) +Handle +Socket::Write (const Arguments& args) { - int r; - HandleScope scope; - js_object_->Set(readyState_str, readyStateCONNECTING); - - /* FIXME Blocking DNS resolution. */ - printf("resolving host: %s, port: %s\n", host, port); - r = getaddrinfo (host, port, &tcp_hints, &address); - if(r != 0) { - perror("getaddrinfo"); - return r; - } - - r = oi_socket_connect (&socket, address); - if(r != 0) { - perror("oi_socket_connect"); - return r; - } - oi_socket_attach (&socket, node_loop()); - - freeaddrinfo(address); - address = NULL; -} - -void Socket::Write (Handle arg) -{ - HandleScope scope; + Socket *socket = Socket::Unwrap(args.Holder()); - if (arg == Null()) { - - oi_socket_write_eof(&socket); + if (args[0] == Null()) { + oi_socket_write_eof(&socket->socket_); - } else if (arg->IsString()) { - Local s = arg->ToString(); - - size_t l1 = s->Utf8Length(), l2; - oi_buf *buf = oi_buf_new2(l1); - l2 = s->WriteUtf8(buf->base, l1); - assert(l1 == l2); - - oi_socket_write(&socket, buf); + } else if (args[0]->IsString()) { + // utf8 encoding + Local s = args[0]->ToString(); + size_t length = s->Utf8Length(); + oi_buf *buf = oi_buf_new2(length); + s->WriteUtf8(buf->base, length); + oi_socket_write(&socket->socket_, buf); - } else if (arg->IsArray()) { + } else if (args[0]->IsArray()) { + // raw encoding + Handle array = Handle::Cast(args[0]); size_t length = array->Length(); - Handle array = Handle::Cast(arg); oi_buf *buf = oi_buf_new2(length); for (int i = 0; i < length; i++) { Local int_value = array->Get(Integer::New(i)); - buf[i] = int_value->Int32Value(); + buf->base[i] = int_value->Int32Value(); } - - oi_socket_write(&socket, buf); + oi_socket_write(&socket->socket_, buf); } else { // raise error bad argument. assert(0); } -} - -void -Socket::Disconnect() -{ - oi_socket_close(&socket); + + return Undefined(); } void -Socket::OnConnect() +Socket::OnConnect (oi_socket *s) { - HandleScope scope; + Socket *socket = static_cast (s->data); - assert(READY_STATE_CONNECTING == ReadyState()); - js_object_->Set(readyState_str, readyStateOPEN); + HandleScope scope; - Handle on_connect_value = js_object_->Get( String::NewSymbol("on_connect") ); + Handle on_connect_value = socket->handle_->Get( String::NewSymbol("onConnect") ); if (!on_connect_value->IsFunction()) return; Handle on_connect = Handle::Cast(on_connect_value); TryCatch try_catch; - Handle r = on_connect->Call(js_object_, 0, NULL); + Handle r = on_connect->Call(socket->handle_, 0, NULL); if(try_catch.HasCaught()) node_fatal_exception(try_catch); } void -Socket::OnRead (const void *buf, size_t count) +Socket::OnRead (oi_socket *s, const void *buf, size_t count) { + Socket *socket = static_cast (s->data); HandleScope scope; - assert(READY_STATE_OPEN == ReadyState()); - - Handle onread_value = js_object_->Get( String::NewSymbol("on_read") ); + Handle onread_value = socket->handle_->Get( String::NewSymbol("onRead") ); if (!onread_value->IsFunction()) return; Handle onread = Handle::Cast(onread_value); @@ -325,101 +257,118 @@ Socket::OnRead (const void *buf, size_t count) Handle argv[argc]; if(count) { - Handle chunk = String::New((const char*)buf, count); // TODO binary data? - argv[0] = chunk; + if(socket->encoding_ == UTF8) { + // utf8 encoding + Handle chunk = String::New((const char*)buf, count); + argv[0] = chunk; + } else { + // raw encoding + Local array = Array::New(count); + for (int i = 0; i < count; i++) { + int val = static_cast(buf)[i]; + array->Set(Integer::New(i), Integer::New(val)); + } + argv[0] = array; + } } else { - // TODO eof? delete write method? - argv[0] = Null(); + argv[0] = Local::New(Null()); } TryCatch try_catch; - Handle r = onread->Call(js_object_, argc, argv); + Handle r = onread->Call(socket->handle_, argc, argv); + + if(try_catch.HasCaught()) + node_fatal_exception(try_catch); +} + +void +Socket::OnClose (oi_socket *s) +{ + Socket *socket = static_cast (s->data); + HandleScope scope; + + Handle onclose_value = socket->handle_->Get( String::NewSymbol("onClose") ); + if (!onclose_value->IsFunction()) return; + Handle onclose = Handle::Cast(onclose_value); + + TryCatch try_catch; + + Handle r = onclose->Call(socket->handle_, 0, NULL); + + if(try_catch.HasCaught()) + node_fatal_exception(try_catch); +} + +void +Socket::OnDrain (oi_socket *s) +{ + Socket *socket = static_cast (s->data); + HandleScope scope; + + Handle onclose_value = socket->handle_->Get( String::NewSymbol("onDrain") ); + if (!onclose_value->IsFunction()) return; + Handle onclose = Handle::Cast(onclose_value); + + TryCatch try_catch; + + Handle r = onclose->Call(socket->handle_, 0, NULL); if(try_catch.HasCaught()) node_fatal_exception(try_catch); } + void -Socket::OnClose () +Socket::OnError (oi_socket *s, oi_error e) { + Socket *socket = static_cast (s->data); HandleScope scope; - printf("onclose readyState %d\n", ReadyState()); + Handle onclose_value = socket->handle_->Get( String::NewSymbol("onError") ); + if (!onclose_value->IsFunction()) return; + Handle onclose = Handle::Cast(onclose_value); + + TryCatch try_catch; - assert(READY_STATE_OPEN == ReadyState()); - js_object_->Set(readyState_str, readyStateCLOSED); + Handle r = onclose->Call(socket->handle_, 0, NULL); + + if(try_catch.HasCaught()) + node_fatal_exception(try_catch); +} - Handle onclose_value = js_object_->Get( String::NewSymbol("on_close") ); +void +Socket::OnTimeout (oi_socket *s) +{ + Socket *socket = static_cast (s->data); + HandleScope scope; + + Handle onclose_value = socket->handle_->Get( String::NewSymbol("onTimeout") ); if (!onclose_value->IsFunction()) return; Handle onclose = Handle::Cast(onclose_value); TryCatch try_catch; - Handle r = onclose->Call(js_object_, 0, NULL); + Handle r = onclose->Call(socket->handle_, 0, NULL); if(try_catch.HasCaught()) node_fatal_exception(try_catch); } + void NodeInit_net (Handle target) { HandleScope scope; - // - // Socket - // - Local socket_template = FunctionTemplate::New(NewSocket); - target->Set(String::NewSymbol("Socket"), socket_template->GetFunction()); + Local socket_template = FunctionTemplate::New(Socket::New); socket_template->InstanceTemplate()->SetInternalFieldCount(1); + target->Set(String::NewSymbol("Socket"), socket_template->GetFunction()); + + NODE_SET_METHOD(socket_template->InstanceTemplate(), "connectTCP", Socket::ConnectTCP); + //NODE_SET_METHOD(socket_template->InstanceTemplate(), "connectUNIX", Socket::ConnectUNIX); + NODE_SET_METHOD(socket_template->InstanceTemplate(), "write", Socket::Write); + NODE_SET_METHOD(socket_template->InstanceTemplate(), "close", Socket::Close); - // socket.connectTCP() - Local socket_connect_tcp = - FunctionTemplate::New(SocketConnectTCPCallback); - socket_template->InstanceTemplate()->Set(String::NewSymbol("connectTCP"), - socket_connect_tcp->GetFunction()); - - // socket.connectUNIX() - Local socket_connect_unix = - FunctionTemplate::New(SocketConnectUNIXCallback); - socket_template->InstanceTemplate()->Set(String::NewSymbol("connectUNIX"), - socket_connect_unix->GetFunction()); - - // socket.write() - Local socket_write = - FunctionTemplate::New(SocketWriteCallback); - socket_template->InstanceTemplate()->Set(String::NewSymbol("write"), - socket_write->GetFunction()); - - // socket.close() - Local socket_close = - FunctionTemplate::New(SocketCloseCallback); - socket_template->InstanceTemplate()->Set(String::NewSymbol("close"), - socket_close->GetFunction()); - - // - // Server - // - Local server_template = FunctionTemplate::New(NewServer); - target->Set(String::NewSymbol("Server"), server_template->GetFunction()); - server_template->InstanceTemplate()->SetInternalFieldCount(1); - - // server.listenTCP() - Local server_listenTCP = - FunctionTemplate::New(ServerListenTCPCallback); - server_template->InstanceTemplate()->Set(String::NewSymbol("listenTCP"), - server_listenTCP->GetFunction()); - - // server.listenUNIX() - Local server_listenUNIX = - FunctionTemplate::New(ServerListenUNIXCallback); - server_template->InstanceTemplate()->Set(String::NewSymbol("listenUNIX"), - server_listenTCP->GetFunction()); - - // server.close() - Local server_close = FunctionTemplate::New(ServerCloseCallback); - server_template->InstanceTemplate()->Set(String::NewSymbol("close"), - server_close->GetFunction()); } diff --git a/src/node.cc b/src/node.cc index e6c296dc19..1b73a34adf 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1,6 +1,6 @@ #include "node.h" -//#include "net.h" +#include "net.h" #include "file.h" #include "process.h" #include "http.h" @@ -116,7 +116,7 @@ static void OnFatalError (const char* location, const char* message) { fprintf(stderr, "Fatal error: %s %s\n", location, message); - ev_unloop(node_loop(), EVUNLOOP_ALL); + exit(1); } @@ -205,7 +205,7 @@ main (int argc, char *argv[]) g->Set(String::New("ARGV"), arguments); // BUILT-IN MODULES - //NodeInit_net(g); + NodeInit_net(g); NodeInit_timers(g); NodeInit_process(g); NodeInit_file(g); diff --git a/wscript b/wscript index 0ca952227c..dc33171178 100644 --- a/wscript +++ b/wscript @@ -128,6 +128,7 @@ def build(bld): node.source = """ src/node.cc src/http.cc + src/net.cc src/process.cc src/file.cc src/timers.cc