@ -4,6 +4,7 @@
# include <stdlib.h>
# include <string.h>
# include <strings.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/socket.h>
@ -12,9 +13,20 @@
using namespace v8 ;
using namespace node ;
# define ON_RECEIVE_SYMBOL String::NewSymbol("onReceive")
# define ON_DISCONNECT_SYMBOL String::NewSymbol("onDisconnect")
# define ON_CONNECT_SYMBOL String::NewSymbol("onConnect")
# define ON_CONNECTION_SYMBOL String::NewSymbol("onConnection")
# define ON_READ_SYMBOL String::NewSymbol("onRead")
# define ON_DRAIN_SYMBOL String::NewSymbol("onDrain")
# define ON_TIMEOUT_SYMBOL String::NewSymbol("onTimeout")
# define ON_ERROR_SYMBOL String::NewSymbol("onError")
# define SEND_SYMBOL String::NewSymbol("send")
# define DISCONNECT_SYMBOL String::NewSymbol("disconnect")
# define CONNECT_SYMBOL String::NewSymbol("connect")
# define ENCODING_SYMBOL String::NewSymbol("encoding")
# define TIMEOUT_SYMBOL String::NewSymbol("timeout")
# define PROTOCOL_SYMBOL String::NewSymbol("protocol")
static const struct addrinfo tcp_hints =
/* ai_flags */ { AI_PASSIVE
@ -27,325 +39,194 @@ static const struct addrinfo tcp_hints =
/* ai_next */ , NULL
} ;
Persistent < Function > tcp_connection_constructor ;
Server : : Server ( Handle < Object > handle , int backlog )
: ObjectWrap ( handle )
{
//HandleScope scope;
oi_server_init ( & server_ , backlog ) ;
server_ . on_connection = Server : : OnConnection ;
// server_.on_error = Server::OnError;
server_ . data = this ;
}
Server : : ~ Server ( )
{
//HandleScope scope;
oi_server_close ( & server_ ) ;
oi_server_detach ( & server_ ) ;
}
Handle < Value >
Server : : New ( const Arguments & args )
void
Connection : : Initialize ( v8 : : Handle < v8 : : Object > target )
{
HandleScope scope ;
int backlog = 1024 ; // default
if ( args . Length ( ) > 0 & & args [ 0 ] - > IsNumber ( ) )
backlog = args [ 0 ] - > IntegerValue ( ) ;
Local < FunctionTemplate > t = FunctionTemplate : : New ( Connection : : v8New ) ;
t - > InstanceTemplate ( ) - > SetInternalFieldCount ( 1 ) ;
target - > Set ( String : : NewSymbol ( " TCPConnection " ) , t - > GetFunction ( ) ) ;
new Server ( args . Holder ( ) , backlog ) ;
tcp_connection_constructor = Persistent < Function > : : New ( t - > GetFunction ( ) ) ;
return args . This ( ) ;
NODE_SET_METHOD ( t - > InstanceTemplate ( ) , " connect " , Connection : : v8Connect ) ;
NODE_SET_METHOD ( t - > InstanceTemplate ( ) , " disconnect " , Connection : : v8Disconnect ) ;
NODE_SET_METHOD ( t - > InstanceTemplate ( ) , " send " , Connection : : v8Send ) ;
}
Handle < Value >
Server : : ListenTCP ( const Arguments & args )
Local < Object >
Connection : : NewInstance ( Local < Function > protocol )
{
if ( args . Length ( ) < 2 ) return Undefined ( ) ;
HandleScope scope ;
Server * server = NODE_UNWRAP ( Server , args . Holder ( ) ) ;
String : : AsciiValue port ( args [ 0 ] ) ;
int callback_index = 1 ;
char * host = NULL ;
if ( args [ 1 ] - > IsString ( ) ) {
callback_index = 2 ;
String : : AsciiValue host_v ( args [ 1 ] - > ToString ( ) ) ;
if ( args [ 1 ] - > IsString ( ) ) host = * host_v ;
Handle < Value > argv [ ] = { protocol } ;
Local < Object > instance = tcp_connection_constructor - > NewInstance ( 1 , argv ) ;
return scope . Close ( instance ) ;
}
// For servers call getaddrinfo inline. This is blocking but it shouldn't
// matter--ever. If someone actually complains then simply swap it out
// with a libeio call.
struct addrinfo * address = NULL ;
int r = getaddrinfo ( host , * port , & tcp_hints , & address ) ;
if ( r ! = 0 )
return ThrowException ( String : : New ( " Error looking up hostname " ) ) ;
if ( ! args [ callback_index ] - > IsFunction ( ) )
return ThrowException ( String : : New ( " Must supply onConnection callback " ) ) ;
Connection : : Connection ( Handle < Object > handle )
: ObjectWrap ( handle )
{
HandleScope scope ;
server - > handle_ - > Set ( ON_CONNECTION_SYMBOL , args [ callback_index ] ) ;
Local < Object > protocol = GetProtocol ( ) ;
r = oi_server_listen ( & server - > server_ , address ) ;
if ( r ! = 0 )
return ThrowException ( String : : New ( " Error listening on port " ) ) ;
oi_server_attach ( EV_DEFAULT_UC_ & server - > server_ ) ;
encoding_ = RAW ;
Local < Value > encoding_v = protocol - > Get ( ENCODING_SYMBOL ) ;
if ( encoding_v - > IsString ( ) ) {
Local < String > encoding_string = encoding_v - > ToString ( ) ;
char buf [ 5 ] ; // need enough room for "utf8" or "raw"
encoding_string - > WriteAscii ( buf , 0 , 4 ) ;
buf [ 4 ] = ' \0 ' ;
if ( strcasecmp ( buf , " utf8 " ) = = 0 ) encoding_ = UTF8 ;
}
freeaddrinfo ( address ) ;
double timeout = 0.0 ; // default
Local < Value > timeout_v = protocol - > Get ( TIMEOUT_SYMBOL ) ;
if ( encoding_v - > IsInt32 ( ) )
timeout = timeout_v - > Int32Value ( ) / 1000.0 ;
return Undefined ( ) ;
}
host_ = NULL ;
port_ = NULL ;
Handle < Value >
Server : : Close ( const Arguments & args )
{
HandleScope scope ;
Server * server = NODE_UNWRAP ( Server , args . Holder ( ) ) ;
oi_server_close ( & server - > server_ ) ;
return Undefined ( ) ;
oi_socket_init ( & socket_ , timeout ) ;
socket_ . on_connect = Connection : : _OnConnect ;
socket_ . on_read = Connection : : _OnReceive ;
socket_ . on_drain = Connection : : _OnDrain ;
socket_ . on_error = Connection : : _OnError ;
socket_ . on_close = Connection : : _OnDisconnect ;
socket_ . on_timeout = Connection : : _OnTimeout ;
socket_ . data = this ;
}
oi_socket *
Server : : OnConnection ( oi_server * s , struct sockaddr * remote_addr , socklen_t remote_addr_len )
Local < Object >
Connection : : GetProtocol ( void )
{
Server * server = static_cast < Server * > ( s - > data ) ;
HandleScope scope ;
Socket * socket = Socket : : NewConnection ( 60.0 ) ;
Local < Value > callback_v = server - > handle_ - > Get ( ON_CONNECTION_SYMBOL ) ;
if ( ! callback_v - > IsFunction ( ) )
return NULL ; // produce error?
Local < Function > callback = Local < Function > : : Cast ( callback_v ) ;
const int argc = 1 ;
Local < Value > argv [ argc ] ;
argv [ 0 ] = Local < Value > : : New ( socket - > handle_ ) ;
callback - > Call ( server - > handle_ , argc , argv ) ;
Local < Value > protocol_v = handle_ - > Get ( PROTOCOL_SYMBOL ) ;
if ( protocol_v - > IsObject ( ) ) {
Local < Object > protocol = protocol_v - > ToObject ( ) ;
return scope . Close ( protocol ) ;
}
return & socket - > socket_ ;
return Local < Object > ( ) ;
}
Handle < Value >
Socket : : New ( const Arguments & args )
Connection : : v8New ( const Arguments & args )
{
if ( args . Length ( ) > 1 )
return Undefined ( ) ;
HandleScope scope ;
// Default options
double timeout = 60.0 ; // in seconds
enum { UTF8 , RAW } encoding ;
if ( args [ 0 ] - > IsFunction ( ) = = false )
return ThrowException ( String : : New ( " Must pass a class as the first argument. " ) ) ;
// Set options from argument.
if ( args . Length ( ) = = 1 & & args [ 0 ] - > IsObject ( ) ) {
Local < Object > options = args [ 0 ] - > ToObject ( ) ;
Local < Value > timeout_value = options - > Get ( String : : NewSymbol ( " timeout " ) ) ;
Local < Value > encoding_value = options - > Get ( String : : NewSymbol ( " encoding " ) ) ;
Handle < Function > protocol = Handle < Function > : : Cast ( args [ 0 ] ) ;
Handle < Value > argv [ ] = { args . This ( ) } ;
Local < Object > protocol_instance = protocol - > NewInstance ( 1 , argv ) ;
args . This ( ) - > Set ( PROTOCOL_SYMBOL , protocol_instance ) ;
if ( timeout_value - > IsNumber ( ) ) {
// timeout is specified in milliseconds like other time
// values in javascript
timeout = timeout_value - > NumberValue ( ) / 1000 ;
}
if ( encoding_value - > IsString ( ) ) {
Local < String > encoding_string = encoding_value - > ToString ( ) ;
char buf [ 5 ] ; // need enough room for "utf8" or "raw"
encoding_string - > WriteAscii ( buf , 0 , 4 ) ;
buf [ 4 ] = ' \0 ' ;
if ( strcasecmp ( buf , " utf8 " ) = = 0 ) encoding = UTF8 ;
}
}
new Socket ( args . Holder ( ) , timeout ) ;
new Connection ( args . This ( ) ) ;
return args . This ( ) ;
}
void
Socket : : SetEncoding ( Handle < Value > encoding_value )
{
if ( encoding_value - > IsString ( ) ) {
HandleScope scope ;
Local < String > encoding_string = encoding_value - > ToString ( ) ;
char buf [ 5 ] ; // need enough room for "utf8" or "raw"
encoding_string - > WriteAscii ( buf , 0 , 4 ) ;
buf [ 4 ] = ' \0 ' ;
if ( strcasecmp ( buf , " utf8 " ) = = 0 )
encoding_ = UTF8 ;
else
encoding_ = RAW ;
}
}
Handle < Value >
Socket : : ConnectTCP ( const Arguments & args )
Connection : : v8Connect ( const Arguments & args )
{
if ( args . Length ( ) < 1 )
return Undefined ( ) ;
HandleScope scope ;
Socket * socket = NODE_UNWRAP ( Socket , args . Holder ( ) ) ;
Connection * connection = NODE_UNWRAP ( Connection , args . Holder ( ) ) ;
String : : AsciiValue port ( args [ 0 ] ) ;
socket - > port_ = strdup ( * port ) ;
if ( args . Length ( ) = = 0 | | args [ 0 ] - > IsInt32 ( ) = = false )
return ThrowException ( String : : New ( " Must specify a port. " ) ) ;
assert ( socket - > host_ = = NULL ) ;
String : : AsciiValue host_v ( args [ 1 ] - > ToString ( ) ) ;
if ( args [ 1 ] - > IsString ( ) ) {
socket - > host_ = strdup ( * host_v ) ;
}
String : : AsciiValue port_sv ( args [ 0 ] - > ToString ( ) ) ;
assert ( connection - > port_ = = NULL ) ;
connection - > port_ = strdup ( * port_sv ) ;
if ( args [ 2 ] - > IsFunction ( ) ) {
socket - > handle_ - > Set ( ON_CONNECT_SYMBOL , args [ 2 ] ) ;
assert ( connection - > host_ = = NULL ) ;
if ( args . Length ( ) > 1 & & args [ 1 ] - > IsString ( ) ) {
String : : Utf8Value host_sv ( args [ 1 ] - > ToString ( ) ) ;
connection - > host_ = strdup ( * host_sv ) ;
}
/* For the moment I will do DNS lookups in the thread pool. This is
/* For the moment I will do DNS lookups in the eio thread pool. This is
* sub - optimal and cannot handle massive numbers of requests but it is
* quite portable .
* In the future I will move to a system using adns or udns :
* http : //lists.schmorp.de/pipermail/libev/2009q1/000632.html
*/
eio_warmup ( ) ;
eio_req * req = eio_custom ( Socket : : Resolve , EIO_PRI_DEFAULT , Socket : : AfterResolve , socket ) ;
eio_req * req = eio_custom ( Connection : : Resolve
, EIO_PRI_DEFAULT
, Connection : : AfterResolve
, connection
) ;
return Undefined ( ) ;
}
/* This function is executed in the thread pool. It cannot touch anything! */
int
Socket : : Resolve ( eio_req * req )
Connection : : Resolve ( eio_req * req )
{
Socket * socket = static_cast < Socket * > ( req - > data ) ;
Connection * connection = static_cast < Connection * > ( req - > data ) ;
struct addrinfo * address = NULL ;
req - > result = getaddrinfo ( socket - > host_ , socket - > port_ , & tcp_hints , & address ) ;
req - > result = getaddrinfo ( connection - > host_ , connection - > port_ , & tcp_hints , & address ) ;
req - > ptr2 = address ;
free ( socket - > host_ ) ;
socket - > host_ = NULL ;
free ( connection - > host_ ) ;
connection - > host_ = NULL ;
free ( socket - > port_ ) ;
socket - > port_ = NULL ;
free ( connection - > port_ ) ;
connection - > port_ = NULL ;
return 0 ;
}
int
Socket : : AfterResolve ( eio_req * req )
Connection : : AfterResolve ( eio_req * req )
{
Socket * socket = static_cast < Socket * > ( req - > data ) ;
Connection * connection = static_cast < Connection * > ( req - > data ) ;
struct addrinfo * address = static_cast < struct addrinfo * > ( req - > ptr2 ) ;
req - > ptr2 = NULL ;
int r = 0 ;
if ( req - > result = = 0 ) {
r = oi_socket_connect ( & socket - > socket_ , address ) ;
r = connection - > Connect ( address ) ;
}
if ( address )
freeaddrinfo ( address ) ;
if ( address ) freeaddrinfo ( address ) ;
// no error. return.
if ( r = = 0 & & req - > result = = 0 ) {
oi_socket_attach ( EV_DEFAULT_UC_ & socket - > socket_ ) ;
oi_socket_attach ( EV_DEFAULT_UC_ & connection - > socket_ ) ;
return 0 ;
}
HandleScope scope ;
Handle < Value > onconnect_value = socket - > handle_ - > Get ( ON_CONNECT_SYMBOL ) ;
if ( ! onconnect_value - > IsFunction ( ) ) return 0 ;
Handle < Function > onconnect = Handle < Function > : : Cast ( onconnect_value ) ;
TryCatch try_catch ;
const int argc = 1 ;
Local < Value > argv [ argc ] ;
argv [ 0 ] = Integer : : New ( r | req - > result ) ; // FIXME very stupid error code.
onconnect - > Call ( socket - > handle_ , argc , argv ) ;
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
return 0 ;
}
Handle < Value >
Socket : : Close ( const Arguments & args )
{
HandleScope scope ;
Socket * socket = NODE_UNWRAP ( Socket , args . Holder ( ) ) ;
oi_socket_close ( & socket - > socket_ ) ;
return Undefined ( ) ;
}
Socket : : Socket ( Handle < Object > handle , double timeout )
: ObjectWrap ( handle )
{
//HandleScope scope;
oi_socket_init ( & socket_ , 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 ;
encoding_ = UTF8 ; // default encoding.
host_ = NULL ;
port_ = NULL ;
}
Socket *
Socket : : NewConnection ( double timeout )
{
HandleScope scope ;
Local < Object > socket_handle = socket_template - > GetFunction ( ) - > NewInstance ( ) ;
Socket * socket = new Socket ( socket_handle , 60.0 ) ;
socket - > handle_ - > Delete ( String : : NewSymbol ( " connectTCP " ) ) ;
return socket ;
}
Socket : : ~ Socket ( )
{
oi_socket_close ( & socket_ ) ;
oi_socket_detach ( & socket_ ) ;
free ( host_ ) ;
free ( port_ ) ;
// return error?
//HandleScope scope;
handle_ - > Delete ( String : : NewSymbol ( " write " ) ) ;
handle_ - > Delete ( String : : NewSymbol ( " close " ) ) ;
return r | req - > result ;
}
Handle < Value >
Socket : : SetEncoding ( const Arguments & args )
Connection : : v8Disconnect ( const Arguments & args )
{
HandleScope scope ;
Socket * socket = NODE_UNWRAP ( Socket , args . Holder ( ) ) ;
socket - > SetEncoding ( args [ 0 ] ) ;
Connection * connection = NODE_UNWRAP ( Connection , args . Holder ( ) ) ;
connection - > Disconnect ( ) ;
return Undefined ( ) ;
}
Handle < Value >
Socket : : Write ( const Arguments & args )
Connection : : v8Send ( const Arguments & args )
{
HandleScope scope ;
Socket * socket = NODE_UNWRAP ( Socket , args . Holder ( ) ) ;
// TODO support a callback using buf->on_release
Connection * connection = NODE_UNWRAP ( Connection , args . Holder ( ) ) ;
if ( args [ 0 ] = = Null ( ) ) {
oi_socket_write_eof ( & socket - > socket_ ) ;
oi_socket_write_eof ( & connection - > socket_ ) ;
} else if ( args [ 0 ] - > IsString ( ) ) {
// utf8 encoding
@ -353,18 +234,18 @@ Socket::Write (const Arguments& args)
size_t length = s - > Utf8Length ( ) ;
oi_buf * buf = oi_buf_new2 ( length ) ;
s - > WriteUtf8 ( buf - > base , length ) ;
oi_socket_write ( & socket - > socket_ , buf ) ;
connection - > Send ( buf ) ;
} else if ( args [ 0 ] - > IsArray ( ) ) {
// raw encoding
Handle < Array > array = Handle < Array > : : Cast ( args [ 0 ] ) ;
size_t length = array - > Length ( ) ;
oi_buf * buf = oi_buf_new2 ( length ) ;
for ( in t i = 0 ; i < length ; i + + ) {
for ( size_ t i = 0 ; i < length ; i + + ) {
Local < Value > int_value = array - > Get ( Integer : : New ( i ) ) ;
buf - > base [ i ] = int_value - > IntegerValue ( ) ;
}
oi_socket_write ( & socket - > socket_ , buf ) ;
connection - > Send ( buf ) ;
} else return ThrowException ( String : : New ( " Bad argument " ) ) ;
@ -372,50 +253,29 @@ Socket::Write (const Arguments& args)
}
void
Socket : : OnConnect ( oi_socket * s )
Connection : : OnReceive ( const void * buf , size_t len )
{
Socket * socket = static_cast < Socket * > ( s - > data ) ;
HandleScope scope ;
Handle < Value > on_connect_value = socket - > handle_ - > Get ( ON_CONNECT_SYMBOL ) ;
if ( ! on_connect_value - > IsFunction ( ) )
return ;
Handle < Function > on_connect = Handle < Function > : : Cast ( on_connect_value ) ;
Local < Object > protocol = GetProtocol ( ) ;
Handle < Value > callback_v = protocol - > Get ( ON_RECEIVE_SYMBOL ) ;
if ( ! callback_v - > IsFunction ( ) ) return ;
TryCatch try_catch ;
const int argc = 1 ;
Local < Value > argv [ argc ] ;
argv [ 0 ] = Integer : : New ( 0 ) ;
Handle < Value > r = on_connect - > Call ( socket - > handle_ , argc , argv ) ;
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
}
void
Socket : : OnRead ( oi_socket * s , const void * buf , size_t count )
{
Socket * socket = static_cast < Socket * > ( s - > data ) ;
HandleScope scope ;
Handle < Value > onread_value = socket - > handle_ - > Get ( ON_READ_SYMBOL ) ;
if ( ! onread_value - > IsFunction ( ) ) return ;
Handle < Function > onread = Handle < Function > : : Cast ( onread_value ) ;
Handle < Function > callback = Handle < Function > : : Cast ( callback_v ) ;
const int argc = 1 ;
Handle < Value > argv [ argc ] ;
if ( count ) {
if ( socket - > encoding_ = = UTF8 ) {
if ( len ) {
if ( encoding_ = = UTF8 ) {
// utf8 encoding
Handle < String > chunk = String : : New ( ( const char * ) buf , count ) ;
Handle < String > chunk = String : : New ( ( const char * ) buf , len ) ;
argv [ 0 ] = chunk ;
} else {
// raw encoding
Local < Array > array = Array : : New ( count ) ;
for ( in t i = 0 ; i < count ; i + + ) {
Local < Array > array = Array : : New ( len ) ;
for ( size_t i = 0 ; i < len ; i + + ) {
char val = static_cast < const char * > ( buf ) [ i ] ;
array - > Set ( Integer : : New ( i ) , Integer : : New ( val ) ) ;
}
@ -426,118 +286,164 @@ Socket::OnRead (oi_socket *s, const void *buf, size_t count)
}
TryCatch try_catch ;
Handle < Value > r = onread - > Call ( socket - > handle_ , argc , argv ) ;
callback - > Call ( protocol , argc , argv ) ;
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
fatal_exception ( try_catch ) ; // XXX is this the right action to take?
}
void
Socket : : OnClose ( oi_socket * s )
Connection : : OnError ( oi_error e )
{
Socket * socket = static_cast < Socket * > ( s - > data ) ;
HandleScope scope ;
}
Handle < Value > onclose_value = socket - > handle_ - > Get ( String : : NewSymbol ( " onClose " ) ) ;
if ( ! onclose_value - > IsFunction ( ) ) {
delete socket ;
return ;
# define DEFINE_SIMPLE_CALLBACK(name, symbol) \
void name ( ) \
{ \
HandleScope scope ; \
Local < Object > protocol = GetProtocol ( ) ; \
Local < Value > callback_v = protocol - > Get ( symbol ) ; \
if ( ! callback_v - > IsFunction ( ) ) return ; \
Handle < Function > callback = Handle < Function > : : Cast ( callback_v ) ; \
callback - > Call ( protocol , 0 , NULL ) ; \
}
Handle < Function > onclose = Handle < Function > : : Cast ( onclose_value ) ;
TryCatch try_catch ;
DEFINE_SIMPLE_CALLBACK ( Connection : : OnConnect , ON_CONNECT_SYMBOL )
DEFINE_SIMPLE_CALLBACK ( Connection : : OnDrain , ON_DRAIN_SYMBOL )
DEFINE_SIMPLE_CALLBACK ( Connection : : OnDisconnect , ON_DISCONNECT_SYMBOL )
DEFINE_SIMPLE_CALLBACK ( Connection : : OnTimeout , ON_TIMEOUT_SYMBOL )
Handle < Value > r = onclose - > Call ( socket - > handle_ , 0 , NULL ) ;
void
Acceptor : : Initialize ( Handle < Object > target )
{
HandleScope scope ;
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
Local < FunctionTemplate > tcp_server_template =
FunctionTemplate : : New ( Acceptor : : v8New ) ;
tcp_server_template - > InstanceTemplate ( ) - > SetInternalFieldCount ( 1 ) ;
target - > Set ( String : : NewSymbol ( " TCPServer " ) , tcp_server_template - > GetFunction ( ) ) ;
delete socket ;
NODE_SET_METHOD ( tcp_server_template - > InstanceTemplate ( )
, " listen "
, Acceptor : : v8Listen
) ;
NODE_SET_METHOD ( tcp_server_template - > InstanceTemplate ( )
, " close "
, Acceptor : : v8Close
) ;
}
void
Socket : : OnDrain ( oi_socket * s )
Acceptor : : Acceptor ( Handle < Object > handle , Handle < Object > options )
: ObjectWrap ( handle )
{
Socket * socket = static_cast < Socket * > ( s - > data ) ;
HandleScope scope ;
Handle < Value > ondrain_value = socket - > handle_ - > Get ( String : : NewSymbol ( " onDrain " ) ) ;
if ( ! ondrain_value - > IsFunction ( ) ) return ;
Handle < Function > ondrain = Handle < Function > : : Cast ( ondrain_value ) ;
TryCatch try_catch ;
Handle < Value > r = ondrain - > Call ( socket - > handle_ , 0 , NULL ) ;
int backlog = 1024 ; // default value
Local < Value > backlog_v = options - > Get ( String : : NewSymbol ( " backlog " ) ) ;
if ( backlog_v - > IsInt32 ( ) ) {
backlog = backlog_v - > IntegerValue ( ) ;
}
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
Local < Value > on_error_v = options - > Get ( ON_ERROR_SYMBOL ) ;
if ( on_error_v - > IsFunction ( ) ) {
handle_ - > Set ( ON_ERROR_SYMBOL , on_error_v ) ;
}
oi_server_init ( & server_ , backlog ) ;
server_ . on_connection = Acceptor : : _OnConnection ;
server_ . on_error = Acceptor : : _OnError ;
server_ . data = this ;
}
void
Socket : : OnError ( oi_socket * s , oi_error e )
Connection *
Acceptor : : OnConnection ( struct sockaddr * addr , socklen_t len )
{
Socket * socket = static_cast < Socket * > ( s - > data ) ;
HandleScope scope ;
Handle < Value > onerror_value = socket - > handle_ - > Get ( String : : NewSymbol ( " onError " ) ) ;
if ( ! onerror_value - > IsFunction ( ) ) return ;
Handle < Function > onerror = Handle < Function > : : Cast ( onerror_value ) ;
TryCatch try_catch ;
Local < Value > protocol_v = handle_ - > GetHiddenValue ( PROTOCOL_SYMBOL ) ;
if ( ! protocol_v - > IsFunction ( ) ) {
Close ( ) ;
return NULL ;
}
Local < Function > protocol = Local < Function > : : Cast ( protocol_v ) ;
Handle < Value > r = onerror - > Call ( socket - > handle_ , 0 , NULL ) ;
Local < Object > connection_handle = Connection : : NewInstance ( protocol ) ;
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
Connection * connection = new Connection ( connection_handle ) ;
return connection ;
}
void
Socket : : OnTimeout ( oi_socket * s )
Acceptor : : OnError ( struct oi_error error )
{
Socket * socket = static_cast < Socket * > ( s - > data ) ;
HandleScope scope ;
Handle < Value > ontimeout_value = socket - > handle_ - > Get ( String : : NewSymbol ( " onTimeout " ) ) ;
if ( ! ontimeout_value - > IsFunction ( ) ) return ;
Handle < Function > ontimeout = Handle < Function > : : Cast ( ontimeout_value ) ;
Local < Value > callback_v = handle_ - > Get ( String : : NewSymbol ( " onError " ) ) ;
if ( ! callback_v - > IsFunction ( ) ) return ;
Local < Function > callback = Local < Function > : : Cast ( callback_v ) ;
callback - > Call ( handle_ , 0 , NULL ) ; // TODO args
}
TryCatch try_catch ;
Handle < Value >
Acceptor : : v8New ( const Arguments & args )
{
HandleScope scope ;
Handle < Value > r = ontimeout - > Call ( socket - > handle_ , 0 , NULL ) ;
if ( args . Length ( ) < 1 | | args [ 0 ] - > IsFunction ( ) = = false )
return ThrowException ( String : : New ( " Must at give connection handler as the first argument " ) ) ;
if ( try_catch . HasCaught ( ) )
fatal_exception ( try_catch ) ;
/// set the handler
args . Holder ( ) - > SetHiddenValue ( PROTOCOL_SYMBOL , args [ 0 ] ) ;
Local < Object > options ;
if ( args . Length ( ) > 1 & & args [ 1 ] - > IsObject ( ) ) {
options = args [ 1 ] - > ToObject ( ) ;
} else {
options = Object : : New ( ) ;
}
void
Socket : : Initialize ( Handle < Object > target )
{
HandleScope scope ;
new Acceptor ( args . Holder ( ) , options ) ;
Local < FunctionTemplate > template_local = FunctionTemplate : : New ( Socket : : New ) ;
socket_template = Persistent < FunctionTemplate > : : New ( template_local ) ;
socket_template - > InstanceTemplate ( ) - > SetInternalFieldCount ( 1 ) ;
target - > Set ( String : : NewSymbol ( " Socket " ) , socket_template - > GetFunction ( ) ) ;
Acceptor * acceptor = NODE_UNWRAP ( Acceptor , args . Holder ( ) ) ;
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 ) ;
NODE_SET_METHOD ( socket_template - > InstanceTemplate ( ) , " setEncoding " , Socket : : SetEncoding ) ;
return args . This ( ) ;
}
void
Server : : Initialize ( Handle < Object > target )
Handle < Value >
Acceptor : : v8Listen ( const Arguments & args )
{
Acceptor * acceptor = NODE_UNWRAP ( Acceptor , args . Holder ( ) ) ;
if ( args . Length ( ) < 1 )
return ThrowException ( String : : New ( " Must give at least a port as argument. " ) ) ;
char * host = NULL ;
HandleScope scope ;
String : : AsciiValue port ( args [ 0 ] - > ToString ( ) ) ;
Local < FunctionTemplate > server_template = FunctionTemplate : : New ( Server : : New ) ;
server_template - > InstanceTemplate ( ) - > SetInternalFieldCount ( 1 ) ;
target - > Set ( String : : NewSymbol ( " Server " ) , server_template - > GetFunction ( ) ) ;
if ( args [ 1 ] - > IsString ( ) ) {
String : : Utf8Value host_sv ( args [ 1 ] - > ToString ( ) ) ;
host = * host_sv ;
}
NODE_SET_METHOD ( server_template - > InstanceTemplate ( ) , " listenTCP " , Server : : ListenTCP ) ;
NODE_SET_METHOD ( server_template - > InstanceTemplate ( ) , " close " , Server : : Close ) ;
// For servers call getaddrinfo inline. This is blocking but it shouldn't
// matter--ever. If someone actually complains then simply swap it out
// with a libeio call.
struct addrinfo * address = NULL ;
int r = getaddrinfo ( host , * port , & tcp_hints , & address ) ;
if ( r ! = 0 )
return ThrowException ( String : : New ( strerror ( errno ) ) ) ;
acceptor - > Listen ( address ) ;
return Undefined ( ) ;
}
Handle < Value >
Acceptor : : v8Close ( const Arguments & args )
{
Acceptor * acceptor = NODE_UNWRAP ( Acceptor , args . Holder ( ) ) ;
acceptor - > Close ( ) ;
return Undefined ( ) ;
}