0
0
mirror of https://github.com/nodejs/node.git synced 2024-11-29 07:00:59 +01:00

begin clean up of Socket

This commit is contained in:
Ryan 2009-04-21 19:56:30 +02:00
parent d105d88625
commit 707f244291
3 changed files with 188 additions and 238 deletions

View File

@ -12,83 +12,49 @@
using namespace v8;
static Persistent<String> readyState_str;
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
};
static Persistent<Integer> readyStateCONNECTING;
static Persistent<Integer> readyStateOPEN;
static Persistent<Integer> readyStateCLOSED;
enum encoding {UTF8, RAW};
class Socket {
public:
Socket (Handle<Object> obj, double timeout);
~Socket ();
int ConnectTCP (char *port, char *host);
void Write (Handle<Value> 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<Value> New (const Arguments& args);
static Handle<Value> Write (const Arguments& args);
static Handle<Value> Close (const Arguments& args);
static Handle<Value> 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<Object> handle);
static void MakeWeak (Persistent<Value> _, void *data);
enum {UTF8, RAW} encoding_;
oi_socket socket_;
struct addrinfo *address_;
Persistent<Object> js_object_;
Persistent<Object> handle_;
};
static void
on_connect (oi_socket *socket)
{
Socket *s = static_cast<Socket*> (socket->data);
s->OnConnect();
}
static void
on_read (oi_socket *socket, const void *buf, size_t count)
{
Socket *s = static_cast<Socket*> (socket->data);
s->OnRead(buf, count);
}
static void
on_drain (oi_socket *socket)
{
Socket *s = static_cast<Socket*> (socket->data);
s->OnDrain();
}
static void
on_error (oi_socket *socket, oi_error e)
{
Socket *s = static_cast<Socket*> (socket->data);
s->OnError(e);
}
static void
on_timeout (oi_socket *socket)
{
Socket *s = static_cast<Socket*> (socket->data);
s->OnTimeout(e);
}
static void
on_close (oi_socket *socket)
{
Socket *s = static_cast<Socket*> (socket->data);
s->OnClose();
}
static Handle<Value>
NewSocket (const Arguments& args)
Handle<Value>
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<Object> obj)
Socket*
Socket::Unwrap (Handle<Object> handle)
{
HandleScope scope;
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
Handle<External> field = Handle<External>::Cast(handle->GetInternalField(0));
Socket* socket = static_cast<Socket*>(field->Value());
return socket;
}
static Handle<Value>
SocketConnectTCPCallback (const Arguments& args)
Handle<Value>
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<Value>
SocketWriteCallback (const Arguments& args)
Handle<Value>
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<Value>
SocketCloseCallback (const Arguments& args)
{
HandleScope scope;
Socket *socket = Unwrapsocket(args.Holder());
socket->Disconnect();
return Undefined();
}
static void
DestroySocket (Persistent<Value> _, void *data)
void
Socket::MakeWeak (Persistent<Value> _, void *data)
{
Socket *s = static_cast<Socket*> (data);
delete s;
}
Socket::Socket(Handle<Object> js_object, double timeout)
Socket::Socket(Handle<Object> 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<Object>::New(js_object);
js_object_->SetInternalField (0, External::New(this));
js_object_.MakeWeak (this, DestroySocket);
handle_ = Persistent<Object>::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)
{
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<Value> arg)
Handle<Value>
Socket::Write (const Arguments& args)
{
HandleScope scope;
Socket *socket = Socket::Unwrap(args.Holder());
if (arg == Null()) {
if (args[0] == Null()) {
oi_socket_write_eof(&socket->socket_);
oi_socket_write_eof(&socket);
} else if (args[0]->IsString()) {
// utf8 encoding
Local<String> 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->IsString()) {
Local<String> 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 (arg->IsArray()) {
} else if (args[0]->IsArray()) {
// raw encoding
Handle<Array> array = Handle<Array>::Cast(args[0]);
size_t length = array->Length();
Handle<Array> array = Handle<Array>::Cast(arg);
oi_buf *buf = oi_buf_new2(length);
for (int i = 0; i < length; i++) {
Local<Value> 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)
{
Socket *socket = static_cast<Socket*> (s->data);
HandleScope scope;
assert(READY_STATE_CONNECTING == ReadyState());
js_object_->Set(readyState_str, readyStateOPEN);
Handle<Value> on_connect_value = js_object_->Get( String::NewSymbol("on_connect") );
Handle<Value> on_connect_value = socket->handle_->Get( String::NewSymbol("onConnect") );
if (!on_connect_value->IsFunction())
return;
Handle<Function> on_connect = Handle<Function>::Cast(on_connect_value);
TryCatch try_catch;
Handle<Value> r = on_connect->Call(js_object_, 0, NULL);
Handle<Value> 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<Socket*> (s->data);
HandleScope scope;
assert(READY_STATE_OPEN == ReadyState());
Handle<Value> onread_value = js_object_->Get( String::NewSymbol("on_read") );
Handle<Value> onread_value = socket->handle_->Get( String::NewSymbol("onRead") );
if (!onread_value->IsFunction()) return;
Handle<Function> onread = Handle<Function>::Cast(onread_value);
@ -325,101 +257,118 @@ Socket::OnRead (const void *buf, size_t count)
Handle<Value> argv[argc];
if(count) {
Handle<String> chunk = String::New((const char*)buf, count); // TODO binary data?
argv[0] = chunk;
if(socket->encoding_ == UTF8) {
// utf8 encoding
Handle<String> chunk = String::New((const char*)buf, count);
argv[0] = chunk;
} else {
// raw encoding
Local<Array> array = Array::New(count);
for (int i = 0; i < count; i++) {
int val = static_cast<const int*>(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<Value>::New(Null());
}
TryCatch try_catch;
Handle<Value> r = onread->Call(js_object_, argc, argv);
Handle<Value> r = onread->Call(socket->handle_, argc, argv);
if(try_catch.HasCaught())
node_fatal_exception(try_catch);
}
void
Socket::OnClose ()
Socket::OnClose (oi_socket *s)
{
Socket *socket = static_cast<Socket*> (s->data);
HandleScope scope;
printf("onclose readyState %d\n", ReadyState());
assert(READY_STATE_OPEN == ReadyState());
js_object_->Set(readyState_str, readyStateCLOSED);
Handle<Value> onclose_value = js_object_->Get( String::NewSymbol("on_close") );
Handle<Value> onclose_value = socket->handle_->Get( String::NewSymbol("onClose") );
if (!onclose_value->IsFunction()) return;
Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
TryCatch try_catch;
Handle<Value> r = onclose->Call(js_object_, 0, NULL);
Handle<Value> 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<Socket*> (s->data);
HandleScope scope;
Handle<Value> onclose_value = socket->handle_->Get( String::NewSymbol("onDrain") );
if (!onclose_value->IsFunction()) return;
Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
TryCatch try_catch;
Handle<Value> r = onclose->Call(socket->handle_, 0, NULL);
if(try_catch.HasCaught())
node_fatal_exception(try_catch);
}
void
Socket::OnError (oi_socket *s, oi_error e)
{
Socket *socket = static_cast<Socket*> (s->data);
HandleScope scope;
Handle<Value> onclose_value = socket->handle_->Get( String::NewSymbol("onError") );
if (!onclose_value->IsFunction()) return;
Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
TryCatch try_catch;
Handle<Value> r = onclose->Call(socket->handle_, 0, NULL);
if(try_catch.HasCaught())
node_fatal_exception(try_catch);
}
void
Socket::OnTimeout (oi_socket *s)
{
Socket *socket = static_cast<Socket*> (s->data);
HandleScope scope;
Handle<Value> onclose_value = socket->handle_->Get( String::NewSymbol("onTimeout") );
if (!onclose_value->IsFunction()) return;
Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
TryCatch try_catch;
Handle<Value> r = onclose->Call(socket->handle_, 0, NULL);
if(try_catch.HasCaught())
node_fatal_exception(try_catch);
}
void
NodeInit_net (Handle<Object> target)
{
HandleScope scope;
//
// Socket
//
Local<FunctionTemplate> socket_template = FunctionTemplate::New(NewSocket);
target->Set(String::NewSymbol("Socket"), socket_template->GetFunction());
Local<FunctionTemplate> socket_template = FunctionTemplate::New(Socket::New);
socket_template->InstanceTemplate()->SetInternalFieldCount(1);
target->Set(String::NewSymbol("Socket"), socket_template->GetFunction());
// socket.connectTCP()
Local<FunctionTemplate> socket_connect_tcp =
FunctionTemplate::New(SocketConnectTCPCallback);
socket_template->InstanceTemplate()->Set(String::NewSymbol("connectTCP"),
socket_connect_tcp->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.connectUNIX()
Local<FunctionTemplate> socket_connect_unix =
FunctionTemplate::New(SocketConnectUNIXCallback);
socket_template->InstanceTemplate()->Set(String::NewSymbol("connectUNIX"),
socket_connect_unix->GetFunction());
// socket.write()
Local<FunctionTemplate> socket_write =
FunctionTemplate::New(SocketWriteCallback);
socket_template->InstanceTemplate()->Set(String::NewSymbol("write"),
socket_write->GetFunction());
// socket.close()
Local<FunctionTemplate> socket_close =
FunctionTemplate::New(SocketCloseCallback);
socket_template->InstanceTemplate()->Set(String::NewSymbol("close"),
socket_close->GetFunction());
//
// Server
//
Local<FunctionTemplate> server_template = FunctionTemplate::New(NewServer);
target->Set(String::NewSymbol("Server"), server_template->GetFunction());
server_template->InstanceTemplate()->SetInternalFieldCount(1);
// server.listenTCP()
Local<FunctionTemplate> server_listenTCP =
FunctionTemplate::New(ServerListenTCPCallback);
server_template->InstanceTemplate()->Set(String::NewSymbol("listenTCP"),
server_listenTCP->GetFunction());
// server.listenUNIX()
Local<FunctionTemplate> server_listenUNIX =
FunctionTemplate::New(ServerListenUNIXCallback);
server_template->InstanceTemplate()->Set(String::NewSymbol("listenUNIX"),
server_listenTCP->GetFunction());
// server.close()
Local<FunctionTemplate> server_close = FunctionTemplate::New(ServerCloseCallback);
server_template->InstanceTemplate()->Set(String::NewSymbol("close"),
server_close->GetFunction());
}

View File

@ -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);

View File

@ -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