// Copyright 2009 Ryan Dahl #ifndef SRC_NET_H_ #define SRC_NET_H_ #include #include #include #include namespace node { class Server; class Connection : public EventEmitter { public: static void Initialize(v8::Handle target); protected: /* v8 interface */ static v8::Persistent constructor_template; static v8::Handle New(const v8::Arguments& args); static v8::Handle Connect(const v8::Arguments& args); static v8::Handle Send(const v8::Arguments& args); static v8::Handle SendUtf8(const v8::Arguments& args); static v8::Handle Close(const v8::Arguments& args); static v8::Handle ForceClose(const v8::Arguments& args); static v8::Handle SetEncoding(const v8::Arguments& args); static v8::Handle ReadPause(const v8::Arguments& args); static v8::Handle ReadResume(const v8::Arguments& args); static v8::Handle SetTimeout(const v8::Arguments& args); static v8::Handle SetNoDelay(const v8::Arguments& args); static v8::Handle ReadyStateGetter(v8::Local _, const v8::AccessorInfo& info); static v8::Handle FDGetter(v8::Local _, const v8::AccessorInfo& info); Connection() : EventEmitter() { encoding_ = BINARY; host_ = NULL; port_ = NULL; Init(); } virtual ~Connection(); int Connect(struct sockaddr *address) { return evcom_stream_connect(&stream_, address); } void Send(const char *buf, size_t len) { evcom_stream_write(&stream_, buf, len); } void Close() { evcom_stream_close(&stream_); } void ForceClose() { evcom_stream_force_close(&stream_); } void ReadPause() { evcom_stream_read_pause(&stream_); } void ReadResume() { evcom_stream_read_resume(&stream_); } void SetTimeout(float timeout) { evcom_stream_reset_timeout(&stream_, timeout); } void SetNoDelay(bool no_delay) { evcom_stream_set_no_delay(&stream_, no_delay); } virtual void OnConnect(); virtual void OnReceive(const void *buf, size_t len); virtual void OnEOF(); virtual void OnClose(); virtual void OnTimeout(); v8::Local GetProtocol(); enum evcom_stream_state ReadyState() { return evcom_stream_state(&stream_); } enum encoding encoding_; bool resolving_; private: /* liboi callbacks */ static void on_connect(evcom_stream *s) { Connection *connection = static_cast(s->data); connection->OnConnect(); } static void on_read(evcom_stream *s, const void *buf, size_t len) { Connection *connection = static_cast(s->data); assert(connection->attached_); if (len == 0) connection->OnEOF(); else connection->OnReceive(buf, len); } static void on_close(evcom_stream *s) { Connection *connection = static_cast(s->data); evcom_stream_detach(s); assert(connection->stream_.recvfd < 0); assert(connection->stream_.sendfd < 0); connection->OnClose(); assert(connection->attached_); connection->Detach(); } static void on_timeout(evcom_stream *s) { Connection *connection = static_cast(s->data); connection->OnTimeout(); } void Init(); // constructor helper. static int Resolve(eio_req *req); static int AfterResolve(eio_req *req); char *host_; char *port_; evcom_stream stream_; friend class Server; }; class Server : public EventEmitter { public: static void Initialize(v8::Handle target); protected: static v8::Persistent constructor_template; static v8::Handle New(const v8::Arguments& args); static v8::Handle Listen(const v8::Arguments& args); static v8::Handle Close(const v8::Arguments& args); Server() : EventEmitter() { evcom_server_init(&server_); server_.on_connection = Server::on_connection; server_.on_close = Server::on_close; server_.data = this; } virtual ~Server() { assert(server_.fd >= 0); } int Listen(struct sockaddr *address, int backlog) { int r = evcom_server_listen(&server_, address, backlog); if (r != 0) return r; evcom_server_attach(EV_DEFAULT_ &server_); Attach(); return 0; } void Close() { evcom_server_close(&server_); } virtual v8::Handle GetConnectionTemplate(); virtual Connection* UnwrapConnection(v8::Local connection); private: Connection* OnConnection(struct sockaddr *addr); static evcom_stream* on_connection(evcom_server *s, struct sockaddr *addr) { Server *server = static_cast(s->data); Connection *connection = server->OnConnection(addr); return &connection->stream_; } void OnClose(int errorno); static void on_close(evcom_server *s) { Server *server = static_cast(s->data); evcom_server_detach(s); server->OnClose(s->errorno); server->Detach(); } evcom_server server_; }; } // namespace node #endif // SRC_NET_H_