From c72967d3351c4a28c3f2434748598017aa0126d5 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 23 Apr 2010 17:10:01 -0700 Subject: [PATCH] Remove http_old tcp_old --- deps/evcom/Makefile | 75 -- deps/evcom/evcom.c | 1589 ------------------------------------ deps/evcom/evcom.h | 260 ------ deps/evcom/recv_states.dot | 37 - deps/evcom/send_states.dot | 65 -- deps/evcom/test/echo.c | 100 --- deps/evcom/test/test.c | 892 -------------------- deps/evcom/test/timeout.rb | 98 --- lib/http_old.js | 641 --------------- lib/tcp_old.js | 26 - src/node.cc | 30 - src/node.h | 1 - src/node_cares.cc | 4 + src/node_http.cc | 392 --------- src/node_http.h | 68 -- src/node_net.cc | 1122 ------------------------- src/node_net.h | 284 ------- src/node_net2.cc | 2 + wscript | 25 +- 19 files changed, 8 insertions(+), 5703 deletions(-) delete mode 100644 deps/evcom/Makefile delete mode 100644 deps/evcom/evcom.c delete mode 100644 deps/evcom/evcom.h delete mode 100644 deps/evcom/recv_states.dot delete mode 100644 deps/evcom/send_states.dot delete mode 100644 deps/evcom/test/echo.c delete mode 100644 deps/evcom/test/test.c delete mode 100755 deps/evcom/test/timeout.rb delete mode 100644 lib/http_old.js delete mode 100644 lib/tcp_old.js delete mode 100644 src/node_http.cc delete mode 100644 src/node_http.h delete mode 100644 src/node_net.cc delete mode 100644 src/node_net.h diff --git a/deps/evcom/Makefile b/deps/evcom/Makefile deleted file mode 100644 index ffb6b64dee..0000000000 --- a/deps/evcom/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# Define EVDIR=/foo/bar if your libev header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -EVDIR=$(HOME)/local/libev - -# Define GNUTLSDIR=/foo/bar if your gnutls header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -# -# Comment out the following line to disable TLS -GNUTLSDIR=/usr - -# CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = -g -I. -Wall -Werror -Wextra #-DNDEBUG=1 -LDFLAGS = - -CC = gcc -AR = ar -RANLIB = ranlib - -ifdef EVDIR - CFLAGS += -I$(EVDIR)/include - LDFLAGS += -L$(EVDIR)/lib -endif - -LDFLAGS += -lev - -ifdef GNUTLSDIR - CFLAGS += -I$(GNUTLSDIR)/include -DEVCOM_HAVE_GNUTLS=1 - LDFLAGS += -L$(GNUTLSDIR)/lib - LDFLAGS += -lgnutls -endif - -DEP = evcom.h -SRC = evcom.c -OBJ = ${SRC:.c=.o} - -NAME=libevcom -OUTPUT_A=$(NAME).a - -all: $(OUTPUT_A) test/test test/echo - -$(OUTPUT_A): $(OBJ) - $(AR) cru $(OUTPUT_A) $(OBJ) - $(RANLIB) $(OUTPUT_A) - -.c.o: - $(CC) -c ${CFLAGS} $< - -${OBJ}: ${DEP} - -FAIL=ruby -e 'puts "\033[1;31m FAIL\033[m"' -PASS=ruby -e 'puts "\033[1;32m PASS\033[m"' - -test: test/test test/echo test/timeout.rb - @echo test.c - @test/test > /dev/null && $(PASS) || $(FAIL) - @echo timeout.rb - @test/timeout.rb - -test/test: test/test.c $(OUTPUT_A) - $(CC) $(LDFLAGS) $(CFLAGS) -o $@ test/test.c $(OUTPUT_A) - -test/echo: test/echo.c $(OUTPUT_A) - $(CC) $(LDFLAGS) $(CFLAGS) -o $@ test/echo.c $(OUTPUT_A) - -send_states.png: send_states.dot - dot -Tpng -o send_states.png send_states.dot - -recv_states.png: recv_states.dot - dot -Tpng -o recv_states.png recv_states.dot - -clean: - rm -rf test/test test/echo - rm -f $(OUTPUT_A) *.o - -.PHONY: all clean test diff --git a/deps/evcom/evcom.c b/deps/evcom/evcom.c deleted file mode 100644 index 1088181cef..0000000000 --- a/deps/evcom/evcom.c +++ /dev/null @@ -1,1589 +0,0 @@ -/* Copyright (c) 2008,2009 Ryan Dahl - * - * evcom_queue comes from ngx_queue.h - * Copyright (C) 2002-2009 Igor Sysoev - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include /* memset */ - -#include - -#include /* TCP_NODELAY */ -#include -#include /* shutdown */ -#include -#include /* sockaddr_in, sockaddr_in6 */ - -#include -#include - -#if EV_MULTIPLICITY -# define D_LOOP_(d) (d)->loop, -# define D_LOOP_SET(d, _loop) do { (d)->loop = (_loop); } while (0) -#else -# define D_LOOP_(d) -# define D_LOOP_SET(d, _loop) -#endif // EV_MULTIPLICITY - - -/* SEND STATES */ -static int stream_send__wait_for_connection (evcom_stream*); -static int stream_send__data (evcom_stream*); -static int stream_send__drain (evcom_stream*); -static int stream_send__wait_for_eof (evcom_stream*); -static int stream_send__wait_for_buf (evcom_stream*); -static int stream_send__shutdown (evcom_stream*); -#if EVCOM_HAVE_GNUTLS -static int stream_send__gnutls_bye (evcom_stream*); -#endif -static int stream_send__close_one (evcom_stream*); -static int stream_send__close (evcom_stream*); - -/* RECV STATES */ -static int stream_recv__data (evcom_stream*); -static int stream_recv__wait_for_resume (evcom_stream*); -static int stream_recv__wait_for_close (evcom_stream*); -static int stream_recv__close_one (evcom_stream*); -static int stream_recv__close (evcom_stream*); - -/* COMMON STATES */ -#if EVCOM_HAVE_GNUTLS -static int stream__handshake (evcom_stream*); -#endif -static int stream__close_both (evcom_stream*); - -#undef TRUE -#define TRUE 1 -#undef FALSE -#define FALSE 0 -#undef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -#define OKAY 0 -#define AGAIN 1 - -#define ATTACHED(s) ((s)->flags & EVCOM_ATTACHED) -#define LISTENING(s) ((s)->flags & EVCOM_LISTENING) -#define CONNECTED(s) ((s)->flags & EVCOM_CONNECTED) -#define SECURE(s) ((s)->flags & EVCOM_SECURE) -#define DUPLEX(s) ((s)->flags & EVCOM_DUPLEX) -#define GOT_CLOSE(s) ((s)->flags & EVCOM_GOT_CLOSE) -#define PAUSED(s) ((s)->flags & EVCOM_PAUSED) -#define READABLE(s) ((s)->flags & EVCOM_READABLE) -#define WRITABLE(s) ((s)->flags & EVCOM_WRITABLE) - -static int too_many_connections = 0; - -EV_INLINE int -set_nonblock (int fd) -{ - int flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) return -1; - - int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (r == -1) return -1; - - return 0; -} - -evcom_buf * -evcom_buf_new2 (size_t len) -{ - void *data = malloc(sizeof(evcom_buf) + len); - if (!data) return NULL; - - evcom_buf *buf = data; - buf->len = len; - buf->release = (void (*)(evcom_buf*))free; - buf->base = data + sizeof(evcom_buf); - - return buf; -} - -evcom_buf * -evcom_buf_new (const char *base, size_t len) -{ - evcom_buf* buf = evcom_buf_new2(len); - if (!buf) return NULL; - - memcpy(buf->base, base, len); - - return buf; -} - -void evcom_ignore_sigpipe (void) -{ - struct sigaction sa; - bzero(&sa, sizeof(sa)); - sa.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sa, NULL); -} - -static int -close_asap (evcom_descriptor *d) -{ - if (d->fd < 0) return OKAY; - - int r = close(d->fd); - - if (r < 0) { - if (errno == EINTR) { - d->action = close_asap; - return AGAIN; - } else { - d->errorno = errno; - } - } - - d->action = NULL; - d->fd = -1; - - return OKAY; -} - -#define release_write_buffer(writer) \ -do { \ - while (!evcom_queue_empty(&(writer)->out)) { \ - evcom_queue *q = evcom_queue_last(&(writer)->out); \ - evcom_buf *buf = evcom_queue_data(q, evcom_buf, queue); \ - evcom_queue_remove(q); \ - if (buf->release) buf->release(buf); \ - } \ -} while (0) - -static int -close_writer_asap (evcom_writer *writer) -{ - release_write_buffer(writer); - ev_feed_event(D_LOOP_(writer) &writer->write_watcher, EV_WRITE); - return close_asap((evcom_descriptor*)writer); -} - -static inline void -evcom_perror (const char *msg, int errorno) -{ - fprintf(stderr, "(evcom) %s %s\n", msg, strerror(errorno)); -} - -static int -stream_send__wait_for_buf (evcom_stream *stream) -{ - if (evcom_queue_empty(&stream->out)) { - if (GOT_CLOSE(stream)) { - stream->send_action = stream_send__drain; - return OKAY; - } - ev_io_stop(D_LOOP_(stream) &stream->write_watcher); - return AGAIN; - } - - stream->send_action = stream_send__data; - return OKAY; -} - -static inline void -stream__set_recv_closed (evcom_stream *stream) -{ - stream->flags &= ~EVCOM_READABLE; - stream->recvfd = -1; - stream->recv_action = NULL; - ev_io_stop(D_LOOP_(stream) &stream->read_watcher); -} - -static inline void -stream__set_send_closed (evcom_stream *stream) -{ - release_write_buffer(stream); - stream->flags &= ~EVCOM_WRITABLE; - stream->sendfd = -1; - stream->send_action = NULL; - ev_io_stop(D_LOOP_(stream) &stream->write_watcher); -} - -static int -stream_send__close_one (evcom_stream *stream) -{ - assert(stream->sendfd >= 0); - - close(stream->sendfd); - - /* TODO recover from EINTR */ - - stream__set_send_closed(stream); - - if (DUPLEX(stream) || stream->recv_action == stream_recv__wait_for_close) { - stream__set_recv_closed(stream); - } - - return OKAY; -} - -static int -stream__close_both (evcom_stream *stream) -{ - assert(stream->sendfd != stream->recvfd); - - assert(stream->sendfd >= 0); - assert(stream->recvfd >= 0); - - close(stream->recvfd); - close(stream->sendfd); - - /* TODO recover from EINTR */ - - stream__set_send_closed(stream); - stream__set_recv_closed(stream); - - return OKAY; -} - -static int -stream_send__close (evcom_stream *stream) -{ - if (DUPLEX(stream) || stream->recvfd < 0) { - stream->send_action = stream_send__close_one; - } else { - stream->send_action = stream__close_both; - } - return OKAY; -} - -static int -stream_recv__close_one (evcom_stream *stream) -{ - assert(stream->recvfd >= 0); - - close(stream->recvfd); - - /* TODO recover from EINTR */ - - stream__set_recv_closed(stream); - - if (DUPLEX(stream)) { - stream__set_send_closed(stream); - } - - return OKAY; -} - -static int -stream_recv__close (evcom_stream *stream) -{ - if (DUPLEX(stream) || stream->sendfd < 0) { - stream->recv_action = stream_recv__close_one; - } else { - stream->recv_action = stream__close_both; - } - return OKAY; -} - -static int -stream_send__drain (evcom_stream *stream) -{ - if (stream->on_drain) { - stream->on_drain(stream); - } - - if (!GOT_CLOSE(stream)) { - stream->send_action = stream_send__wait_for_buf; - return OKAY; - } - -#if EVCOM_HAVE_GNUTLS - if (SECURE(stream)) { - stream->send_action = stream_send__gnutls_bye; - return OKAY; - } -#endif - - if (DUPLEX(stream)) { - stream->send_action = stream_send__shutdown; - return OKAY; - } - - stream->send_action = stream_send__close_one; - return OKAY; -} - -static int -stream_send__wait_for_eof (evcom_stream *stream) -{ - if (READABLE(stream)) { - ev_io_stop(D_LOOP_(stream) &stream->write_watcher); - assert(stream->send_action == stream_send__wait_for_eof); - return AGAIN; - } - - stream->send_action = stream_send__close_one; - return OKAY; -} - -static inline ssize_t -nosigpipe_send (int fd, const void *buf, size_t len) -{ - int flags = 0; -#ifdef MSG_NOSIGNAL - flags |= MSG_NOSIGNAL; -#endif -#ifdef MSG_DONTWAIT - flags |= MSG_DONTWAIT; -#endif - return send(fd, buf, len, flags); -} - -static inline ssize_t -nosigpipe_stream_send (evcom_stream *stream, const void *buf, size_t len) -{ - return write(stream->sendfd, buf, len); -} - -#if EVCOM_HAVE_GNUTLS -static ssize_t -nosigpipe_push (gnutls_transport_ptr_t data, const void *buf, size_t len) -{ - evcom_stream *stream = (evcom_stream*)data; - assert(SECURE(stream)); - - return nosigpipe_stream_send(stream, buf, len); -} - -static ssize_t -pull (gnutls_transport_ptr_t data, void* buf, size_t len) -{ - evcom_stream *stream = (evcom_stream*)data; - assert(SECURE(stream)); - - return read(stream->recvfd, buf, len); -} - -static int -stream__handshake (evcom_stream *stream) -{ - assert(SECURE(stream)); - - int r = gnutls_handshake(stream->session); - - if (gnutls_error_is_fatal(r)) { - stream->gnutls_errorno = r; - stream->send_action = stream_send__close; - stream->recv_action = stream_recv__close; - return OKAY; - } - - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - - if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) { - if (0 == gnutls_record_get_direction((stream)->session)) { - ev_io_start(D_LOOP_(stream) &(stream)->read_watcher); - ev_io_stop(D_LOOP_(stream) &(stream)->write_watcher); - } else { - ev_io_stop(D_LOOP_(stream) &(stream)->read_watcher); - ev_io_start(D_LOOP_(stream) &(stream)->write_watcher); - } - assert(stream->recv_action == stream__handshake); - assert(stream->send_action == stream__handshake); - return AGAIN; - } - - assert(!CONNECTED(stream)); - stream->flags |= EVCOM_CONNECTED; - if (stream->on_connect) stream->on_connect(stream); - - /* evcom_stream_force_close might have been called. */ - if (stream->recvfd >= 0 && stream->sendfd >= 0) { - ev_io_start(D_LOOP_(stream) &stream->read_watcher); - ev_io_start(D_LOOP_(stream) &stream->write_watcher); - - stream->send_action = stream_send__data; - stream->recv_action = stream_recv__data; - } - - return OKAY; -} - -static int -stream_send__gnutls_bye (evcom_stream *stream) -{ - assert(SECURE(stream)); - - int r = gnutls_bye(stream->session, GNUTLS_SHUT_WR); - - if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) { - assert(1 == gnutls_record_get_direction((stream)->session)); - assert(stream->send_action == stream_send__gnutls_bye); - return AGAIN; - } - - if (gnutls_error_is_fatal(r)) { - stream->gnutls_errorno = r; - stream->send_action = stream_send__close; - return OKAY; - } - - stream->flags &= ~EVCOM_WRITABLE; - - stream->send_action = stream_send__wait_for_eof; - return OKAY; -} - -void -evcom_stream_set_secure_session (evcom_stream *stream, gnutls_session_t session) -{ - stream->session = session; - stream->flags |= EVCOM_SECURE; -} -#endif /* HAVE GNUTLS */ - -static int -stream_recv__wait_for_close (evcom_stream *stream) -{ - assert(!READABLE(stream)); - - if (!WRITABLE(stream)) { - stream->recv_action = stream_recv__close; - return OKAY; - } - - ev_io_stop(D_LOOP_(stream) &stream->read_watcher); - return AGAIN; -} - -static int -stream_recv__wait_for_resume (evcom_stream *stream) -{ - stream->flags |= EVCOM_PAUSED; - ev_io_stop(D_LOOP_(stream) &stream->read_watcher); - assert(stream->recv_action == stream_recv__wait_for_resume); - return AGAIN; -} - -static int -stream_recv__data (evcom_stream *stream) -{ - char buf[EVCOM_CHUNKSIZE]; - size_t buf_size = EVCOM_CHUNKSIZE; - ssize_t recved; - - while (READABLE(stream)) { - assert(CONNECTED(stream)); - - if (PAUSED(stream)) { - stream->recv_action = stream_recv__wait_for_resume; - return OKAY; - } - - -#if EVCOM_HAVE_GNUTLS - if (SECURE(stream)) { - recved = gnutls_record_recv(stream->session, buf, buf_size); - - if (gnutls_error_is_fatal(recved)) { - stream->gnutls_errorno = recved; - stream->recv_action = stream_recv__close; - return OKAY; - } - - if (recved == GNUTLS_E_INTERRUPTED || recved == GNUTLS_E_AGAIN) { - if (1 == gnutls_record_get_direction((stream)->session)) { - fprintf(stderr, "(evcom) gnutls recv: unexpected switch direction!\n"); - ev_io_stop(D_LOOP_(stream) &(stream)->read_watcher); - ev_io_start(D_LOOP_(stream) &(stream)->write_watcher); - } - return AGAIN; - } - - /* A server may also receive GNUTLS_E_REHANDSHAKE when a client has - * initiated a andshake. In that case the server can only initiate a - * handshake or terminate the connection. */ - if (recved == GNUTLS_E_REHANDSHAKE) { - assert(WRITABLE(stream)); - stream->recv_action = stream__handshake; - stream->send_action = stream__handshake; - return OKAY; - } - } else -#endif /* EVCOM_HAVE_GNUTLS */ - { - recved = read(stream->recvfd, buf, buf_size); - } - - if (recved < 0) { - if (errno == EAGAIN || errno == EINTR) { - assert(stream->recv_action == stream_recv__data); - return AGAIN; - } - - if (errno != ECONNRESET) { - evcom_perror("recv()", stream->errorno); - } - - stream->errorno = errno; - stream->recv_action = stream_recv__close; - return OKAY; - } - - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - - assert(recved >= 0); - - if (recved == 0) { - stream->flags &= ~EVCOM_READABLE; - ev_io_stop(D_LOOP_(stream) &stream->read_watcher); - stream->recv_action = stream_recv__wait_for_close; - } - - /* NOTE: EOF is signaled with recved == 0 on callback */ - if (stream->on_read) stream->on_read(stream, buf, recved); - - if (recved == 0) { - return OKAY; - } - } - return AGAIN; -} - -static int -stream_send__data (evcom_stream *stream) -{ - ssize_t sent; - - while (!evcom_queue_empty(&stream->out)) { - assert(WRITABLE(stream)); - - evcom_queue *q = evcom_queue_last(&stream->out); - evcom_buf *buf = evcom_queue_data(q, evcom_buf, queue); - -#if EVCOM_HAVE_GNUTLS - if (SECURE(stream)) { - sent = gnutls_record_send(stream->session, - buf->base + buf->written, - buf->len - buf->written); - - if (sent == GNUTLS_E_INTERRUPTED || sent == GNUTLS_E_AGAIN) { - if (0 == gnutls_record_get_direction((stream)->session)) { - fprintf(stderr, "(evcom) gnutls send: unexpected switch direction!\n"); - ev_io_start(D_LOOP_(stream) &(stream)->read_watcher); - ev_io_stop(D_LOOP_(stream) &(stream)->write_watcher); - } - return AGAIN; - } - - if (gnutls_error_is_fatal(sent)) { - stream->gnutls_errorno = sent; - stream->send_action = stream_send__close; - return OKAY; - } - } else -#endif // EVCOM_HAVE_GNUTLS - { - /* TODO use writev() here? */ - sent = nosigpipe_stream_send(stream, - buf->base + buf->written, - buf->len - buf->written); - } - - if (sent <= 0) { - switch (errno) { - case EAGAIN: - case EINTR: - assert(stream->send_action == stream_send__data); - return AGAIN; - - default: - stream->errorno = errno; - evcom_perror("send()", errno); - /* pass through */ - case EPIPE: - stream->send_action = stream_send__close; - return OKAY; - } - } - - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - - assert(sent >= 0); - - buf->written += sent; - - if (buf->written == buf->len) { - evcom_queue_remove(q); - if (buf->release) buf->release(buf); - } - } - - assert(evcom_queue_empty(&stream->out)); - - stream->send_action = stream_send__drain; - return OKAY; -} - -static int -stream_send__shutdown (evcom_stream *stream) -{ - int r = shutdown(stream->sendfd, SHUT_WR); - - if (r < 0) { - switch (errno) { - case EINTR: - assert(stream->send_action == stream_send__shutdown); - return OKAY; - - case ENOTCONN: - break; - - default: - stream->errorno = errno; - evcom_perror("shutdown()", errno); - break; - } - stream->send_action = stream_send__close; - return OKAY; - } - - stream->flags &= ~EVCOM_WRITABLE; - stream->send_action = stream_send__wait_for_eof; - return OKAY; -} - -static int -stream__connection_established (evcom_stream *stream) -{ - assert(!CONNECTED(stream)); - -#if EVCOM_HAVE_GNUTLS - if (SECURE(stream)) { - stream->send_action = stream__handshake; - stream->recv_action = stream__handshake; - } else -#endif - { - stream->flags |= EVCOM_CONNECTED; - if (stream->on_connect) stream->on_connect(stream); - - stream->send_action = stream_send__data; - stream->recv_action = stream_recv__data; - } - - ev_io_start(D_LOOP_(stream) &stream->write_watcher); - ev_io_start(D_LOOP_(stream) &stream->read_watcher); - - return OKAY; -} - -static int -stream_send__wait_for_connection (evcom_stream *stream) -{ - assert(DUPLEX(stream)); - - int connect_error; - socklen_t len = sizeof(int); - int r = getsockopt(stream->sendfd, SOL_SOCKET, SO_ERROR, &connect_error, &len); - - if (r < 0) { - stream->errorno = r; - stream->send_action = stream_send__close; - return OKAY; - } - - if (connect_error == 0) { - stream->send_action = stream__connection_established; - return OKAY; - - } else if (connect_error == EINPROGRESS || connect_error == EINTR) { - assert(stream->send_action == stream_send__wait_for_connection); - return AGAIN; - } - - stream->errorno = connect_error; - stream->send_action = stream_send__close; - return OKAY; -} - -void -evcom_stream_assign_fds (evcom_stream *stream, int recvfd, int sendfd) -{ - assert(recvfd >= 0); - assert(sendfd >= 0); - - if (recvfd == sendfd) stream->flags |= EVCOM_DUPLEX; - - if (set_nonblock(recvfd) != 0) { - evcom_perror("set_nonblock(recvfd)", errno); - } - - if (set_nonblock(sendfd) != 0) { - evcom_perror("set_nonblock(sendfd)", errno); - } - -#ifdef SO_NOSIGPIPE - if (DUPLEX(stream)) { - int flags = 1; - int r = setsockopt(sendfd, SOL_SOCKET, SO_NOSIGPIPE, &flags, sizeof(flags)); - if (r < 0) { - evcom_perror("setsockopt(SO_NOSIGPIPE)", errno); - } - } -#endif - - ev_io_set(&stream->read_watcher, recvfd, EV_READ); - ev_io_set(&stream->write_watcher, sendfd, EV_WRITE); - - stream->recvfd = recvfd; - stream->sendfd = sendfd; - - stream->send_action = stream__connection_established; - stream->recv_action = stream__connection_established; - - stream->flags |= EVCOM_READABLE; - stream->flags |= EVCOM_WRITABLE; - -#if EVCOM_HAVE_GNUTLS - if (SECURE(stream)) { - gnutls_transport_set_lowat(stream->session, 0); - gnutls_transport_set_push_function(stream->session, nosigpipe_push); - gnutls_transport_set_pull_function(stream->session, pull); - gnutls_transport_set_ptr2(stream->session, stream, stream); - } -#endif -} - -/* Retruns evcom_stream if a connection could be accepted. - * The returned stream is not yet attached to the event loop. - * Otherwise NULL - */ -static evcom_stream* -accept_connection (evcom_server *server) -{ - struct sockaddr address; /* connector's address information */ - socklen_t addr_len = sizeof(address); - - int fd = accept(server->fd, &address, &addr_len); - if (fd < 0) { - switch (errno) { - case EMFILE: - case ENFILE: - too_many_connections = 1; - server->flags |= EVCOM_TOO_MANY_CONN; - evcom_server_detach(server); - return NULL; - - case EINTR: - case EAGAIN: - return NULL; - - default: - evcom_perror("accept()", errno); - return NULL; - } - assert(0 && "no reach"); - } - - evcom_stream *stream = NULL; - - if (server->on_connection) { - stream = server->on_connection(server, &address); - } - - if (stream == NULL) { - close(fd); - return NULL; - } - - if (set_nonblock(fd) != 0) { - evcom_perror("set_nonblock()", errno); - return NULL; - } - - stream->server = server; - evcom_stream_assign_fds(stream, fd, fd); - - return stream; -} - -/* Internal callback - * Called by server->watcher. - */ -static int -accept_connections (evcom_descriptor *d) -{ - evcom_server *server = (evcom_server *)d; - - assert(LISTENING(server)); - - /* accept as many connections as possible */ - evcom_stream *stream; - while (server->fd >= 0 && (stream = accept_connection(server))) { - evcom_stream_attach(D_LOOP_(server) stream); - } - - return AGAIN; -} - -static inline socklen_t -address_length (struct sockaddr *address) -{ - struct sockaddr_un* unix_address = (struct sockaddr_un*)address; - int length = 0; - - switch (address->sa_family) { - case AF_INET: - length = sizeof(struct sockaddr_in); - break; - case AF_INET6: - length = sizeof(struct sockaddr_in6); - break; - case AF_UNIX: -#ifdef SUN_LEN - length = SUN_LEN(unix_address); -#else - length = strlen(unix_address->sun_path) + sizeof(unix_address->sun_family); -#endif - break; - - default: - assert(0 && "Unsupported socket family"); - } - return length; -} - -int -evcom_server_listen (evcom_server *server, struct sockaddr *address, int backlog) -{ - assert(!LISTENING(server)); - - int fd = socket(address->sa_family, SOCK_STREAM, 0); - if (fd < 0) { - server->errorno = errno; - evcom_perror("socket()", errno); - return -1; - } - - server->fd = fd; - ev_io_set(&server->watcher, server->fd, EV_READ); - - if (set_nonblock(fd) != 0) { - server->errorno = errno; - evcom_perror("set_nonblock()", errno); - close(fd); - return -1; - } - - int flags = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags)); - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)); - - /* XXX: Sending single byte chunks in a response body? Perhaps there is a - * need to enable the Nagel algorithm dynamically. For now disabling. - */ - //setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)); - - if (bind(fd, address, address_length(address)) < 0) { - server->errorno = errno; - evcom_perror("bind()", errno); - close(fd); - return -1; - } - - if (listen(fd, backlog) < 0) { - server->errorno = errno; - evcom_perror("listen()", errno); - close(fd); - return -1; - } - - server->flags |= EVCOM_LISTENING; - server->action = accept_connections; - - return 0; -} - -/** - * Stops the server. Will not accept new connections. Does not drop - * existing connections. - */ -void -evcom_server_close (evcom_server *server) -{ - ev_io_start(D_LOOP_(server) &server->watcher); - ev_feed_event(D_LOOP_(server) &server->watcher, EV_READ); - - close_asap((evcom_descriptor*)server); -} - -void -evcom_server_attach (EV_P_ evcom_server *server) -{ - ev_io_start (EV_A_ &server->watcher); - D_LOOP_SET(server, EV_A); - server->flags |= EVCOM_ATTACHED; -} - -void -evcom_server_detach (evcom_server *server) -{ - ev_io_stop (D_LOOP_(server) &server->watcher); - D_LOOP_SET(server, NULL); - server->flags &= ~EVCOM_ATTACHED; -} - -static void -io_event(EV_P_ ev_io *watcher, int revents) -{ - evcom_descriptor *d = watcher->data; - -#if EV_MULTIPLICITY - assert(d->loop == loop); -#endif - - int r = OKAY; - - if (revents & EV_ERROR) { - d->errorno = 1; - r = close_asap(d); - } - - while (r == OKAY && d->action && d->fd >= 0) { - r = d->action(d); - } - - if (d->fd < 0) { - assert(d->action == NULL); - ev_clear_pending(EV_A_ watcher); - ev_io_stop(EV_A_ watcher); - if (d->on_close) d->on_close(d); - } -} - -static void -evcom_descriptor_init (evcom_descriptor *d) -{ - d->fd = -1; - D_LOOP_SET(d, NULL); - d->flags = 0; - d->errorno = 0; - d->action = NULL; -} - -void -evcom_server_init (evcom_server *server) -{ - evcom_descriptor_init((evcom_descriptor*)server); - ev_init (&server->watcher, io_event); - server->watcher.data = server; - server->on_connection = NULL; -} - -/* Internal callback. called by stream->timeout_watcher */ -static void -on_timeout (EV_P_ ev_timer *watcher, int revents) -{ - evcom_stream *stream = watcher->data; - -#if EV_MULTIPLICITY - assert(stream->loop == loop); -#endif - assert(revents == EV_TIMEOUT); - assert(watcher == &stream->timeout_watcher); - - if (PAUSED(stream)) { - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - return; - } - - if (stream->on_timeout) stream->on_timeout(stream); - - // Hack to get error in Node on 'close' event. - // should probably be made into a proper error code. - stream->errorno = 1; - - ev_timer_stop(EV_A_ watcher); - evcom_stream_force_close(stream); - - if (stream->on_close) stream->on_close(stream); -} - -static void -stream_event (EV_P_ ev_io *w, int revents) -{ - evcom_stream *stream = w->data; - - if (revents & EV_READ) { - while (stream->recv_action) { - int r = stream->recv_action(stream); - if (r == AGAIN) break; - } - } - - if (revents & EV_WRITE) { - while (stream->send_action) { - int r = stream->send_action(stream); - if (r == AGAIN) break; - } - } - - if (stream->send_action == NULL) { - ev_io_stop(EV_A_ &stream->write_watcher); - } - - if (stream->recv_action == NULL) { - ev_io_stop(EV_A_ &stream->read_watcher); - } - - if (stream->sendfd < 0 && stream->recvfd < 0) { - ev_timer_stop(EV_A_ &stream->timeout_watcher); - - if (stream->server && (stream->server->flags & EVCOM_TOO_MANY_CONN)) { -#if EV_MULTIPLICITY - struct ev_loop *loop = stream->server->loop; -#endif - stream->server->flags &= ~EVCOM_TOO_MANY_CONN; - evcom_server_attach(EV_A_ stream->server); - } - too_many_connections = 0; - - if (stream->on_close) stream->on_close(stream); - } -} - -/** - * If using SSL do consider setting - * gnutls_db_set_retrieve_function (stream->session, _); - * gnutls_db_set_remove_function (stream->session, _); - * gnutls_db_set_store_function (stream->session, _); - * gnutls_db_set_ptr (stream->session, _); - */ -void -evcom_stream_init (evcom_stream *stream) -{ - stream->flags = 0; - stream->errorno = 0; - stream->recvfd = -1; - stream->sendfd = -1; - - // reader things - ev_init(&stream->read_watcher, stream_event); - stream->read_watcher.data = stream; - stream->recv_action = NULL; - - // writer things - ev_init(&stream->write_watcher, stream_event); - stream->write_watcher.data = stream; - evcom_queue_init(&stream->out); - stream->send_action = NULL; - - // stream things - stream->server = NULL; -#if EVCOM_HAVE_GNUTLS - stream->gnutls_errorno = 0; - stream->session = NULL; -#endif - ev_timer_init(&stream->timeout_watcher, on_timeout, 0., 60.); - stream->timeout_watcher.data = stream; - - stream->on_connect = NULL; - stream->on_timeout = NULL; - stream->on_read = NULL; - stream->on_drain = NULL; - stream->on_close = NULL; -} - -void -evcom_stream_close (evcom_stream *stream) -{ - stream->flags |= EVCOM_GOT_CLOSE; - if (ATTACHED(stream)) { - // start the watchers if attached. - evcom_stream_attach(D_LOOP_(stream) stream); - } -} - -void evcom_stream_force_close (evcom_stream *stream) -{ - if (stream->recvfd >= 0) { - close(stream->recvfd); - /* XXX What to do on EINTR? */ - stream__set_recv_closed(stream); - } - - if (!DUPLEX(stream) && stream->sendfd >= 0) { - close(stream->sendfd); - } - stream__set_send_closed(stream); - - evcom_stream_detach(stream); -} - -/* Returns the number of bytes flushed to the buffer */ -ssize_t -evcom_stream_write (evcom_stream *stream, const char *str, size_t len) -{ - if (!WRITABLE(stream) || GOT_CLOSE(stream)) { - assert(0 && "Do not write to a closed stream"); - return -1; - } - - ssize_t sent = 0; - - if ( stream->send_action == stream_send__wait_for_buf - && evcom_queue_empty(&stream->out) - ) - { - assert(CONNECTED(stream)); -#if EVCOM_HAVE_GNUTLS - if (SECURE(stream)) { - sent = gnutls_record_send(stream->session, str, len); - - if (gnutls_error_is_fatal(sent)) { - stream->gnutls_errorno = sent; - goto close; - } - } else -#endif // EVCOM_HAVE_GNUTLS - { - /* TODO use writev() here? */ - sent = nosigpipe_stream_send(stream, str, len); - } - - if (sent < 0) { - switch (errno) { - case EPIPE: - goto close; - - case EINTR: - case EAGAIN: - sent = 0; - break; - - default: - stream->errorno = errno; - evcom_perror("send()", stream->errorno); - goto close; - } - } - } /* TODO else { memcpy to last buffer on head } */ - - assert(sent >= 0); - if ((size_t)sent == len) return sent; /* sent the whole buffer */ - - len -= sent; - str += sent; - - evcom_buf *b = evcom_buf_new(str, len); - evcom_queue_insert_head(&stream->out, &b->queue); - b->written = 0; - - assert(stream->sendfd >= 0); - - if (ATTACHED(stream)) { - ev_io_start(D_LOOP_(stream) &stream->write_watcher); - } - return sent; - -close: - stream->send_action = stream_send__close; - stream->recv_action = stream_recv__close; - if (ATTACHED(stream)) { - ev_io_start(D_LOOP_(stream) &stream->write_watcher); - } - return -1; -} - -void -evcom_stream_reset_timeout (evcom_stream *stream, float timeout) -{ - stream->timeout_watcher.repeat = timeout; - if (ATTACHED(stream)) { - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - } -} - -void -evcom_stream_set_no_delay (evcom_stream *stream, int no_delay) -{ - if (DUPLEX(stream)) { - int flags = no_delay ? 1 : 0; - setsockopt(stream->recvfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)); - } -} - -void -evcom_stream_attach (EV_P_ evcom_stream *stream) -{ - D_LOOP_SET(stream, EV_A); - stream->flags |= EVCOM_ATTACHED; - - ev_timer_again(EV_A_ &stream->timeout_watcher); - - if (READABLE(stream)) { - ev_io_start(EV_A_ &stream->read_watcher); - } - - if (WRITABLE(stream)) { - ev_io_start(EV_A_ &stream->write_watcher); - } -} - -void -evcom_stream_detach (evcom_stream *stream) -{ - ev_io_stop(D_LOOP_(stream) &stream->write_watcher); - ev_io_stop(D_LOOP_(stream) &stream->read_watcher); - ev_timer_stop(D_LOOP_(stream) &stream->timeout_watcher); - D_LOOP_SET(stream, NULL); - stream->flags &= ~EVCOM_ATTACHED; -} - -void -evcom_stream_read_pause (evcom_stream *stream) -{ - stream->flags |= EVCOM_PAUSED; - ev_timer_stop(D_LOOP_(stream) &stream->timeout_watcher); - if (stream->recv_action == stream_recv__data) { - ev_io_stop(D_LOOP_(stream) &stream->read_watcher); - stream->recv_action = stream_recv__wait_for_resume; - } -} - -void -evcom_stream_read_resume (evcom_stream *stream) -{ - stream->flags &= ~EVCOM_PAUSED; - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - if (stream->recv_action == stream_recv__wait_for_resume) { - stream->recv_action = stream_recv__data; - } - if (ATTACHED(stream)) { - ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher); - if (READABLE(stream)) ev_io_start(D_LOOP_(stream) &stream->read_watcher); - } -} - -int -evcom_stream_connect (evcom_stream *stream, struct sockaddr *address) -{ - int fd = socket(address->sa_family, SOCK_STREAM, 0); - - if (fd < 0) { - evcom_perror("socket()", errno); - return -1; - } - - int r = set_nonblock(fd); - if (r < 0) { - stream->errorno = errno; - evcom_perror("set_nonblock()", errno); - close(fd); - return -1; - } - - r = connect(fd, address, address_length(address)); - - if (r < 0 && errno != EINPROGRESS) { - stream->errorno = errno; - evcom_perror("connect", errno); - close(fd); - return -1; - } - - evcom_stream_assign_fds(stream, fd, fd); - - stream->send_action = stream_send__wait_for_connection; - stream->recv_action = NULL; - - return 0; -} - -int evcom_stream_pair (evcom_stream *a, evcom_stream *b) -{ - int sv[2]; - int old_errno; - - int r = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); - if (r < 0) return -1; - - r = set_nonblock(sv[0]); - if (r < 0) goto set_nonblock_error; - r = set_nonblock(sv[1]); - if (r < 0) goto set_nonblock_error; - - evcom_stream_assign_fds(a, sv[0], sv[0]); - evcom_stream_assign_fds(b, sv[1], sv[1]); - - return 0; - -set_nonblock_error: - old_errno = errno; - evcom_perror("set_nonblock()", errno); - close(sv[0]); - close(sv[1]); - errno = old_errno; - return -1; -} - -enum evcom_stream_state -evcom_stream_state (evcom_stream *stream) -{ - if (stream->recvfd < 0 && stream->sendfd && stream->flags == 0) { - return EVCOM_INITIALIZED; - } - - if (stream->recvfd < 0 && stream->sendfd < 0) return EVCOM_CLOSED; - - if (!CONNECTED(stream)) return EVCOM_CONNECTING; - - if (GOT_CLOSE(stream)) { - if (READABLE(stream)) { - return EVCOM_CONNECTED_RO; - } else { - return EVCOM_CLOSING; - } - } - - if (READABLE(stream) && WRITABLE(stream)) return EVCOM_CONNECTED_RW; - - if (WRITABLE(stream)) return EVCOM_CONNECTED_WO; - - if (READABLE(stream)) return EVCOM_CONNECTED_RO; - - return EVCOM_CLOSING; -} - -static int -reader_recv (evcom_descriptor *d) -{ - evcom_reader* reader = (evcom_reader*) d; - - char buf[EVCOM_CHUNKSIZE]; - size_t buf_size = EVCOM_CHUNKSIZE; - ssize_t recved; - - while (reader->fd >= 0) { - recved = read(reader->fd, buf, buf_size); - - if (recved < 0) { - if (errno == EAGAIN || errno == EINTR) return AGAIN; - reader->errorno = errno; - evcom_perror("read()", reader->errorno); - return close_asap(d); - } - - /* NOTE: EOF is signaled with recved == 0 on callback */ - if (reader->on_read) reader->on_read(reader, buf, recved); - - if (recved == 0) return close_asap(d); - } - return AGAIN; -} - -void -evcom_reader_init (evcom_reader *reader) -{ - evcom_descriptor_init((evcom_descriptor*)reader); - - reader->on_close = NULL; - reader->on_read = NULL; - - ev_init(&reader->read_watcher, io_event); - reader->read_watcher.data = reader; -} - -void -evcom_reader_set (evcom_reader *reader, int fd) -{ - assert(fd >= 0); - reader->fd = fd; - - ev_io_set(&reader->read_watcher, fd, EV_READ); - reader->action = reader_recv; -} - -void -evcom_reader_attach (EV_P_ evcom_reader *reader) -{ - ev_io_start(EV_A_ &reader->read_watcher); - D_LOOP_SET(reader, EV_A); -} - -void -evcom_reader_detach (evcom_reader *reader) -{ - ev_io_stop(D_LOOP_(reader) &reader->read_watcher); - D_LOOP_SET(reader, NULL); -} - -void -evcom_reader_close (evcom_reader *reader) -{ - ev_io_start(D_LOOP_(reader) &reader->read_watcher); - ev_feed_event(D_LOOP_(reader) &reader->read_watcher, EV_READ); - - close_asap((evcom_descriptor*)reader); -} - -static int -writer_send (evcom_descriptor *d) -{ - evcom_writer* writer = (evcom_writer*) d; - assert(writer->fd >= 0); - - while (!evcom_queue_empty(&writer->out)) { - evcom_queue *q = evcom_queue_last(&writer->out); - evcom_buf *buf = evcom_queue_data(q, evcom_buf, queue); - - ssize_t sent = write(writer->fd, buf->base + buf->written, - buf->len - buf->written); - - if (sent < 0) { - switch (errno) { - case ECONNRESET: - case EPIPE: - return close_writer_asap(writer); - - case EINTR: - case EAGAIN: - sent = 0; - return AGAIN; - - default: - writer->errorno = errno; - evcom_perror("send()", writer->errorno); - return close_writer_asap(writer); - } - } - assert(sent >= 0); - - buf->written += sent; - - if (buf->written == buf->len) { - evcom_queue_remove(q); - if (buf->release) buf->release(buf); - } - } - - if (GOT_CLOSE(writer)) { - assert(evcom_queue_empty(&writer->out)); - return close_writer_asap(writer); - } else { - ev_io_stop(D_LOOP_(writer) &writer->write_watcher); - return AGAIN; - } -} - -void -evcom_writer_init (evcom_writer* writer) -{ - evcom_descriptor_init((evcom_descriptor*)writer); - - writer->on_close = NULL; - - ev_init(&writer->write_watcher, io_event); - writer->write_watcher.data = writer; - - evcom_queue_init(&writer->out); -} - -void -evcom_writer_set (evcom_writer* writer, int fd) -{ - assert(fd >= 0); - writer->fd = fd; - - ev_io_set(&writer->write_watcher, fd, EV_WRITE); - writer->action = writer_send; -} - -void -evcom_writer_attach (EV_P_ evcom_writer* writer) -{ - if (!evcom_queue_empty(&writer->out)) { - ev_io_start (EV_A_ &writer->write_watcher); - } - D_LOOP_SET(writer, EV_A); -} - -void -evcom_writer_detach (evcom_writer* writer) -{ - ev_io_stop(D_LOOP_(writer) &writer->write_watcher); - D_LOOP_SET(writer, NULL); -} - -void -evcom_writer_write (evcom_writer* writer, const char* buf, size_t len) -{ - assert(writer->fd >= 0); - - ssize_t sent = 0; - - if (evcom_queue_empty(&writer->out)) { - sent = write(writer->fd, buf, len); - - if (sent < 0) { - switch (errno) { - case ECONNRESET: - case EPIPE: - goto close; - - case EINTR: - case EAGAIN: - sent = 0; - break; - - default: - writer->errorno = errno; - evcom_perror("send()", writer->errorno); - goto close; - } - } - } /* TODO else { memcpy to last buffer on head } */ - - assert(sent >= 0); - if ((size_t)sent == len) return; /* sent the whole buffer */ - - len -= sent; - buf += sent; - - evcom_buf *b = evcom_buf_new(buf, len); - evcom_queue_insert_head(&writer->out, &b->queue); - b->written = 0; - - assert(writer->fd >= 0); - ev_io_start(D_LOOP_(writer) &writer->write_watcher); - return; - -close: - close_writer_asap(writer); -} - -void -evcom_writer_close (evcom_writer* writer) -{ - writer->flags |= EVCOM_GOT_CLOSE; - if (evcom_queue_empty(&writer->out)) close_writer_asap(writer); -} diff --git a/deps/evcom/evcom.h b/deps/evcom/evcom.h deleted file mode 100644 index 3b07289fb5..0000000000 --- a/deps/evcom/evcom.h +++ /dev/null @@ -1,260 +0,0 @@ -/* Copyright (c) 2008,2009 Ryan Dahl - * - * evcom_queue comes from Nginx, ngx_queue.h - * Copyright (C) 2002-2009 Igor Sysoev - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include /* offsetof() */ - -#ifndef evcom_h -#define evcom_h - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef EVCOM_HAVE_GNUTLS -# define EVCOM_HAVE_GNUTLS 0 -#endif -#if EVCOM_HAVE_GNUTLS -# include -#endif - -/* The maximum evcom_stream will try to read in one callback */ -#ifndef EVCOM_CHUNKSIZE -# define EVCOM_CHUNKSIZE (8*1024) -#endif - -/* flags for stream and server */ -#define EVCOM_ATTACHED 0x0001 -#define EVCOM_LISTENING 0x0002 -#define EVCOM_CONNECTED 0x0004 -#define EVCOM_SECURE 0x0008 -#define EVCOM_DUPLEX 0x0010 -#define EVCOM_GOT_CLOSE 0x0020 -#define EVCOM_PAUSED 0x0040 -#define EVCOM_READABLE 0x0080 -#define EVCOM_WRITABLE 0x0100 -#define EVCOM_TOO_MANY_CONN 0x0200 - -enum evcom_stream_state { EVCOM_INITIALIZED - , EVCOM_CONNECTING - , EVCOM_CONNECTED_RW /* read write */ - , EVCOM_CONNECTED_RO /* read only */ - , EVCOM_CONNECTED_WO /* write only */ - , EVCOM_CLOSING - , EVCOM_CLOSED - }; - -typedef struct evcom_queue { - struct evcom_queue *prev; - struct evcom_queue *next; -} evcom_queue; - -typedef struct evcom_buf { - /* public */ - char *base; - size_t len; - void (*release) (struct evcom_buf *); /* called when oi is done with the object */ - void *data; - - /* private */ - size_t written; - evcom_queue queue; -} evcom_buf; - -#if EV_MULTIPLICITY -# define EVCOM_LOOP struct ev_loop *loop; -#else -# define EVCOM_LOOP -#endif - -#define EVCOM_DESCRIPTOR(type) \ - /* private */ unsigned int flags; \ - /* private */ int (*action) (struct evcom_descriptor*); \ - /* read-only */ int errorno; \ - /* read-only */ int fd; \ - /* read-only */ EVCOM_LOOP \ - /* public */ void *data; \ - /* public */ void (*on_close) (struct type*); - -/* abstract base class */ -typedef struct evcom_descriptor { - EVCOM_DESCRIPTOR(evcom_descriptor) -} evcom_descriptor; - -typedef struct evcom_reader { - EVCOM_DESCRIPTOR(evcom_reader) - ev_io read_watcher; /* private */ - void (*on_read) (struct evcom_reader*, const void* buf, size_t len); /* public */ -} evcom_reader; - -typedef struct evcom_writer { - EVCOM_DESCRIPTOR(evcom_writer) - ev_io write_watcher; /* private */ - evcom_queue out; /* private */ -} evcom_writer; - -typedef struct evcom_stream { - /* PRIVATE */ - EVCOM_LOOP - int errorno; - unsigned int flags; - evcom_queue out; - ev_io read_watcher; - ev_io write_watcher; - int (*send_action) (struct evcom_stream*); - int (*recv_action) (struct evcom_stream*); - ev_timer timeout_watcher; -#if EVCOM_HAVE_GNUTLS - gnutls_session_t session; -#endif - - /* READ-ONLY */ - int recvfd; - int sendfd; - struct evcom_server *server; -#if EVCOM_HAVE_GNUTLS - int gnutls_errorno; -#endif - - /* PUBLIC */ - void (*on_connect) (struct evcom_stream *); - void (*on_timeout) (struct evcom_stream *); - void (*on_read) (struct evcom_stream *, const void* buf, size_t len); - void (*on_drain) (struct evcom_stream *); - void (*on_close) (struct evcom_stream *); - void *data; -} evcom_stream; - -typedef struct evcom_server { - EVCOM_DESCRIPTOR(evcom_server) - - /* PRIVATE */ - ev_io watcher; - - /* PUBLIC */ - struct evcom_stream* - (*on_connection)(struct evcom_server *, struct sockaddr *remote_addr); -} evcom_server; - -/* Highly recommended to ignore SIGPIPE! */ -void evcom_ignore_sigpipe (void); - -void evcom_reader_init (evcom_reader*); -void evcom_reader_set (evcom_reader*, int fd); -void evcom_reader_attach (EV_P_ evcom_reader*); -void evcom_reader_detach (evcom_reader*); -void evcom_reader_close (evcom_reader*); - -void evcom_writer_init (evcom_writer*); -void evcom_writer_set (evcom_writer*, int fd); -void evcom_writer_attach (EV_P_ evcom_writer*); -void evcom_writer_detach (evcom_writer*); -void evcom_writer_write (evcom_writer*, const char *str, size_t len); -void evcom_writer_close (evcom_writer*); - -void evcom_server_init (evcom_server *); - int evcom_server_listen (evcom_server *, struct sockaddr *address, int backlog); -void evcom_server_attach (EV_P_ evcom_server *); -void evcom_server_detach (evcom_server *); -void evcom_server_close (evcom_server *); - -void evcom_stream_init (evcom_stream *); - - int evcom_stream_pair (evcom_stream *a, evcom_stream *b); - int evcom_stream_connect (evcom_stream *, struct sockaddr *address); -void evcom_stream_assign_fds (evcom_stream *, int recvfd, int sendfd); - -void evcom_stream_attach (EV_P_ evcom_stream *); -void evcom_stream_detach (evcom_stream *); -void evcom_stream_read_resume (evcom_stream *); -void evcom_stream_read_pause (evcom_stream *); -void evcom_stream_reset_timeout (evcom_stream *, float timeout); -void evcom_stream_set_no_delay (evcom_stream *, int no_delay); -ssize_t evcom_stream_write (evcom_stream *, const char *str, size_t len); -/* Once the write buffer is drained, evcom_stream_close will shutdown the - * writing end of the stream and will close the read end once the server - * replies with an EOF. - */ -void evcom_stream_close (evcom_stream *); - -/* Will not wait for the write queue to complete. Closes both directions */ -void evcom_stream_force_close (evcom_stream *); - - -#if EVCOM_HAVE_GNUTLS -/* Tells the stream to use transport layer security (SSL). evcom_stream does - * not want to make any decisions about security requirements, so the - * majoirty of GnuTLS configuration is left to the user. Only the transport - * layer of GnuTLS is controlled by evcom_stream. That is, do not use - * gnutls_transport_* functions. Do use the rest of GnuTLS's API. - */ -void evcom_stream_set_secure_session (evcom_stream *, gnutls_session_t); -#endif - -enum evcom_stream_state evcom_stream_state (evcom_stream *stream); - -evcom_buf* evcom_buf_new (const char* base, size_t len); -evcom_buf* evcom_buf_new2 (size_t len); - -EV_INLINE void -evcom_queue_init (evcom_queue *q) -{ - q->prev = q; - q->next = q; -} - -EV_INLINE void -evcom_queue_insert_head (evcom_queue *h, evcom_queue *x) -{ - (x)->next = (h)->next; - (x)->next->prev = x; - (x)->prev = h; - (h)->next = x; -} - -EV_INLINE void -evcom_queue_remove (evcom_queue *x) -{ - (x)->next->prev = (x)->prev; - (x)->prev->next = (x)->next; -#ifndef NDEBUG - (x)->prev = NULL; - (x)->next = NULL; -#endif -} - -#define evcom_queue_empty(h) (h == (h)->prev) -#define evcom_queue_head(h) (h)->next -#define evcom_queue_last(h) (h)->prev -#define evcom_queue_data(q, type, link) \ - (type *) ((unsigned char *) q - offsetof(type, link)) - - -#ifdef __cplusplus -} -#endif -#endif /* evcom_h */ diff --git a/deps/evcom/recv_states.dot b/deps/evcom/recv_states.dot deleted file mode 100644 index 52f9624230..0000000000 --- a/deps/evcom/recv_states.dot +++ /dev/null @@ -1,37 +0,0 @@ -strict digraph recv_states { - start [peripheries=2]; - end [peripheries=2]; - handshake; - recv_data; - wait_for_resume; - wait_for_close; - close_one; - close_both; - - node [label="", shape="box", height=0.1, width=0.1]; - close; - - - - start -> handshake [label="tls"]; - start -> recv_data; - - handshake -> close [label="error"]; - handshake -> recv_data; - - recv_data -> handshake [label="rehandshake"]; - recv_data -> wait_for_resume [label="pause"]; - recv_data -> wait_for_close [label="eof"]; - recv_data -> close [label="error"]; - - wait_for_resume -> recv_data; - - wait_for_close -> close; - - close -> close_one [label="duplex"]; - close -> close_both; - - close_one -> end; - close_both -> end; - -} diff --git a/deps/evcom/send_states.dot b/deps/evcom/send_states.dot deleted file mode 100644 index bb913736c0..0000000000 --- a/deps/evcom/send_states.dot +++ /dev/null @@ -1,65 +0,0 @@ -strict digraph send_states { - start [peripheries=2]; - end [peripheries=2]; - connection_established; - handshake; - send_data; - shutdown; - gnutls_bye; - close_one; - close_both; - - wait_for_connect; - wait_for_buf; - wait_for_eof; - - node [label="", shape="box", height=0.1, width=0.1]; - close; - drain; - hangup; - hangup_unsecure; - - - - start -> wait_for_connect [label="duplex"]; - start -> connection_established; - - wait_for_connect -> connection_established; - wait_for_connect -> close [label="error"]; - - connection_established -> handshake [label="tls"]; - connection_established -> send_data; - - handshake -> close [label="error"]; - handshake -> send_data; - - send_data -> close [label="error"]; - send_data -> drain [label="drain"]; - - drain -> wait_for_buf; - drain -> hangup [label="got_close"]; - - wait_for_buf -> send_data; - wait_for_buf -> drain [label="empty_buf"]; - - hangup -> gnutls_bye [label="tls"]; - hangup -> hangup_unsecure; - - gnutls_bye -> wait_for_eof; - gnutls_bye -> close [label="error"]; - - hangup_unsecure -> shutdown [label="duplex"]; - hangup_unsecure -> close_one; - - shutdown -> wait_for_eof; - shutdown -> close [label="error"]; - - wait_for_eof -> close_one; - close_one -> wait_for_eof [label="readable"]; - - close -> close_both; - close -> close_one [label="duplex"]; - - close_both -> end; - close_one -> end; -} diff --git a/deps/evcom/test/echo.c b/deps/evcom/test/echo.c deleted file mode 100644 index 15c17b3ced..0000000000 --- a/deps/evcom/test/echo.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#include -#include -#if EVCOM_HAVE_GNUTLS -# include -#endif - -#define HOST "127.0.0.1" -#define SOCKFILE "/tmp/oi.sock" -#define PORT 5000 - -static int nconnections; - -static void -on_peer_close (evcom_stream *stream) -{ - assert(stream->errorno == 0); - //printf("server connection closed\n"); - free(stream); -} - -static void -on_peer_timeout (evcom_stream *stream) -{ - assert(stream); - fprintf(stderr, "peer connection timeout\n"); - assert(0); -} - - - -// timeout must match the timeout in timeout.rb -#define TIMEOUT 5.0 - -static void -on_peer_read (evcom_stream *stream, const void *base, size_t len) -{ - if(len == 0) return; - - evcom_stream_write(stream, base, len); -} - -static evcom_stream* -on_server_connection (evcom_server *server, struct sockaddr *addr) -{ - assert(server); - assert(addr); - - evcom_stream *stream = malloc(sizeof(evcom_stream)); - evcom_stream_init(stream); - stream->on_read = on_peer_read; - stream->on_close = on_peer_close; - stream->on_timeout = on_peer_timeout; - evcom_stream_reset_timeout(stream, TIMEOUT); - - nconnections++; - - - //printf("on server connection\n"); - - return stream; -} - -int -main (void) -{ - int r; - evcom_server server; - - //printf("sizeof(evcom_server): %d\n", sizeof(evcom_server)); - //printf("sizeof(evcom_stream): %d\n", sizeof(evcom_stream)); - - evcom_server_init(&server); - server.on_connection = on_server_connection; - - struct sockaddr_in address; - memset(&address, 0, sizeof(struct sockaddr_in)); - address.sin_family = AF_INET; - address.sin_port = htons(PORT); - address.sin_addr.s_addr = INADDR_ANY; - - r = evcom_server_listen(&server, (struct sockaddr*)&address, 10); - assert(r == 0); - evcom_server_attach(EV_DEFAULT_ &server); - - ev_loop(EV_DEFAULT_ 0); - - return 0; -} diff --git a/deps/evcom/test/test.c b/deps/evcom/test/test.c deleted file mode 100644 index cbfd7bb3ce..0000000000 --- a/deps/evcom/test/test.c +++ /dev/null @@ -1,892 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#if EVCOM_HAVE_GNUTLS -# include -#endif - -#undef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -#undef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -#define MARK_PROGRESS(c,cur,max) \ - if (cur % (MAX(max,50)/50) == 0) write(STDERR_FILENO, c, 1) - -#define SOCKFILE "/tmp/oi.sock" -#define PORT 5000 - -static evcom_server server; -static int nconnections; -static int use_tls; -static int got_server_close; - -static void -common_on_server_close (evcom_server *s) -{ - printf("server on_close\n"); - assert(s == &server); - assert(s->errorno == 0); - got_server_close = 1; - evcom_server_detach(s); -} - -static void -common_on_peer_close (evcom_stream *stream) -{ - assert(EVCOM_CLOSED == evcom_stream_state(stream)); - assert(stream->errorno == 0); - printf("server connection closed\n"); -#if EVCOM_HAVE_GNUTLS - assert(stream->gnutls_errorno == 0); - if (use_tls) gnutls_deinit(stream->session); -#endif - evcom_stream_detach(stream); - free(stream); -} - -static void -common_on_client_timeout (evcom_stream *stream) -{ - assert(stream); - printf("client connection timeout\n"); -} - -static void -common_on_peer_timeout (evcom_stream *stream) -{ - assert(stream); - fprintf(stderr, "peer connection timeout\n"); - assert(0); -} - -#if EVCOM_HAVE_GNUTLS -#define DH_BITS 768 -static gnutls_anon_server_credentials_t server_credentials; -const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; -static gnutls_dh_params_t dh_params; - -void anon_tls_server (evcom_stream *stream) -{ - gnutls_session_t session; - stream->data = session; - - int r = gnutls_init(&session, GNUTLS_SERVER); - assert(r == 0); - gnutls_set_default_priority(session); - gnutls_kx_set_priority (session, kx_prio); - gnutls_credentials_set(session, GNUTLS_CRD_ANON, server_credentials); - gnutls_dh_set_prime_bits(session, DH_BITS); - - evcom_stream_set_secure_session(stream, session); -} - -void anon_tls_client (evcom_stream *stream) -{ - gnutls_session_t client_session; - gnutls_anon_client_credentials_t client_credentials; - - gnutls_anon_allocate_client_credentials (&client_credentials); - gnutls_init(&client_session, GNUTLS_CLIENT); - gnutls_set_default_priority(client_session); - gnutls_kx_set_priority(client_session, kx_prio); - /* Need to enable anonymous KX specifically. */ - gnutls_credentials_set(client_session, GNUTLS_CRD_ANON, client_credentials); - - evcom_stream_set_secure_session(stream, client_session); - assert(stream->flags & EVCOM_SECURE); -} - -#endif // EVCOM_HAVE_GNUTLS - - - - - -#define PING "PING" -#define PONG "PONG" -#define EXCHANGES 500 -#define PINGPONG_TIMEOUT 5.0 - -static int successful_ping_count; - -static void -pingpong_on_peer_read (evcom_stream *stream, const void *base, size_t len) -{ - if (len == 0) { - evcom_stream_close(stream); - return; - } - - char buf[2000]; - strncpy(buf, base, len); - buf[len] = 0; - printf("server got message: %s\n", buf); - - evcom_stream_write(stream, PONG, sizeof PONG); -} - -static void -pingpong_on_client_close (evcom_stream *stream) -{ - assert(EVCOM_CLOSED == evcom_stream_state(stream)); - assert(stream); - printf("client connection closed\n"); - evcom_server_close(&server); - evcom_stream_detach(stream); -} - -static evcom_stream* -pingpong_on_server_connection (evcom_server *_server, struct sockaddr *addr) -{ - assert(_server == &server); - assert(addr); - - evcom_stream *stream = malloc(sizeof(evcom_stream)); - evcom_stream_init(stream); - stream->on_read = pingpong_on_peer_read; - stream->on_close = common_on_peer_close; - stream->on_timeout = common_on_peer_timeout; - evcom_stream_reset_timeout(stream, PINGPONG_TIMEOUT); - - assert(EVCOM_INITIALIZED == evcom_stream_state(stream)); - - nconnections++; - -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_server(stream); -#endif - - printf("on server connection\n"); - - return stream; -} - -static void -pingpong_on_client_connect (evcom_stream *stream) -{ - printf("client connected. sending ping\n"); - evcom_stream_write(stream, PING, sizeof PING); - assert(EVCOM_CONNECTED_RW == evcom_stream_state(stream)); -} - -static void -pingpong_on_client_read (evcom_stream *stream, const void *base, size_t len) -{ - if(len == 0) { - evcom_stream_close(stream); - return; - } - - assert(len = strlen(PONG)); - - char buf[len+1]; - strncpy(buf, base, len); - buf[len] = 0; - printf("client got message: %s\n", buf); - - assert(strcmp(buf, PONG) == 0); - - if (++successful_ping_count > EXCHANGES) { - evcom_stream_close(stream); - return; - } - - MARK_PROGRESS(".", successful_ping_count, EXCHANGES); - - evcom_stream_write(stream, PING, sizeof PING); -} - -int -pingpong (struct sockaddr *address) -{ - int r; - evcom_stream client; - - successful_ping_count = 0; - nconnections = 0; - got_server_close = 0; - - evcom_server_init(&server); - server.on_connection = pingpong_on_server_connection; - server.on_close = common_on_server_close; - - r = evcom_server_listen(&server, address, 10); - assert(r == 0); - evcom_server_attach(EV_DEFAULT_ &server); - - evcom_stream_init(&client); - client.on_read = pingpong_on_client_read; - client.on_connect = pingpong_on_client_connect; - client.on_close = pingpong_on_client_close; - client.on_timeout = common_on_client_timeout; - evcom_stream_reset_timeout(&client, PINGPONG_TIMEOUT); - - assert(EVCOM_INITIALIZED == evcom_stream_state(&client)); - -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_client(&client); -#endif - - r = evcom_stream_connect(&client, address); - assert(r == 0 && "problem connecting"); - evcom_stream_attach(EV_DEFAULT_ &client); - - ev_loop(EV_DEFAULT_ 0); - - printf("successful_ping_count = %d\n", successful_ping_count); - assert(successful_ping_count == EXCHANGES + 1); - assert(nconnections == 1); - assert(got_server_close); - - return 0; -} - - - -#define NCONN 50 -#define CONNINT_TIMEOUT 10.0 - -static void -send_bye_and_close(evcom_stream *stream, const void *base, size_t len) -{ - assert(base); - assert(len == 0); - evcom_stream_write(stream, "BYE", 3); - printf("server wrote bye\n"); - evcom_stream_close(stream); -} - -static evcom_stream* -connint_on_connection(evcom_server *_server, struct sockaddr *addr) -{ - assert(_server == &server); - assert(addr); - - evcom_stream *stream = malloc(sizeof(evcom_stream)); - evcom_stream_init(stream); - stream->on_read = send_bye_and_close; - stream->on_close = common_on_peer_close; - stream->on_timeout = common_on_peer_timeout; - evcom_stream_reset_timeout(stream, CONNINT_TIMEOUT); - -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_server(stream); -#endif - - printf("on server connection\n"); - - return stream; -} - -static void -connint_on_client_connect (evcom_stream *stream) -{ - printf("on client connection\n"); - evcom_stream_close(stream); -} - -static void -connint_on_client_close (evcom_stream *stream) -{ - evcom_stream_close(stream); // already closed, but it shouldn't crash if we try to do it again - - printf("client connection closed\n"); - - MARK_PROGRESS(".", nconnections, NCONN); - - if(++nconnections == NCONN) { - evcom_server_close(&server); - printf("closing server\n"); - } - - evcom_stream_detach(stream); -} - -static void -connint_on_client_read (evcom_stream *stream, const void *base, size_t len) -{ - if (len == 0) { - evcom_stream_close(stream); - return; - } - - char buf[200000]; - strncpy(buf, base, len); - buf[len] = 0; - - printf("client got message: %s\n", buf); - - assert(strcmp(buf, "BYE") == 0); - evcom_stream_close(stream); -} - -int -connint (struct sockaddr *address) -{ - int r; - - nconnections = 0; - got_server_close = 0; - - evcom_server_init(&server); - server.on_connection = connint_on_connection; - server.on_close = common_on_server_close; - - evcom_server_listen(&server, address, 1000); - evcom_server_attach(EV_DEFAULT_ &server); - - evcom_stream clients[NCONN]; - int i; - for (i = 0; i < NCONN; i++) { - evcom_stream *client = &clients[i]; - evcom_stream_init(client); - client->on_read = connint_on_client_read; - client->on_connect = connint_on_client_connect; - client->on_close = connint_on_client_close; - client->on_timeout = common_on_client_timeout; - evcom_stream_reset_timeout(client, CONNINT_TIMEOUT); -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_client(client); -#endif - r = evcom_stream_connect(client, address); - assert(r == 0 && "problem connecting"); - evcom_stream_attach(EV_DEFAULT_ client); - } - - ev_loop(EV_DEFAULT_ 0); - - assert(nconnections == NCONN); - assert(got_server_close); - - return 0; -} - - -static evcom_reader reader; -static evcom_writer writer; -static int reader_got_close = 0; -static int reader_got_eof = 0; -static int reader_got_hello = 0; -static int reader_cnt = 0; -static int writer_got_close = 0; -#define PIPE_MSG "hello world" -#define PIPE_CNT 5000 - -static void -reader_read (evcom_reader *r, const void *str, size_t len) -{ - assert(r == &reader); - - if (len == 0) { - reader_got_eof = 1; - return; - } - - assert(len == strlen(PIPE_MSG)); - - if (strncmp(str, PIPE_MSG, strlen(PIPE_MSG)) == 0) { - reader_got_hello = 1; - } - - if (++reader_cnt < PIPE_CNT) { - MARK_PROGRESS(".", reader_cnt, PIPE_CNT); - evcom_writer_write(&writer, PIPE_MSG, strlen(PIPE_MSG)); - } else { - evcom_writer_close(&writer); - } -} - -static void -reader_close (evcom_reader *r) -{ - assert(r == &reader); - reader_got_close = 1; - evcom_reader_detach(r); -} - -static void -writer_close (evcom_writer *w) -{ - assert(w == &writer); - writer_got_close = 1; - evcom_writer_detach(w); -} - -int -pipe_stream (void) -{ - reader_cnt = 0; - reader_got_close = 0; - reader_got_hello = 0; - reader_got_eof = 0; - writer_got_close = 0; - - int pipefd[2]; - int r = pipe(pipefd); - if (r < 0) { - perror("pipe()"); - return -1; - } - - evcom_reader_init(&reader); - reader.on_read = reader_read; - reader.on_close = reader_close; - evcom_reader_set(&reader, pipefd[0]); - evcom_reader_attach(EV_DEFAULT_ &reader); - - evcom_writer_init(&writer); - writer.on_close = writer_close; - evcom_writer_set(&writer, pipefd[1]); - evcom_writer_attach(EV_DEFAULT_ &writer); - - evcom_writer_write(&writer, PIPE_MSG, strlen(PIPE_MSG)); - - ev_loop(EV_DEFAULT_ 0); - - assert(reader_got_close); - assert(reader_got_hello); - assert(reader_got_eof); - assert(writer_got_close); - assert(reader_cnt == PIPE_CNT); - - return 0; -} - -#define PAIR_PINGPONG_TIMEOUT 5000.0 -#define PAIR_PINGPONG_EXCHANGES 50 -static int a_got_close; -static int a_got_connect; -static int b_got_close; -static int b_got_connect; -static int pair_pingpong_cnt; -static evcom_stream a, b; - -void a_connect (evcom_stream *stream) -{ - assert(stream == &a); - a_got_connect = 1; -} - -void a_close (evcom_stream *stream) -{ - evcom_stream_detach(stream); - assert(stream == &a); - a_got_close = 1; - - assert(stream->errorno == 0); -#if EVCOM_HAVE_GNUTLS - if (stream->gnutls_errorno) { - fprintf(stderr, "\nGNUTLS ERROR: %s\n", gnutls_strerror(stream->gnutls_errorno)); - } - assert(stream->gnutls_errorno == 0); - if (use_tls) gnutls_deinit(stream->session); -#endif -} - -void a_read (evcom_stream *stream, const void *buf, size_t len) -{ - assert(stream == &a); - if (len == 0) return; - - assert(len == strlen(PONG)); - assert(strncmp(buf, PONG, strlen(PONG)) == 0); - - if (++pair_pingpong_cnt < PAIR_PINGPONG_EXCHANGES) { - evcom_stream_write(&a, PING, strlen(PING)); - } else if (pair_pingpong_cnt == PAIR_PINGPONG_EXCHANGES) { - evcom_stream_close(stream); - } - - MARK_PROGRESS(".", pair_pingpong_cnt, PAIR_PINGPONG_EXCHANGES); -} - -void b_connect (evcom_stream *stream) -{ - assert(stream == &b); - b_got_connect = 1; -} - -void b_close (evcom_stream *stream) -{ - evcom_stream_detach(stream); - assert(stream == &b); - b_got_close = 1; - - assert(stream->errorno == 0); -#if EVCOM_HAVE_GNUTLS - if (stream->gnutls_errorno) { - fprintf(stderr, "\nGNUTLS ERROR: %s\n", gnutls_strerror(stream->gnutls_errorno)); - } - assert(stream->gnutls_errorno == 0); - if (use_tls) gnutls_deinit(stream->session); -#endif -} - -void b_read (evcom_stream *stream, const void *buf, size_t len) -{ - assert(stream == &b); - if (len == 0) { - evcom_stream_close(stream); - return; - } - - assert(len == strlen(PING)); - assert(strncmp(buf, PING, strlen(PING)) == 0); - - evcom_stream_write(&b, PONG, strlen(PONG)); -} - -int -pair_pingpong (int use_pipe) -{ - a_got_close = 0; - a_got_connect = 0; - b_got_close = 0; - b_got_connect = 0; - pair_pingpong_cnt = 0; - - evcom_stream_init(&a); - a.on_close = a_close; - a.on_connect = a_connect; - a.on_read = a_read; - evcom_stream_reset_timeout(&a, PAIR_PINGPONG_TIMEOUT); -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_client(&a); -#endif - - evcom_stream_init(&b); - b.on_close = b_close; - b.on_connect = b_connect; - b.on_read = b_read; - evcom_stream_reset_timeout(&b, PAIR_PINGPONG_TIMEOUT); -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_server(&b); -#endif - - if (use_pipe) { - int pipeA[2], pipeB[2]; - assert(0 == pipe(pipeA)); - assert(0 == pipe(pipeB)); - - evcom_stream_assign_fds(&a, pipeA[0], pipeB[1]); - evcom_stream_assign_fds(&b, pipeB[0], pipeA[1]); - - } else { - int r = evcom_stream_pair(&a, &b); - assert(r == 0); - } - - evcom_stream_attach(EV_DEFAULT_ &a); - evcom_stream_attach(EV_DEFAULT_ &b); - - evcom_stream_write(&a, PING, strlen(PING)); - - ev_loop(EV_DEFAULT_ 0); - - assert(a_got_close); - assert(a_got_connect); - assert(b_got_close); - assert(b_got_connect); - assert(pair_pingpong_cnt == PAIR_PINGPONG_EXCHANGES); - - return 0; -} - - -static void -free_stream (evcom_stream *stream) -{ - assert(stream->errorno == 0); - free(stream); -} - -#define ZERO_TIMEOUT 50.0 -static size_t zero_to_write = 0; -static size_t zero_written = 0; -static size_t zero_read = 0; -static size_t zero_client_closed = 0; - -static void -error_out (evcom_stream *stream) -{ - assert(stream); - fprintf(stderr, "peer connection timeout\n"); - assert(0); -} - -static void -echo (evcom_stream *stream, const void *base, size_t len) -{ - if(len == 0) { - fprintf(stderr, "close"); - evcom_stream_close(stream); - } else { - evcom_stream_write(stream, base, len); - } -} - -static evcom_stream* -make_echo_connection (evcom_server *server, struct sockaddr *addr) -{ - assert(server); - assert(addr); - - evcom_stream *stream = malloc(sizeof(evcom_stream)); - evcom_stream_init(stream); - stream->on_read = echo; - stream->on_close = free_stream; - stream->on_timeout = error_out; - evcom_stream_reset_timeout(stream, ZERO_TIMEOUT); - -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_server(stream); -#endif - - return stream; -} - - -static void -zero_start (evcom_stream *stream) -{ - evcom_stream_write(stream, "0", 1); - zero_written++; -} - -static void -zero_close (evcom_stream *stream) -{ - assert(stream); - zero_client_closed = 1; -} - -static void -zero_recv (evcom_stream *stream, const void *buf, size_t len) -{ - MARK_PROGRESS("-", zero_read, zero_to_write); - zero_read += len; - - size_t i; - - for (i = 0; i < len; i++) { - assert(((char*)buf)[i] == '0'); - } - - for (i = 0; i < MIN(zero_to_write - zero_written, 90000); i++) { - evcom_stream_write(stream, "0", 1); - zero_written++; - - MARK_PROGRESS(".", zero_written, zero_to_write); - - if (zero_written == zero_to_write) { - - fprintf(stderr, "CLOSE"); - evcom_stream_close(stream); - } - } - - if (len == 0) { - fprintf(stderr, "finish"); - evcom_server_close(&server); - } -} - -int -zero_stream (struct sockaddr *address, size_t to_write) -{ - int r; - - assert(to_write >= 1024); // should be kind of big at least. - zero_to_write = to_write; - got_server_close = 0; - zero_written = 0; - zero_read = 0; - zero_client_closed = 0; - - evcom_server_init(&server); - server.on_connection = make_echo_connection; - server.on_close = common_on_server_close; - - evcom_server_listen(&server, address, 1000); - evcom_server_attach(EV_DEFAULT_ &server); - - evcom_stream client; - evcom_stream_init(&client); - client.on_read = zero_recv; - client.on_connect = zero_start; - client.on_close = zero_close; - client.on_timeout = error_out; - evcom_stream_reset_timeout(&client, ZERO_TIMEOUT); -#if EVCOM_HAVE_GNUTLS - if (use_tls) anon_tls_client(&client); -#endif - r = evcom_stream_connect(&client, address); - assert(r == 0 && "problem connecting"); - evcom_stream_attach(EV_DEFAULT_ &client); - - ev_loop(EV_DEFAULT_ 0); - - assert(got_server_close); - assert(zero_written == zero_to_write); - assert(zero_read == zero_to_write); - assert(zero_client_closed) ; - - return 0; -} - - -struct sockaddr * -create_unix_address (void) -{ - struct stat tstat; - if (lstat(SOCKFILE, &tstat) == 0) { - assert(S_ISSOCK(tstat.st_mode)); - unlink(SOCKFILE); - } - - struct sockaddr_un *address = calloc(1, sizeof(struct sockaddr_un)); - address->sun_family = AF_UNIX; - strcpy(address->sun_path, SOCKFILE); - - return (struct sockaddr*)address; -} - -void -free_unix_address (struct sockaddr *address) -{ - struct stat tstat; - if (lstat(SOCKFILE, &tstat) == 0) { - assert(S_ISSOCK(tstat.st_mode)); - unlink(SOCKFILE); - } - free(address); -} - - -int -main (void) -{ - fprintf(stderr, "sizeof(evcom_server): %d\n", (int)sizeof(evcom_server)); - fprintf(stderr, "sizeof(evcom_stream): %d\n", (int)sizeof(evcom_stream)); - fprintf(stderr, "sizeof(evcom_reader): %d\n", (int)sizeof(evcom_reader)); - fprintf(stderr, "sizeof(evcom_writer): %d\n", (int)sizeof(evcom_writer)); - - evcom_ignore_sigpipe(); - -#if EVCOM_HAVE_GNUTLS - gnutls_global_init(); - - gnutls_dh_params_init (&dh_params); - - fsync((int)stderr); - gnutls_dh_params_generate2 (dh_params, DH_BITS); - - gnutls_anon_allocate_server_credentials (&server_credentials); - gnutls_anon_set_server_dh_params (server_credentials, dh_params); -#endif - - - struct sockaddr_in tcp_address; - memset(&tcp_address, 0, sizeof(struct sockaddr_in)); - tcp_address.sin_family = AF_INET; - tcp_address.sin_port = htons(PORT); - tcp_address.sin_addr.s_addr = INADDR_ANY; - - use_tls = 0; - - fprintf(stderr, "pair_pingpong use_pipe=1: "); - assert(pair_pingpong(1) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "pair_pingpong use_pipe=0: "); - assert(pair_pingpong(0) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "zero_stream tcp: "); - assert(zero_stream((struct sockaddr*)&tcp_address, 5*1024*1024) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "pipe_stream: "); - assert(pipe_stream() == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "pingpong tcp: "); - assert(pingpong((struct sockaddr*)&tcp_address) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "connint tcp: "); - assert(connint((struct sockaddr*)&tcp_address) == 0); - fprintf(stderr, "\n"); - -#if EVCOM_HAVE_GNUTLS - use_tls = 1; - - fprintf(stderr, "zero_stream ssl: "); - assert(zero_stream((struct sockaddr*)&tcp_address, 50*1024) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "pair_pingpong ssl use_pipe=1: "); - assert(pair_pingpong(1) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "pair_pingpong ssl use_pipe=0: "); - assert(pair_pingpong(0) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "pingpong ssl: "); - assert(pingpong((struct sockaddr*)&tcp_address) == 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "connint ssl: "); - assert(connint((struct sockaddr*)&tcp_address) == 0); - fprintf(stderr, "\n"); - -#endif - - struct sockaddr *unix_address; - - use_tls = 0; - - fprintf(stderr, "pingpong unix: "); - unix_address = create_unix_address(); - assert(pingpong(unix_address) == 0); - free_unix_address(unix_address); - fprintf(stderr, "\n"); - - fprintf(stderr, "connint unix: "); - unix_address = create_unix_address(); - assert(connint(unix_address) == 0); - free_unix_address(unix_address); - fprintf(stderr, "\n"); - -#if EVCOM_HAVE_GNUTLS - use_tls = 1; - - fprintf(stderr, "pingpong unix ssl: "); - unix_address = create_unix_address(); - assert(pingpong(unix_address) == 0); - free_unix_address(unix_address); - fprintf(stderr, "\n"); - - fprintf(stderr, "connint unix ssl: "); - unix_address = create_unix_address(); - assert(connint(unix_address) == 0); - free_unix_address(unix_address); - fprintf(stderr, "\n"); -#endif - - return 0; -} diff --git a/deps/evcom/test/timeout.rb b/deps/evcom/test/timeout.rb deleted file mode 100755 index db45d84acb..0000000000 --- a/deps/evcom/test/timeout.rb +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env ruby -require 'socket' - -def test(description) - pid = fork do - exec(File.dirname(__FILE__) + "/echo") - end - - puts "#{description}: " - begin - sleep 0.5 # give time for the server to start - yield(pid) - rescue - puts "\033[1;31mFAIL\033[m" - raise $! - ensure - `kill -9 #{pid}` - end - puts "\033[1;32mPASS\033[m" -end - -test("make sure echo server works") do - socket = TCPSocket.open("localhost", 5000) - w = socket.write("hello"); - raise "error" unless w == 5 - - got = socket.recv(5); - raise "error" unless got == "hello" - - socket.close -end - -test("doing nothing should not timeout the server") do |pid| - 10.times do - print "." - STDOUT.flush - if Process.waitpid(pid, Process::WNOHANG) - raise "server died when it shouldn't have" - end - sleep 1 - end - puts "" -end - -test("connecting and doing nothing to should timeout in 5 seconds") do |pid| - socket = TCPSocket.open("localhost", 5000) - i = 0 - 10.times do - print "." - STDOUT.flush - break if Process.waitpid(pid, Process::WNOHANG) - sleep 1 - i+=1 - end - puts "" - raise "died too soon (after #{i} seconds)" if i < 5 - raise "died too late (after #{i} seconds)" if i > 6 -end - - -test("connecting and writing once to should timeout in 5 seconds") do |pid| - socket = TCPSocket.open("localhost", 5000) - w = socket.write("hello"); - raise "error" unless w == 5 - - i = 0 - 10.times do - print "." - STDOUT.flush - break if Process.waitpid(pid, Process::WNOHANG) - sleep 1 - i+=1 - end - puts "" - raise "died too soon (after #{i} seconds)" if i < 5 - raise "died too late (after #{i} seconds)" if i > 6 -end - -test("connecting waiting 3, writing once to should timeout in 8 seconds") do |pid| - socket = TCPSocket.open("localhost", 5000) - - sleep 3 - - w = socket.write("hello"); - raise "error" unless w == 5 - - i = 0 - 10.times do - print "." - STDOUT.flush - break if Process.waitpid(pid, Process::WNOHANG) - sleep 1 - i+=1 - end - puts "" - raise "died too soon (after #{i} seconds)" if i < 5 - raise "died too late (after #{i} seconds)" if i > 6 -end diff --git a/lib/http_old.js b/lib/http_old.js deleted file mode 100644 index 061c0dd8fd..0000000000 --- a/lib/http_old.js +++ /dev/null @@ -1,641 +0,0 @@ -var sys = require('sys'); -var events = require('events'); - -// FIXME: The TCP binding isn't actually used here, but it needs to be -// loaded before the http binding. -process.binding('tcp'); - -var http = process.binding('http'); - -var CRLF = "\r\n"; -var STATUS_CODES = exports.STATUS_CODES = { - 100 : 'Continue', - 101 : 'Switching Protocols', - 200 : 'OK', - 201 : 'Created', - 202 : 'Accepted', - 203 : 'Non-Authoritative Information', - 204 : 'No Content', - 205 : 'Reset Content', - 206 : 'Partial Content', - 300 : 'Multiple Choices', - 301 : 'Moved Permanently', - 302 : 'Moved Temporarily', - 303 : 'See Other', - 304 : 'Not Modified', - 305 : 'Use Proxy', - 400 : 'Bad Request', - 401 : 'Unauthorized', - 402 : 'Payment Required', - 403 : 'Forbidden', - 404 : 'Not Found', - 405 : 'Method Not Allowed', - 406 : 'Not Acceptable', - 407 : 'Proxy Authentication Required', - 408 : 'Request Time-out', - 409 : 'Conflict', - 410 : 'Gone', - 411 : 'Length Required', - 412 : 'Precondition Failed', - 413 : 'Request Entity Too Large', - 414 : 'Request-URI Too Large', - 415 : 'Unsupported Media Type', - 500 : 'Internal Server Error', - 501 : 'Not Implemented', - 502 : 'Bad Gateway', - 503 : 'Service Unavailable', - 504 : 'Gateway Time-out', - 505 : 'HTTP Version not supported' -}; - -var connection_expression = /Connection/i; -var transfer_encoding_expression = /Transfer-Encoding/i; -var close_expression = /close/i; -var chunk_expression = /chunk/i; -var content_length_expression = /Content-Length/i; - - -/* Abstract base class for ServerRequest and ClientResponse. */ -function IncomingMessage (connection) { - events.EventEmitter.call(this); - - this.connection = connection; - this.httpVersion = null; - this.headers = {}; - - // request (server) only - this.url = ""; - - this.method = null; - - // response (client) only - this.statusCode = null; - this.client = this.connection; -} -sys.inherits(IncomingMessage, events.EventEmitter); -exports.IncomingMessage = IncomingMessage; - -IncomingMessage.prototype._parseQueryString = function () { - throw new Error("_parseQueryString is deprecated. Use require(\"querystring\") to parse query strings.\n"); -}; - -IncomingMessage.prototype.setBodyEncoding = function (enc) { - // TODO: Find a cleaner way of doing this. - this.connection.setEncoding(enc); -}; - -IncomingMessage.prototype.pause = function () { - this.connection.pause(); -}; - -IncomingMessage.prototype.resume = function () { - this.connection.resume(); -}; - -IncomingMessage.prototype._addHeaderLine = function (field, value) { - if (field in this.headers) { - // TODO Certain headers like 'Content-Type' should not be concatinated. - // See https://www.google.com/reader/view/?tab=my#overview-page - this.headers[field] += ", " + value; - } else { - this.headers[field] = value; - } -}; - -function OutgoingMessage (connection) { - events.EventEmitter.call(this, connection); - - this.connection = connection; - - this.output = []; - this.outputEncodings = []; - - this.closeOnFinish = false; - this.chunked_encoding = false; - this.should_keep_alive = true; - this.use_chunked_encoding_by_default = true; - - this.flushing = false; - this.headWritten = false; - - this.finished = false; -} -sys.inherits(OutgoingMessage, events.EventEmitter); -exports.OutgoingMessage = OutgoingMessage; - -OutgoingMessage.prototype._send = function (data, encoding) { - var length = this.output.length; - - if (length === 0) { - this.output.push(data); - encoding = encoding || "ascii"; - this.outputEncodings.push(encoding); - return; - } - - var lastEncoding = this.outputEncodings[length-1]; - var lastData = this.output[length-1]; - - if ((lastEncoding === encoding) || - (!encoding && data.constructor === lastData.constructor)) { - if (lastData.constructor === String) { - this.output[length-1] = lastData + data; - } else { - this.output[length-1] = lastData.concat(data); - } - return; - } - - this.output.push(data); - encoding = encoding || "ascii"; - this.outputEncodings.push(encoding); -}; - -OutgoingMessage.prototype.sendHeaderLines = function (first_line, headers) { - var sent_connection_header = false; - var sent_content_length_header = false; - var sent_transfer_encoding_header = false; - - // first_line in the case of request is: "GET /index.html HTTP/1.1\r\n" - // in the case of response it is: "HTTP/1.1 200 OK\r\n" - var message_header = first_line; - var field, value; - for (var i in headers) { - if (headers[i] instanceof Array) { - field = headers[i][0]; - value = headers[i][1]; - } else { - if (!headers.hasOwnProperty(i)) continue; - field = i; - value = headers[i]; - } - - message_header += field + ": " + value + CRLF; - - if (connection_expression.test(field)) { - sent_connection_header = true; - if (close_expression.test(value)) this.closeOnFinish = true; - - } else if (transfer_encoding_expression.test(field)) { - sent_transfer_encoding_header = true; - if (chunk_expression.test(value)) this.chunked_encoding = true; - - } else if (content_length_expression.test(field)) { - sent_content_length_header = true; - - } - } - - // keep-alive logic - if (sent_connection_header == false) { - if (this.should_keep_alive && - (sent_content_length_header || this.use_chunked_encoding_by_default)) { - message_header += "Connection: keep-alive\r\n"; - } else { - this.closeOnFinish = true; - message_header += "Connection: close\r\n"; - } - } - - if (sent_content_length_header == false && sent_transfer_encoding_header == false) { - if (this.use_chunked_encoding_by_default) { - message_header += "Transfer-Encoding: chunked\r\n"; - this.chunked_encoding = true; - } - else { - this.closeOnFinish = true; - } - } - - message_header += CRLF; - - this._send(message_header); - // wait until the first body chunk, or close(), is sent to flush. -}; - - -OutgoingMessage.prototype.sendBody = function () { - throw new Error("sendBody() has been renamed to write(). " + - "The 'body' event has been renamed to 'data' and " + - "the 'complete' event has been renamed to 'end'."); -}; - - -OutgoingMessage.prototype.write = function (chunk, encoding) { - if ( (this instanceof ServerResponse) && !this.headWritten) { - throw new Error("writeHead() must be called before write()") - } - - encoding = encoding || "ascii"; - if (this.chunked_encoding) { - this._send(process._byteLength(chunk, encoding).toString(16)); - this._send(CRLF); - this._send(chunk, encoding); - this._send(CRLF); - } else { - this._send(chunk, encoding); - } - - if (this.flushing) { - this.flush(); - } else { - this.flushing = true; - } -}; - -OutgoingMessage.prototype.flush = function () { - this.emit("flush"); -}; - -OutgoingMessage.prototype.finish = function () { - throw new Error("finish() has been renamed to close()."); -}; - -OutgoingMessage.prototype.close = function () { - if (this.chunked_encoding) this._send("0\r\n\r\n"); // last chunk - this.finished = true; - this.flush(); -}; - - -function ServerResponse (req) { - OutgoingMessage.call(this, req.connection); - - if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) { - this.use_chunked_encoding_by_default = false; - this.should_keep_alive = false; - } -} -sys.inherits(ServerResponse, OutgoingMessage); -exports.ServerResponse = ServerResponse; - - -ServerResponse.prototype.writeHead = function (statusCode) { - var reasonPhrase, headers, headerIndex; - - if (typeof arguments[1] == 'string') { - reasonPhrase = arguments[1]; - headerIndex = 2; - } else { - reasonPhrase = STATUS_CODES[statusCode] || "unknown"; - headerIndex = 1; - } - - if (typeof arguments[headerIndex] == 'object') { - headers = arguments[headerIndex]; - } else { - headers = {}; - } - - var status_line = "HTTP/1.1 " + statusCode.toString() + " " - + reasonPhrase + CRLF; - this.sendHeaderLines(status_line, headers); - this.headWritten = true; -}; - -// TODO eventually remove sendHeader(), writeHeader() -ServerResponse.prototype.sendHeader = ServerResponse.prototype.writeHead; -ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead; - -function ClientRequest (connection, method, url, headers) { - OutgoingMessage.call(this, connection); - - this.should_keep_alive = false; - if (method === "GET" || method === "HEAD") { - this.use_chunked_encoding_by_default = false; - } else { - this.use_chunked_encoding_by_default = true; - } - this.closeOnFinish = true; - - this.sendHeaderLines(method + " " + url + " HTTP/1.1\r\n", headers); -} -sys.inherits(ClientRequest, OutgoingMessage); -exports.ClientRequest = ClientRequest; - -ClientRequest.prototype.finish = function () { - throw new Error( "finish() has been renamed to close() and no longer takes " - + "a response handler as an argument. Manually add a 'response' listener " - + "to the request object." - ); -}; - -ClientRequest.prototype.close = function () { - if (arguments.length > 0) { - throw new Error( "ClientRequest.prototype.close does not take any arguments. " - + "Add a response listener manually to the request object." - ); - } - OutgoingMessage.prototype.close.call(this); -}; - - -function createIncomingMessageStream (connection, incoming_listener) { - var incoming, field, value; - - connection.addListener("messageBegin", function () { - incoming = new IncomingMessage(connection); - field = null; - value = null; - }); - - // Only servers will get URL events. - connection.addListener("url", function (data) { - incoming.url += data; - }); - - connection.addListener("headerField", function (data) { - if (value) { - incoming._addHeaderLine(field, value); - field = null; - value = null; - } - if (field) { - field += data; - } else { - field = data; - } - }); - - connection.addListener("headerValue", function (data) { - if (value) { - value += data; - } else { - value = data; - } - }); - - connection.addListener("headerComplete", function (info) { - if (field && value) { - incoming._addHeaderLine(field, value); - } - - incoming.httpVersion = info.httpVersion; - incoming.httpVersionMajor = info.versionMajor; - incoming.httpVersionMinor = info.versionMinor; - - if (info.method) { - // server only - incoming.method = info.method; - } else { - // client only - incoming.statusCode = info.statusCode; - } - - incoming_listener(incoming, info.should_keep_alive); - }); - - connection.addListener("body", function (chunk) { - incoming.emit('data', chunk); - }); - - connection.addListener("messageComplete", function () { - incoming.emit('end'); - }); -} - -/* Returns true if the message queue is finished and the connection - * should be closed. */ -function flushMessageQueue (connection, queue) { - while (queue[0]) { - var message = queue[0]; - - while (message.output.length > 0) { - if (connection.readyState !== "open" && connection.readyState !== "writeOnly") { - return true; - } - - var data = message.output.shift(); - var encoding = message.outputEncodings.shift(); - - connection.write(data, encoding); - } - - if (!message.finished) break; - - message.emit("sent"); - queue.shift(); - - if (message.closeOnFinish) return true; - } - return false; -} - - -exports.createServer = function (requestListener, options) { - var server = new http.Server(); - //server.setOptions(options); - server.addListener("request", requestListener); - server.addListener("connection", connectionListener); - return server; -}; - -function connectionListener (connection) { - // An array of responses for each connection. In pipelined connections - // we need to keep track of the order they were sent. - var responses = []; - - connection.resetParser(); - - // is this really needed? - connection.addListener("end", function () { - if (responses.length == 0) { - connection.close(); - } else { - responses[responses.length-1].closeOnFinish = true; - } - }); - - - createIncomingMessageStream(connection, function (incoming, should_keep_alive) { - var req = incoming; - - var res = new ServerResponse(req); - res.should_keep_alive = should_keep_alive; - res.addListener("flush", function () { - if (flushMessageQueue(connection, responses)) { - connection.close(); - } - }); - responses.push(res); - - connection.server.emit("request", req, res); - }); -} - - -exports.createClient = function (port, host) { - var client = new http.Client(); - var secure_credentials={ secure : false }; - - var requests = []; - var currentRequest; - - client.tcpSetSecure = client.setSecure; - client.setSecure = function(format_type, ca_certs, crl_list, private_key, certificate) { - secure_credentials.secure = true; - secure_credentials.format_type = format_type; - secure_credentials.ca_certs = ca_certs; - secure_credentials.crl_list = crl_list; - secure_credentials.private_key = private_key; - secure_credentials.certificate = certificate; - } - - client._reconnect = function () { - if (client.readyState != "opening") { - //sys.debug("HTTP CLIENT: reconnecting readyState = " + client.readyState); - client.connect(port, host); - if (secure_credentials.secure) { - client.tcpSetSecure(secure_credentials.format_type, - secure_credentials.ca_certs, - secure_credentials.crl_list, - secure_credentials.private_key, - secure_credentials.certificate); - } - } - }; - - client._pushRequest = function (req) { - req.addListener("flush", function () { - if (client.readyState == "closed") { - //sys.debug("HTTP CLIENT request flush. reconnect. readyState = " + client.readyState); - client._reconnect(); - return; - } - //sys.debug("client flush readyState = " + client.readyState); - if (req == currentRequest) flushMessageQueue(client, [req]); - }); - requests.push(req); - }; - - client.addListener("connect", function () { - client.resetParser(); - currentRequest = requests.shift(); - currentRequest.flush(); - }); - - client.addListener("end", function () { - //sys.debug("client got end closing. readyState = " + client.readyState); - client.close(); - }); - - client.addListener("close", function (had_error) { - if (had_error) { - client.emit("error"); - return; - } - - //sys.debug("HTTP CLIENT onClose. readyState = " + client.readyState); - - // If there are more requests to handle, reconnect. - if (requests.length > 0) { - client._reconnect(); - } - }); - - createIncomingMessageStream(client, function (res) { - //sys.debug("incoming response!"); - - res.addListener('end', function ( ) { - //sys.debug("request complete disconnecting. readyState = " + client.readyState); - client.close(); - }); - - currentRequest.emit("response", res); - }); - - return client; -}; - -http.Client.prototype.get = function () { - throw new Error("client.get(...) is now client.request('GET', ...)"); -}; - -http.Client.prototype.head = function () { - throw new Error("client.head(...) is now client.request('HEAD', ...)"); -}; - -http.Client.prototype.post = function () { - throw new Error("client.post(...) is now client.request('POST', ...)"); -}; - -http.Client.prototype.del = function () { - throw new Error("client.del(...) is now client.request('DELETE', ...)"); -}; - -http.Client.prototype.put = function () { - throw new Error("client.put(...) is now client.request('PUT', ...)"); -}; - -http.Client.prototype.request = function (method, url, headers) { - if (typeof(url) != "string") { // assume method was omitted, shift arguments - headers = url; - url = method; - method = null; - } - var req = new ClientRequest(this, method || "GET", url, headers); - this._pushRequest(req); - return req; -}; - - -exports.cat = function (url, encoding_, headers_) { - var encoding = 'utf8', - headers = {}, - callback = null; - - // parse the arguments for the various options... very ugly - if (typeof(arguments[1]) == 'string') { - encoding = arguments[1]; - if (typeof(arguments[2]) == 'object') { - headers = arguments[2]; - if (typeof(arguments[3]) == 'function') callback = arguments[3]; - } else { - if (typeof(arguments[2]) == 'function') callback = arguments[2]; - } - } else { - // didn't specify encoding - if (typeof(arguments[1]) == 'object') { - headers = arguments[1]; - callback = arguments[2]; - } else { - callback = arguments[1]; - } - } - - var url = require("url").parse(url); - - var hasHost = false; - for (var i in headers) { - if (i.toLowerCase() === "host") { - hasHost = true; - break; - } - } - if (!hasHost) headers["Host"] = url.hostname; - - var content = ""; - - var client = exports.createClient(url.port || 80, url.hostname); - var req = client.request((url.pathname || "/")+(url.search || "")+(url.hash || ""), headers); - - req.addListener('response', function (res) { - if (res.statusCode < 200 || res.statusCode >= 300) { - if (callback) callback(res.statusCode); - client.close(); - return; - } - res.setBodyEncoding(encoding); - res.addListener('data', function (chunk) { content += chunk; }); - res.addListener('end', function () { - if (callback) callback(null, content); - }); - }); - - client.addListener("error", function (err) { - // todo an error should actually be passed here... - if (callback) callback(new Error('Connection error')); - }); - - req.close(); -}; diff --git a/lib/tcp_old.js b/lib/tcp_old.js deleted file mode 100644 index a27a32761a..0000000000 --- a/lib/tcp_old.js +++ /dev/null @@ -1,26 +0,0 @@ -var tcp = process.binding('tcp'); - -var TLS_STATUS_CODES = { - 1 : 'JS_GNUTLS_CERT_VALIDATED', - 0 : 'JS_GNUTLS_CERT_UNDEFINED', -} -TLS_STATUS_CODES[-100] = 'JS_GNUTLS_CERT_SIGNER_NOT_FOUND'; -TLS_STATUS_CODES[-101] = 'JS_GNUTLS_CERT_SIGNER_NOT_CA'; -TLS_STATUS_CODES[-102] = 'JS_GNUTLS_CERT_INVALID'; -TLS_STATUS_CODES[-103] = 'JS_GNUTLS_CERT_NOT_ACTIVATED'; -TLS_STATUS_CODES[-104] = 'JS_GNUTLS_CERT_EXPIRED'; -TLS_STATUS_CODES[-105] = 'JS_GNUTLS_CERT_REVOKED'; -TLS_STATUS_CODES[-106] = 'JS_GNUTLS_CERT_DOES_NOT_MATCH_HOSTNAME'; - -exports.createServer = function (on_connection, options) { - var server = new tcp.Server(); - server.addListener("connection", on_connection); - //server.setOptions(options); - return server; -}; - -exports.createConnection = function (port, host) { - var connection = new tcp.Connection(); - connection.connect(port, host); - return connection; -}; diff --git a/src/node.cc b/src/node.cc index ee6a86cecc..65f6fde74c 100644 --- a/src/node.cc +++ b/src/node.cc @@ -19,13 +19,11 @@ #include #include #include -#include #include #if 0 // not in use # include #endif -#include #include #include #include @@ -1516,29 +1514,6 @@ static Handle Binding(const Arguments& args) { binding_cache->Set(module, exports); } - } else if (!strcmp(*module_v, "http")) { - if (binding_cache->Has(module)) { - exports = binding_cache->Get(module)->ToObject(); - } else { - // Warning: When calling requireBinding('http') from javascript then - // be sure that you call requireBinding('tcp') before it. - assert(binding_cache->Has(String::New("tcp"))); - exports = Object::New(); - HTTPServer::Initialize(exports); - HTTPConnection::Initialize(exports); - binding_cache->Set(module, exports); - } - - } else if (!strcmp(*module_v, "tcp")) { - if (binding_cache->Has(module)) { - exports = binding_cache->Get(module)->ToObject(); - } else { - exports = Object::New(); - Server::Initialize(exports); - Connection::Initialize(exports); - binding_cache->Set(module, exports); - } - } else if (!strcmp(*module_v, "cares")) { if (binding_cache->Has(module)) { exports = binding_cache->Get(module)->ToObject(); @@ -1643,7 +1618,6 @@ static Handle Binding(const Arguments& args) { exports->Set(String::New("freelist"), String::New(native_freelist)); exports->Set(String::New("fs"), String::New(native_fs)); exports->Set(String::New("http"), String::New(native_http)); - exports->Set(String::New("http_old"), String::New(native_http_old)); exports->Set(String::New("crypto"), String::New(native_crypto)); exports->Set(String::New("ini"), String::New(native_ini)); exports->Set(String::New("mjsunit"), String::New(native_mjsunit)); @@ -1653,7 +1627,6 @@ static Handle Binding(const Arguments& args) { exports->Set(String::New("repl"), String::New(native_repl)); exports->Set(String::New("sys"), String::New(native_sys)); exports->Set(String::New("tcp"), String::New(native_tcp)); - exports->Set(String::New("tcp_old"), String::New(native_tcp_old)); exports->Set(String::New("uri"), String::New(native_uri)); exports->Set(String::New("url"), String::New(native_url)); exports->Set(String::New("utils"), String::New(native_utils)); @@ -1896,9 +1869,6 @@ int main(int argc, char *argv[]) { return 1; } - // Ignore the SIGPIPE - evcom_ignore_sigpipe(); - // Initialize the default ev loop. #ifdef __sun // TODO(Ryan) I'm experiencing abnormally high load using Solaris's diff --git a/src/node.h b/src/node.h index 7f2adb8e5f..5d6bec6e20 100644 --- a/src/node.h +++ b/src/node.h @@ -5,7 +5,6 @@ #include #include #include -#include #include /* struct stat */ #include diff --git a/src/node_cares.cc b/src/node_cares.cc index cfc19b01e2..f453f28c94 100644 --- a/src/node_cares.cc +++ b/src/node_cares.cc @@ -4,6 +4,10 @@ #include #include +#include +#include +#include + #include #include diff --git a/src/node_http.cc b/src/node_http.cc deleted file mode 100644 index 30cc93bd29..0000000000 --- a/src/node_http.cc +++ /dev/null @@ -1,392 +0,0 @@ -#include - -#include -#include -#include - -using namespace v8; -using namespace node; - -Persistent HTTPConnection::client_constructor_template; -Persistent HTTPConnection::server_constructor_template; - -static Persistent method_symbol; -static Persistent status_code_symbol; -static Persistent http_version_symbol; -static Persistent version_major_symbol; -static Persistent version_minor_symbol; -static Persistent should_keep_alive_symbol; - -static Persistent message_begin_symbol; -static Persistent message_complete_symbol; -static Persistent url_symbol; -static Persistent query_string_symbol; -static Persistent path_symbol; -static Persistent fragment_symbol; -static Persistent header_field_symbol; -static Persistent header_value_symbol; -static Persistent header_complete_symbol; -static Persistent body_symbol; -static Persistent end_symbol; - -static Persistent delete_sym; -static Persistent get_sym; -static Persistent head_sym; -static Persistent post_sym; -static Persistent put_sym; -static Persistent connect_sym; -static Persistent options_sym; -static Persistent trace_sym; -static Persistent copy_sym; -static Persistent lock_sym; -static Persistent mkcol_sym; -static Persistent move_sym; -static Persistent propfind_sym; -static Persistent proppatch_sym; -static Persistent unlock_sym; -static Persistent unknown_method_sym; - -static struct http_parser_settings settings; - -void -HTTPConnection::Initialize (Handle target) -{ - HandleScope scope; - - Local t = FunctionTemplate::New(NewClient); - client_constructor_template = Persistent::New(t); - client_constructor_template->Inherit(Connection::constructor_template); - client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - client_constructor_template->SetClassName(String::NewSymbol("Client")); - NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "resetParser", ResetParser); - target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction()); - - t = FunctionTemplate::New(NewServer); - server_constructor_template = Persistent::New(t); - server_constructor_template->Inherit(Connection::constructor_template); - server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "resetParser", ResetParser); - server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection")); - - end_symbol = NODE_PSYMBOL("end"); - - settings.on_message_begin = on_message_begin; - settings.on_path = on_path; - settings.on_query_string = on_query_string; - settings.on_url = on_url; - settings.on_fragment = on_fragment; - settings.on_header_field = on_header_field; - settings.on_header_value = on_header_value; - settings.on_headers_complete = on_headers_complete; - settings.on_body = on_body; - settings.on_message_complete = on_message_complete; -} - -Handle -HTTPConnection::NewClient (const Arguments& args) -{ - HandleScope scope; - - HTTPConnection *connection = new HTTPConnection(HTTP_RESPONSE); - connection->Wrap(args.This()); - - return args.This(); -} - -Handle -HTTPConnection::NewServer (const Arguments& args) -{ - HandleScope scope; - - HTTPConnection *connection = new HTTPConnection(HTTP_REQUEST); - connection->Wrap(args.This()); - - return args.This(); -} - - -Handle HTTPConnection::ResetParser(const Arguments& args) { - HandleScope scope; - HTTPConnection *connection = ObjectWrap::Unwrap(args.Holder()); - connection->ResetParser(); - return Undefined(); -} - - -void -HTTPConnection::OnReceive (const void *buf, size_t len) -{ - HandleScope scope; - - assert(refs_); - size_t nparsed; - - nparsed = http_parser_execute(&parser_, settings, static_cast(buf), len); - - if (nparsed != len) { - ForceClose(); - } -} - -void -HTTPConnection::OnEOF () -{ - HandleScope scope; - assert(refs_); - size_t nparsed; - nparsed = http_parser_execute(&parser_, settings, NULL, 0); - Emit(end_symbol, 0, NULL); -} - -int -HTTPConnection::on_message_begin (http_parser *parser) -{ - if (message_begin_symbol.IsEmpty()) { - method_symbol = NODE_PSYMBOL("method"); - status_code_symbol = NODE_PSYMBOL("statusCode"); - http_version_symbol = NODE_PSYMBOL("httpVersion"); - version_major_symbol = NODE_PSYMBOL("versionMajor"); - version_minor_symbol = NODE_PSYMBOL("versionMinor"); - should_keep_alive_symbol = NODE_PSYMBOL("should_keep_alive"); - - message_begin_symbol = NODE_PSYMBOL("messageBegin"); - message_complete_symbol = NODE_PSYMBOL("messageComplete"); - url_symbol = NODE_PSYMBOL("url"); - query_string_symbol = NODE_PSYMBOL("queryString"); - path_symbol = NODE_PSYMBOL("path"); - fragment_symbol = NODE_PSYMBOL("fragment"); - header_field_symbol = NODE_PSYMBOL("headerField"); - header_value_symbol = NODE_PSYMBOL("headerValue"); - header_complete_symbol = NODE_PSYMBOL("headerComplete"); - body_symbol = NODE_PSYMBOL("body"); - - delete_sym = NODE_PSYMBOL("DELETE"); - get_sym = NODE_PSYMBOL("GET"); - head_sym = NODE_PSYMBOL("HEAD"); - post_sym = NODE_PSYMBOL("POST"); - put_sym = NODE_PSYMBOL("PUT"); - connect_sym = NODE_PSYMBOL("CONNECT"); - options_sym = NODE_PSYMBOL("OPTIONS"); - trace_sym = NODE_PSYMBOL("TRACE"); - copy_sym = NODE_PSYMBOL("COPY"); - lock_sym = NODE_PSYMBOL("LOCK"); - mkcol_sym = NODE_PSYMBOL("MKCOL"); - move_sym = NODE_PSYMBOL("MOVE"); - propfind_sym = NODE_PSYMBOL("PROPFIND"); - proppatch_sym = NODE_PSYMBOL("PROPPATCH"); - unlock_sym = NODE_PSYMBOL("UNLOCK"); - unknown_method_sym = NODE_PSYMBOL("UNKNOWN_METHOD"); - } - - HTTPConnection *connection = static_cast (parser->data); - assert(connection->refs_); - connection->Emit(message_begin_symbol, 0, NULL); - return 0; -} - -int -HTTPConnection::on_message_complete (http_parser *parser) -{ - HTTPConnection *connection = static_cast (parser->data); - assert(connection->refs_); - connection->Emit(message_complete_symbol, 0, NULL); - return 0; -} - -int -HTTPConnection::on_url (http_parser *parser, const char *buf, size_t len) -{ - HTTPConnection *connection = static_cast(parser->data); - assert(connection->refs_); - Local argv[1] = { String::New(buf, len) }; - connection->Emit(url_symbol, 1, argv); - return 0; -} - -int -HTTPConnection::on_query_string (http_parser *parser, const char *buf, size_t len) -{ - HTTPConnection *connection = static_cast(parser->data); - assert(connection->refs_); - Local argv[1] = { String::New(buf, len) }; - connection->Emit(query_string_symbol, 1, argv); - return 0; -} - -int -HTTPConnection::on_path (http_parser *parser, const char *buf, size_t len) -{ - HTTPConnection *connection = static_cast(parser->data); - assert(connection->refs_); - Local argv[1] = { String::New(buf, len) }; - connection->Emit(path_symbol, 1, argv); - return 0; -} - -int -HTTPConnection::on_fragment (http_parser *parser, const char *buf, size_t len) -{ - HTTPConnection *connection = static_cast(parser->data); - assert(connection->refs_); - Local argv[1] = { String::New(buf, len) }; - connection->Emit(fragment_symbol, 1, argv); - return 0; -} - -const static char normalizer[] = - "\0------------------------------" - "-----------------0123456789-----" - "--abcdefghijklmnopqrstuvwxyz----" - "--abcdefghijklmnopqrstuvwxyz----" - "--------------------------------" - "--------------------------------" - "--------------------------------" - "--------------------------------"; - -int -HTTPConnection::on_header_field (http_parser *parser, const char *buf, size_t len) -{ - HTTPConnection *connection = static_cast(parser->data); - assert(connection->refs_); - - // NORMALIZE - size_t i; - char *nonconstbuf = (char*)buf; // FIXME - for (i = 0; i < len; i++) { nonconstbuf[i] = normalizer[buf[i]]; } - - Local argv[1] = { String::New(buf, len) }; - connection->Emit(header_field_symbol, 1, argv); - return 0; -} - -int -HTTPConnection::on_header_value (http_parser *parser, const char *buf, size_t len) -{ - HTTPConnection *connection = static_cast(parser->data); - assert(connection->refs_); - - Local argv[1] = { String::New(buf, len) }; - connection->Emit(header_value_symbol, 1, argv); - return 0; -} - -static inline Persistent -method_to_str(enum http_method m) { - switch (m) { - case HTTP_DELETE: return delete_sym; - case HTTP_GET: return get_sym; - case HTTP_HEAD: return head_sym; - case HTTP_POST: return post_sym; - case HTTP_PUT: return put_sym; - case HTTP_CONNECT: return connect_sym; - case HTTP_OPTIONS: return options_sym; - case HTTP_TRACE: return trace_sym; - case HTTP_COPY: return copy_sym; - case HTTP_LOCK: return lock_sym; - case HTTP_MKCOL: return mkcol_sym; - case HTTP_MOVE: return move_sym; - case HTTP_PROPFIND: return propfind_sym; - case HTTP_PROPPATCH: return proppatch_sym; - case HTTP_UNLOCK: return unlock_sym; - default: return unknown_method_sym; - } -} - -int -HTTPConnection::on_headers_complete (http_parser *parser) -{ - HTTPConnection *connection = static_cast (parser->data); - assert(connection->refs_); - - Local message_info = Object::New(); - - // METHOD - if (connection->type_ == HTTP_REQUEST) { - message_info->Set(method_symbol, method_to_str(connection->parser_.method)); - } - - // STATUS - if (connection->type_ == HTTP_RESPONSE) { - message_info->Set(status_code_symbol, - Integer::New(connection->parser_.status_code)); - } - - // VERSION - char version[10]; - snprintf( version - , 10 - , "%d.%d" - , connection->parser_.http_major - , connection->parser_.http_minor - ); - message_info->Set(http_version_symbol, String::New(version)); - message_info->Set(version_major_symbol, - Integer::New(connection->parser_.http_major)); - message_info->Set(version_minor_symbol, - Integer::New(connection->parser_.http_minor)); - - message_info->Set(should_keep_alive_symbol, - http_should_keep_alive(&connection->parser_) ? True() : False()); - - Local argv[1] = { message_info }; - - connection->Emit(header_complete_symbol, 1, argv); - - return 0; -} - -int -HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len) -{ - assert(len != 0); - - HTTPConnection *connection = static_cast (parser->data); - assert(connection->refs_); - - // TODO each message should have their encoding. - // don't look at the conneciton for encoding - Local data = Encode(buf, len, connection->encoding_); - connection->Emit(body_symbol, 1, &data); - - return 0; -} - -Persistent HTTPServer::constructor_template; - -void -HTTPServer::Initialize (Handle target) -{ - HandleScope scope; - - Local t = FunctionTemplate::New(New); - constructor_template = Persistent::New(t); - constructor_template->Inherit(Server::constructor_template); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - constructor_template->SetClassName(String::NewSymbol("Server")); - target->Set(String::NewSymbol("Server"), constructor_template->GetFunction()); -} - -Handle -HTTPServer::New (const Arguments& args) -{ - HandleScope scope; - - HTTPServer *server = new HTTPServer(); - server->Wrap(args.This()); - - return args.This(); -} - -Handle -HTTPServer::GetConnectionTemplate (void) -{ - return HTTPConnection::server_constructor_template; -} - -Connection* -HTTPServer::UnwrapConnection (Local connection) -{ - HandleScope scope; - return ObjectWrap::Unwrap(connection); -} - diff --git a/src/node_http.h b/src/node_http.h deleted file mode 100644 index 0b1b6ac07b..0000000000 --- a/src/node_http.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef node_http_h -#define node_http_h - -#include -#include -#include - -namespace node { - -class HTTPConnection : public Connection { -public: - static void Initialize (v8::Handle target); - - static v8::Persistent client_constructor_template; - static v8::Persistent server_constructor_template; - -protected: - static v8::Handle NewClient (const v8::Arguments& args); - static v8::Handle NewServer (const v8::Arguments& args); - static v8::Handle ResetParser(const v8::Arguments& args); - - HTTPConnection (enum http_parser_type t) - : Connection() - { - type_ = t; - ResetParser(); - } - - void ResetParser() { - http_parser_init (&parser_, type_); - parser_.data = this; - } - - void OnReceive (const void *buf, size_t len); - void OnEOF (); - - static int on_message_begin (http_parser *parser); - static int on_url (http_parser *parser, const char *at, size_t length); - static int on_query_string (http_parser *parser, const char *at, size_t length); - static int on_path (http_parser *parser, const char *at, size_t length); - static int on_fragment (http_parser *parser, const char *at, size_t length); - static int on_header_field (http_parser *parser, const char *buf, size_t len); - static int on_header_value (http_parser *parser, const char *buf, size_t len); - static int on_headers_complete (http_parser *parser); - static int on_body (http_parser *parser, const char *buf, size_t len); - static int on_message_complete (http_parser *parser); - - enum http_parser_type type_; - http_parser parser_; - friend class HTTPServer; -}; - -class HTTPServer : public Server { -public: - static void Initialize (v8::Handle target); - static v8::Persistent constructor_template; - -protected: - static v8::Handle New (const v8::Arguments& args); - - HTTPServer (void) : Server() {} - - v8::Handle GetConnectionTemplate (void); - Connection* UnwrapConnection (v8::Local connection); -}; - -} // namespace node -#endif diff --git a/src/node_net.cc b/src/node_net.cc deleted file mode 100644 index 2c5b8de32c..0000000000 --- a/src/node_net.cc +++ /dev/null @@ -1,1122 +0,0 @@ -// Copyright 2009 Ryan Dahl -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* inet_ntop */ -#include /* sockaddr_in, sockaddr_in6 */ - -using namespace v8; - -namespace node { - -static Persistent utf8_symbol; -static Persistent binary_symbol; -static Persistent ascii_symbol; - -static Persistent server_symbol; -static Persistent remote_address_symbol; -static Persistent fd_symbol; - -static Persistent ready_state_symbol; -static Persistent open_symbol; -static Persistent opening_symbol; -static Persistent read_only_symbol; -static Persistent write_only_symbol; -static Persistent closing_symbol; -static Persistent closed_symbol; - -static Persistent data_symbol; -static Persistent connection_symbol; -static Persistent connect_symbol; -static Persistent timeout_symbol; -static Persistent drain_symbol; -static Persistent end_symbol; -static Persistent close_symbol; - -static const struct addrinfo server_tcp_hints = -/* ai_flags */ { AI_PASSIVE -/* ai_family */ , AF_UNSPEC -/* ai_socktype */ , SOCK_STREAM - , 0 - }; - -static const struct addrinfo client_tcp_hints = -/* ai_flags */ { 0 -/* ai_family */ , AF_UNSPEC -/* ai_socktype */ , SOCK_STREAM - , 0 - }; - -Persistent Connection::constructor_template; - -Handle ThrottleMissingError(const Arguments& args) { - HandleScope scope; - return ThrowException(Exception::Error(String::New( - "readPause() and readResume() have been renamed to pause() and " - "resume() respectively."))); -} - -// Initialize the tcp.Connection object. -void Connection::Initialize(v8::Handle target) { - HandleScope scope; - - utf8_symbol = NODE_PSYMBOL("utf8"); - binary_symbol = NODE_PSYMBOL("binary"); - ascii_symbol = NODE_PSYMBOL("ascii"); - - server_symbol = NODE_PSYMBOL("server"); - remote_address_symbol = NODE_PSYMBOL("remoteAddress"); - fd_symbol = NODE_PSYMBOL("fd"); - - ready_state_symbol = NODE_PSYMBOL("readyState"); - open_symbol = NODE_PSYMBOL("open"); - opening_symbol = NODE_PSYMBOL("opening"); - read_only_symbol = NODE_PSYMBOL("readOnly"); - write_only_symbol = NODE_PSYMBOL("writeOnly"); - closing_symbol = NODE_PSYMBOL("closing"); - closed_symbol = NODE_PSYMBOL("closed"); - - data_symbol = NODE_PSYMBOL("data"); - connection_symbol = NODE_PSYMBOL("connection"); - connect_symbol = NODE_PSYMBOL("connect"); - timeout_symbol = NODE_PSYMBOL("timeout"); - drain_symbol = NODE_PSYMBOL("drain"); - end_symbol = NODE_PSYMBOL("end"); - close_symbol = NODE_PSYMBOL("close"); - - Local t = FunctionTemplate::New(New); - - constructor_template = Persistent::New(t); - // Inherits from node.EventEmitter - constructor_template->Inherit(EventEmitter::constructor_template); - // All native node objects have 1 internal field (required by ObjectWrap) - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - // Set class name for debugging output - constructor_template->SetClassName(String::NewSymbol("Connection")); - - NODE_SET_PROTOTYPE_METHOD(constructor_template, "connect", Connect); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "send", Send); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "write", Write); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", Close); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "forceClose", ForceClose); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "setEncoding", SetEncoding); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "pause", Pause); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "resume", Resume); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "readPause", ThrottleMissingError); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "readResume", ThrottleMissingError); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "setTimeout", SetTimeout); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "setNoDelay", SetNoDelay); - #if EVCOM_HAVE_GNUTLS - NODE_SET_PROTOTYPE_METHOD(constructor_template, "setSecure", SetSecure); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "verifyPeer", VerifyPeer); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "getPeerCertificate", - GetPeerCertificate); - gnutls_global_init(); - #endif - - // Getter for connection.readyState - constructor_template->InstanceTemplate()->SetAccessor( - ready_state_symbol, - ReadyStateGetter); - - // Getter for connection.readyState - constructor_template->InstanceTemplate()->SetAccessor( - fd_symbol, - FDGetter); - - // Assign class to its place as tcp.Connection - target->Set(String::NewSymbol("Connection"), - constructor_template->GetFunction()); -} - -Handle Connection::ReadyStateGetter(Local property, - const AccessorInfo& info) { - // Unwrap the javascript object to get the C++ object - Connection *connection = ObjectWrap::Unwrap(info.This()); - assert(connection); - - HandleScope scope; - - assert(property == ready_state_symbol); - - // Resolving is not done in evcom, it's done in this file. Thus we add - // this "opening" symbol to the native EVCOM ready states. "opening" - // really means "resolving". - if (connection->resolving_) return scope.Close(opening_symbol); - - // Map between the evcom enum and V8 strings: - switch (evcom_stream_state(&connection->stream_)) { - case EVCOM_INITIALIZED: return scope.Close(closed_symbol); - case EVCOM_CONNECTING: return scope.Close(opening_symbol); - case EVCOM_CONNECTED_RW: return scope.Close(open_symbol); - case EVCOM_CONNECTED_RO: return scope.Close(read_only_symbol); - case EVCOM_CONNECTED_WO: return scope.Close(write_only_symbol); - case EVCOM_CLOSING: return scope.Close(closing_symbol); - case EVCOM_CLOSED: return scope.Close(closed_symbol); - } - - assert(0 && "This shouldnt happen"); - return ThrowException(Exception::Error( - String::New("This shouldn't happen."))); -} - -Handle Connection::FDGetter(Local property, - const AccessorInfo& info) { - // Unwrap the javascript object to get the C++ object - Connection *connection = ObjectWrap::Unwrap(info.This()); - assert(connection); - - HandleScope scope; - - assert(property == fd_symbol); - - Local fd = Integer::New(connection->stream_.recvfd); - - return scope.Close(fd); -} - -// Constructor - these actions are not taken in the normal constructor -// (Connection::Connection) because sometimes the Connection needs to be -// reinitialized without destroying the object. -void Connection::Init() { - resolving_ = false; - secure_ = false; - evcom_stream_init(&stream_); - stream_.on_connect = Connection::on_connect; - stream_.on_read = Connection::on_read; - stream_.on_close = Connection::on_close; - stream_.on_timeout = Connection::on_timeout; - stream_.on_drain = Connection::on_drain; - stream_.data = this; -} - -Connection::~Connection() { - assert(stream_.recvfd < 0 && "garbage collecting open Connection"); - assert(stream_.sendfd < 0 && "garbage collecting open Connection"); -} - -// V8 contstructor -Handle Connection::New(const Arguments& args) { - HandleScope scope; - - // All constructors in node look similar to this. - - // allocate the C++ object - Connection *connection = new Connection(); - - // Use ObjectWrap::Wrap to assign it to the internal field in the V8 - // object. - connection->Wrap(args.This()); - - return args.This(); -} - -// Open a connection. Starts resolving the hostname in the libeio -// thread pool, when that completes in Connection::AfterResolve, actually -// open the connection. -Handle Connection::Connect(const Arguments& args) { - // Unwrap V8 object into C++ object - Connection *connection = ObjectWrap::Unwrap(args.Holder()); - assert(connection); - - HandleScope scope; - - // If the connection is closed, reinitialize it. - if (connection->ReadyState() == EVCOM_CLOSED) { - connection->Init(); // in case we're reusing the socket - assert(connection->ReadyState() == EVCOM_INITIALIZED); - } - - // If connect() is called on an open connection, raise an error. - if (connection->ReadyState() != EVCOM_INITIALIZED || connection->resolving_) { - Local exception = Exception::Error( - String::New("Socket is not in CLOSED state.")); - return ThrowException(exception); - } - - assert(connection->stream_.recvfd < 0); - assert(connection->stream_.sendfd < 0); - - // Make sure we have at least one argument (a port) - if (args.Length() == 0) { - Local exception = Exception::TypeError( - String::New("First argument must be a port number")); - return ThrowException(exception); - } - - // We need the port as a string for getaddrinfo(). - // Thus cast it to a string. The strdup()'d value will be freed in - // Resolve(). - String::AsciiValue port_sv(args[0]->ToString()); - assert(connection->port_ == NULL); - connection->port_ = strdup(*port_sv); - - // Get the host, if any is present. - assert(connection->host_ == NULL); - if (args.Length() > 1 && args[1]->IsString()) { - String::Utf8Value host_sv(args[1]->ToString()); - connection->host_ = strdup(*host_sv); - } - - connection->resolving_ = true; // This is done so that readyState can return - // "opening" while getaddinfo() runs. - - // There will not be any active watchers from this object on the event - // loop while getaddrinfo() runs. If the only thing happening in the - // script was this hostname resolution, then the event loop would drop - // out. Thus we need to add ev_ref() until AfterResolve(). - ev_ref(EV_DEFAULT_UC); - - // Ref the object so it doesn't get garbage collected. - connection->Ref(); - - // For the moment I will do DNS lookups in the eio thread pool. This is - // sub-optimal and cannot handle massive numbers of requests. - // In the future I will move to a system using adns or udns: - // http://lists.schmorp.de/pipermail/libev/2009q1/000632.html - eio_custom(Connection::Resolve, EIO_PRI_DEFAULT, Connection::AfterResolve, - connection); - - return Undefined(); -} - -// This function is executed in the thread pool. It cannot modify any -// members of the connection object. -int Connection::Resolve(eio_req *req) { - Connection *connection = static_cast (req->data); - struct addrinfo *address = NULL; - - assert(connection->refs_); - assert(connection->resolving_); - - req->result = getaddrinfo(connection->host_, connection->port_, - &client_tcp_hints, &address); - req->ptr2 = address; - - free(connection->port_); - connection->port_ = NULL; - - return 0; -} - -static struct addrinfo * AddressDefaultToIPv4(struct addrinfo *address_list) { - struct addrinfo *address = NULL; - - for (address = address_list; address != NULL; address = address->ai_next) { - if (address->ai_addr->sa_family == AF_INET) break; - } - - return address == NULL ? address_list : address; -} - -int Connection::AfterResolve(eio_req *req) { - ev_unref(EV_DEFAULT_UC); - - Connection *connection = static_cast (req->data); - - assert(connection->resolving_); - assert(connection->refs_); - - struct addrinfo *address = NULL, - *address_list = static_cast(req->ptr2); - - address = AddressDefaultToIPv4(address_list); - - connection->resolving_ = false; - - int r = 0; - if (req->result == 0) r = connection->Connect(address->ai_addr); - - if (address_list) freeaddrinfo(address_list); - - // no error. return. - if (req->result == 0 && !r) { - evcom_stream_attach(EV_DEFAULT_UC_ &connection->stream_); - goto out; - } - - /* RESOLVE ERROR */ - - /* TODO: the whole resolve process should be moved into evcom_stream. - * The fact that I'm modifying a read-only variable here should be - * good evidence of this. - */ - - if (req->result) { - connection->stream_.errorno = req->result; - } else { - assert(r); - assert(connection->stream_.errorno); - } - - connection->OnClose(); - - connection->Unref(); - - out: - return 0; -} - -Handle Connection::SetEncoding(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - - if (!args[0]->IsString()) { - connection->encoding_ = BINARY; - return scope.Close(binary_symbol); - } - - switch (ParseEncoding(args[0])) { - case ASCII: - connection->encoding_ = ASCII; - return scope.Close(ascii_symbol); - - case UTF8: - connection->encoding_ = UTF8; - return scope.Close(utf8_symbol); - - case BINARY: - connection->encoding_ = BINARY; - return scope.Close(binary_symbol); - } - assert(0 && "this shouldn't happen"); - return ThrowException(Exception::Error( - String::New("Could not parse encoding. This is a Node bug."))); -} - -#if EVCOM_HAVE_GNUTLS - -Handle Connection::SetSecure(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - int r; - - connection->secure_ = true; - - // Create credentials - - gnutls_certificate_allocate_credentials(&connection->credentials); - - if (args[1]->IsString()) { - String::Utf8Value caString(args[1]->ToString()); - gnutls_datum_t datum = { reinterpret_cast(*caString) - , caString.length() - }; - r = gnutls_certificate_set_x509_trust_mem(connection->credentials, - &datum, GNUTLS_X509_FMT_PEM); - } - - if (args[2]->IsString()) { - String::Utf8Value crlString(args[2]->ToString()); - gnutls_datum_t datum = { reinterpret_cast(*crlString) - , crlString.length() - }; - r = gnutls_certificate_set_x509_crl_mem(connection->credentials, - &datum, GNUTLS_X509_FMT_PEM); - } - - if (args[3]->IsString() && args[4]->IsString()) { - String::Utf8Value keyString(args[3]->ToString()); - String::Utf8Value certString(args[4]->ToString()); - gnutls_datum_t datum_key = { reinterpret_cast(*keyString) - , keyString.length() - }; - gnutls_datum_t datum_cert = { reinterpret_cast(*certString) - , certString.length() - }; - r = gnutls_certificate_set_x509_key_mem(connection->credentials, - &datum_cert, &datum_key, - GNUTLS_X509_FMT_PEM); - } - - // Create the session object - - init_tls_session(&connection->stream_, - connection->credentials, - GNUTLS_CLIENT); - - return Undefined(); -} - - -Handle Connection::VerifyPeer(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - - const gnutls_datum_t * cert_chain; - uint cert_chain_length; - gnutls_x509_crl_t *crl_list; - uint crl_list_size; - gnutls_x509_crt_t *ca_list; - uint ca_list_size; - int r; - - if (!connection->secure_) { - return Undefined(); - } - - cert_chain = gnutls_certificate_get_peers(connection->stream_.session, - &cert_chain_length); - - gnutls_certificate_get_x509_crls(connection->credentials, - &crl_list, - &crl_list_size); - - gnutls_certificate_get_x509_cas(connection->credentials, - &ca_list, - &ca_list_size); - - r = verify_certificate_chain(connection->stream_.session, - connection->host_, - cert_chain, - cert_chain_length, - crl_list, - crl_list_size, - ca_list, - ca_list_size); - - return scope.Close(Integer::New(r)); -} - -Handle Connection::GetPeerCertificate(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - - if (!connection->secure_) { - return Undefined(); - } - - const gnutls_datum_t * cert_chain; - uint cert_chain_length; - char *name; - size_t name_size; - gnutls_x509_crt_t cert; - cert_chain = gnutls_certificate_get_peers(connection->stream_.session, - &cert_chain_length); - - if ( (cert_chain_length == 0) || (cert_chain == NULL) ) { - return Undefined(); - } - - gnutls_x509_crt_init(&cert); - gnutls_x509_crt_import(cert, &cert_chain[0], GNUTLS_X509_FMT_DER); - - - gnutls_x509_crt_get_dn(cert, NULL, &name_size); - name = (char *)malloc(name_size); - gnutls_x509_crt_get_dn(cert, name, &name_size); - - Local dnString = String::New(name); - free(name); - gnutls_x509_crt_deinit(cert); - return scope.Close(dnString); -} -#endif - -Handle Connection::Pause(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - - connection->Pause(); - - return Undefined(); -} - -Handle Connection::Resume(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - - connection->Resume(); - - return Undefined(); -} - -Handle Connection::SetTimeout(const Arguments& args) { - HandleScope scope; - - Connection *connection = ObjectWrap::Unwrap(args.This()); - assert(connection); - - float timeout = NODE_V8_UNIXTIME(args[0]); - - connection->SetTimeout(timeout); - - return Undefined(); -} - -Handle Connection::Close(const Arguments& args) { - HandleScope scope; - Connection *connection = ObjectWrap::Unwrap(args.Holder()); - assert(connection); - - connection->Close(); - - if (connection->host_ != NULL) { - free(connection->host_); - connection->host_ = NULL; - } - - return Undefined(); -} - -Handle Connection::ForceClose(const Arguments& args) { - HandleScope scope; - Connection *connection = ObjectWrap::Unwrap(args.Holder()); - assert(connection); - - connection->ForceClose(); - connection->Unref(); - return Undefined(); -} - -Handle Connection::SetNoDelay(const Arguments& args) { - HandleScope scope; - Connection *connection = ObjectWrap::Unwrap(args.Holder()); - - bool no_delay = true; - if (args.Length() > 0) { - no_delay = args[0]->IsTrue(); - } - - connection->SetNoDelay(no_delay); - - return Undefined(); -} - - -Handle Connection::Send(const Arguments& args) { - HandleScope scope; - return ThrowException(Exception::Error(String::New( - "connection.send() has been renamed to connection.write(). " - "(Also the 'receive' event has been renamed to 'data' and " - "the 'eof' event has been renamed to 'end'.)"))); -} - - -Handle Connection::Write(const Arguments& args) { - HandleScope scope; - Connection *connection = ObjectWrap::Unwrap(args.Holder()); - assert(connection); - - if (connection->ReadyState() != EVCOM_CONNECTED_RW && - connection->ReadyState() != EVCOM_CONNECTED_WO) { - Local exception = Exception::Error( - String::New("Socket is not open for writing")); - return ThrowException(exception); - } - - enum encoding enc = ParseEncoding(args[1]); - ssize_t len = DecodeBytes(args[0], enc); - - if (len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - - char * buf = new char[len]; - ssize_t bufsize = DecodeWrite(buf, len, args[0], enc); - assert(bufsize == len); - ssize_t sent = connection->Write(buf, bufsize); - delete [] buf; - - return sent == bufsize ? True() : False(); -} - -void Connection::OnReceive(const void *buf, size_t len) { - HandleScope scope; - Local data = Encode(buf, len, encoding_); - Emit(data_symbol, 1, &data); -} - -void Connection::OnClose() { - HandleScope scope; - - Handle argv[2] = { - stream_.errorno == 0 ? False() : True(), - String::New(strerror(stream_.errorno)) - }; - - Emit(close_symbol, 2, argv); -} - -void Connection::OnConnect() { - HandleScope scope; - - if (stream_.server) { - Server *server = static_cast(stream_.server->data); - Local value = Local::New(handle_); - server->Emit(connection_symbol, 1, &value); - } - - Emit(connect_symbol, 0, NULL); -} - -void Connection::OnTimeout() { - HandleScope scope; - Emit(timeout_symbol, 0, NULL); -} - -void Connection::OnDrain() { - HandleScope scope; - Emit(drain_symbol, 0, NULL); -} - -void Connection::OnEOF() { - HandleScope scope; - Emit(end_symbol, 0, NULL); -} - -Persistent Server::constructor_template; - -void Server::Initialize(Handle target) { - HandleScope scope; - - Local t = FunctionTemplate::New(New); - constructor_template = Persistent::New(t); - constructor_template->Inherit(EventEmitter::constructor_template); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - constructor_template->SetClassName(String::NewSymbol("Server")); - - NODE_SET_PROTOTYPE_METHOD(constructor_template, "listen", Listen); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", Close); - #if EVCOM_HAVE_GNUTLS - NODE_SET_PROTOTYPE_METHOD(constructor_template, "setSecure", SetSecure); - #endif - - target->Set(String::NewSymbol("Server"), constructor_template->GetFunction()); -} - -static Local GetAddressString(struct sockaddr *addr) { - HandleScope scope; - char ip[INET6_ADDRSTRLEN]; - Local remote_address; - - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sa = reinterpret_cast(addr); - inet_ntop(AF_INET, &(sa->sin_addr), ip, INET6_ADDRSTRLEN); - remote_address = String::New(ip); - - } else if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sa6 = reinterpret_cast(addr); - inet_ntop(AF_INET6, &(sa6->sin6_addr), ip, INET6_ADDRSTRLEN); - remote_address = String::New(ip); - - } else { - assert(0 && "received a bad sa_family"); - } - - return scope.Close(remote_address); -} - -Handle Server::GetConnectionTemplate() { - return Connection::constructor_template; -} - -Connection* Server::UnwrapConnection(Local connection) { - HandleScope scope; - return ObjectWrap::Unwrap(connection); -} - -Connection* Server::OnConnection(struct sockaddr *addr) { - HandleScope scope; - - TryCatch try_catch; - - Local js_connection = - GetConnectionTemplate()->GetFunction()->NewInstance(0, NULL); - - if (js_connection.IsEmpty()) { - FatalException(try_catch); - return NULL; - } - - Local remote_address = GetAddressString(addr); - js_connection->Set(remote_address_symbol, remote_address); - js_connection->Set(server_symbol, handle_); - - Connection *connection = UnwrapConnection(js_connection); - if (!connection) return NULL; - - #if EVCOM_HAVE_GNUTLS - if (secure_) { - connection->secure_ = true; - connection->credentials = credentials; - init_tls_session(&connection->stream_, - connection->credentials, - GNUTLS_SERVER); - } - #endif - - connection->Ref(); - - return connection; -} - -void Server::OnClose(int errorno) { - HandleScope scope; - - Handle argv[1] = { Integer::New(errorno) }; - - Emit(close_symbol, 1, argv); -} - -Handle Server::New(const Arguments& args) { - HandleScope scope; - - Server *server = new Server(); - server->Wrap(args.This()); - return args.This(); -} - -Handle Server::Listen(const Arguments& args) { - Server *server = ObjectWrap::Unwrap(args.Holder()); - assert(server); - - HandleScope scope; - - if (args.Length() == 0) { - Local exception = Exception::TypeError( - String::New("First argument must be a port number")); - return ThrowException(exception); - } - - String::AsciiValue port(args[0]->ToString()); - -#ifndef DNS_MAXNAME -# define DNS_MAXNAME 1024 -#endif - - char host[DNS_MAXNAME+1] = "\0"; - int backlog = 128; - - if (args.Length() == 2) { - if (args[1]->IsInt32()) { - backlog = args[1]->Int32Value(); - } else if (args[1]->IsString()) { - args[1]->ToString()->WriteAscii(host, 0, DNS_MAXNAME+1); - } - } else if (args.Length() > 2) { - if (args[1]->IsString()) { - args[1]->ToString()->WriteAscii(host, 0, DNS_MAXNAME+1); - } - - if (!args[2]->IsInt32()) { - return ThrowException( - Exception::TypeError(String::New("backlog must be an integer"))); - } - - backlog = args[2]->Int32Value(); - } - - // For servers call getaddrinfo inline. This is blocking but it shouldn't - // matter much. If someone actually complains then simply swap it out - // with a libeio call. - struct addrinfo * address = NULL, - * address_list = NULL; - - int r = getaddrinfo(strlen(host) ? - host : NULL, *port, &server_tcp_hints, &address_list); - - if (r != 0) { - Local exception = Exception::Error(String::New(gai_strerror(r))); - return ThrowException(exception); - } - - address = AddressDefaultToIPv4(address_list); - - server->Listen(address->ai_addr, backlog); - - if (address_list) freeaddrinfo(address_list); - - if (server->server_.errorno) { - Local e = Exception::Error( - String::NewSymbol(strerror(server->server_.errorno))); - Local obj = e->ToObject(); - obj->Set(String::NewSymbol("errno"), Integer::New(server->server_.errorno)); - return ThrowException(e); - } - - return Undefined(); -} - -#if EVCOM_HAVE_GNUTLS - -Handle Server::SetSecure(const Arguments& args) { - Server *server = ObjectWrap::Unwrap(args.Holder()); - assert(server); - - int r; - - server->secure_ = true; - gnutls_certificate_allocate_credentials(&server->credentials); - - - if (args[1]->IsString()) { - String::Utf8Value caString(args[1]->ToString()); - gnutls_datum_t datum = { reinterpret_cast(*caString) - , caString.length() - }; - r = gnutls_certificate_set_x509_trust_mem(server->credentials, - &datum, GNUTLS_X509_FMT_PEM); - } - - - if (args[2]->IsString()) { - String::Utf8Value crlString(args[2]->ToString()); - gnutls_datum_t datum = { reinterpret_cast(*crlString) - , crlString.length() - }; - r = gnutls_certificate_set_x509_crl_mem(server->credentials, - &datum, GNUTLS_X509_FMT_PEM); - } - - if (args[3]->IsString() && args[4]->IsString()) { - String::Utf8Value keyString(args[3]->ToString()); - String::Utf8Value certString(args[4]->ToString()); - gnutls_datum_t datum_key = { reinterpret_cast(*keyString) - , keyString.length() - }; - gnutls_datum_t datum_cert = { reinterpret_cast(*certString) - , certString.length() - }; - r = gnutls_certificate_set_x509_key_mem(server->credentials, - &datum_cert, &datum_key, - GNUTLS_X509_FMT_PEM); - } - - return Undefined(); -} - -#endif - -Handle Server::Close(const Arguments& args) { - Server *server = ObjectWrap::Unwrap(args.Holder()); - assert(server); - - server->Close(); - return Undefined(); -} - -} // namespace node - - - - -#if EVCOM_HAVE_GNUTLS -void init_tls_session(evcom_stream* stream_, - gnutls_certificate_credentials_t credentials, - gnutls_connection_end_t session_type) { - gnutls_init(&stream_->session, - session_type); - if (session_type == GNUTLS_SERVER) { - gnutls_certificate_server_set_request(stream_->session, - GNUTLS_CERT_REQUEST); - } - gnutls_set_default_priority(stream_->session); - const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - const int proto_type_priority[] = { GNUTLS_TLS1_0, - GNUTLS_TLS1_1, - GNUTLS_SSL3, - 0}; - gnutls_certificate_type_set_priority(stream_->session, - cert_type_priority); - gnutls_protocol_set_priority(stream_->session, - proto_type_priority); - gnutls_credentials_set(stream_->session, - GNUTLS_CRD_CERTIFICATE, - credentials); - evcom_stream_set_secure_session(stream_, - stream_->session); -} - - -/* This function will try to verify the peer's certificate chain, and - * also check if the hostname matches, and the activation, expiration dates. - */ -int verify_certificate_chain(gnutls_session_t session, - const char *hostname, - const gnutls_datum_t * cert_chain, - int cert_chain_length, - gnutls_x509_crl_t *crl_list, - int crl_list_size, - gnutls_x509_crt_t *ca_list, - int ca_list_size) { - int r = 0; - int i; - int ss = 0; - gnutls_x509_crt_t *cert; - - if ((cert_chain_length == 0) || (cert_chain == NULL)) { - return JS_GNUTLS_CERT_UNDEFINED; - } - cert = (gnutls_x509_crt_t *)malloc(sizeof(*cert) * cert_chain_length); - - /* Import all the certificates in the chain to - * native certificate format. - */ - for (i = 0; i < cert_chain_length; i++) { - gnutls_x509_crt_init(&cert[i]); - gnutls_x509_crt_import(cert[i], &cert_chain[i], GNUTLS_X509_FMT_DER); - } - - /* If the last certificate in the chain is self signed ignore it. - * That is because we want to check against our trusted certificate - * list. - */ - - if (gnutls_x509_crt_check_issuer(cert[cert_chain_length - 1], - cert[cert_chain_length - 1]) > 0 - && cert_chain_length > 0) { - cert_chain_length--; - ss = 1; - } - - /* Now verify the certificates against their issuers - * in the chain. - */ - for (i = 1; i < cert_chain_length; i++) { - r = verify_cert2(cert[i - 1], cert[i], crl_list, crl_list_size); - if (r < 0) goto out; - } - - /* Here we must verify the last certificate in the chain against - * our trusted CA list. - */ - - if (cert_chain_length>0) { - r = verify_last_cert(cert[cert_chain_length - 1], ca_list, ca_list_size, - crl_list, crl_list_size); - if (r < 0) goto out; - } else { - r = verify_last_cert(cert[0], ca_list, ca_list_size, - crl_list, crl_list_size); - if (r < 0) goto out; - } - - /* Check if the name in the first certificate matches our destination! - */ - if (hostname != NULL) { - if (!gnutls_x509_crt_check_hostname(cert[0], hostname)) { - r = JS_GNUTLS_CERT_DOES_NOT_MATCH_HOSTNAME; - } - } - - out: - - for (i = 0; i < cert_chain_length+ss; i++) { - gnutls_x509_crt_deinit(cert[i]); - } - - return r; -} - - -/* Verifies a certificate against an other certificate - * which is supposed to be it's issuer. Also checks the - * crl_list if the certificate is revoked. - */ -int verify_cert2(gnutls_x509_crt_t crt, - gnutls_x509_crt_t issuer, - gnutls_x509_crl_t * crl_list, - int crl_list_size) { - unsigned int output; - int ret; - time_t now = time(0); - - gnutls_x509_crt_verify(crt, &issuer, 1, 0, &output); - - if (output & GNUTLS_CERT_INVALID) { - if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) { - return JS_GNUTLS_CERT_SIGNER_NOT_FOUND; - } - if (output & GNUTLS_CERT_SIGNER_NOT_CA) { - return JS_GNUTLS_CERT_SIGNER_NOT_CA; - } - return JS_GNUTLS_CERT_SIGNER_NOT_CA; - } - - - /* Now check the expiration dates. - */ - if (gnutls_x509_crt_get_activation_time(crt) > now) { - return JS_GNUTLS_CERT_NOT_ACTIVATED; - } - - if (gnutls_x509_crt_get_expiration_time(crt) < now) { - return JS_GNUTLS_CERT_EXPIRED; - } - - /* Check if the certificate is revoked. - */ - ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); - if (ret == 1) { - return JS_GNUTLS_CERT_REVOKED; - } - - return JS_GNUTLS_CERT_VALIDATED; -} - - -/* Verifies a certificate against our trusted CA list. - * Also checks the crl_list if the certificate is revoked. - */ -int verify_last_cert(gnutls_x509_crt_t crt, - gnutls_x509_crt_t * ca_list, - int ca_list_size, - gnutls_x509_crl_t * crl_list, - int crl_list_size) { - unsigned int output; - int ret; - time_t now = time(0); - - gnutls_x509_crt_verify(crt, ca_list, ca_list_size, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &output); - - if (output & GNUTLS_CERT_INVALID) { - if (output & GNUTLS_CERT_SIGNER_NOT_CA) { - return JS_GNUTLS_CERT_SIGNER_NOT_CA; - } - return JS_GNUTLS_CERT_INVALID; - } - - - /* Now check the expiration dates. - */ - if (gnutls_x509_crt_get_activation_time(crt) > now) { - return JS_GNUTLS_CERT_NOT_ACTIVATED; - } - - if (gnutls_x509_crt_get_expiration_time(crt) < now) { - return JS_GNUTLS_CERT_EXPIRED; - } - - /* Check if the certificate is revoked. - */ - ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); - if (ret == 1) { - return JS_GNUTLS_CERT_REVOKED; - } - - return JS_GNUTLS_CERT_VALIDATED; -} -#endif // EVCOM_HAVE_GNUTLS - diff --git a/src/node_net.h b/src/node_net.h deleted file mode 100644 index 8ad1471a6a..0000000000 --- a/src/node_net.h +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2009 Ryan Dahl -#ifndef SRC_NET_H_ -#define SRC_NET_H_ - -#include -#include -#include -#include - -#if EVCOM_HAVE_GNUTLS -#include -#include -#endif - - -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 Write(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 Pause(const v8::Arguments& args); - static v8::Handle Resume(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); - - #if EVCOM_HAVE_GNUTLS - static v8::Handle SetSecure(const v8::Arguments& args); - static v8::Handle VerifyPeer(const v8::Arguments& args); - static v8::Handle GetPeerCertificate(const v8::Arguments& args); - #endif - - Connection() : EventEmitter() { - encoding_ = BINARY; - - host_ = NULL; - port_ = NULL; - - Init(); - } - virtual ~Connection(); - - int Connect(struct sockaddr *address) { - return evcom_stream_connect(&stream_, address); - } - - ssize_t Write(const char *buf, size_t len) { - return evcom_stream_write(&stream_, buf, len); - } - - void Close() { - evcom_stream_close(&stream_); - } - - void ForceClose() { - evcom_stream_force_close(&stream_); - } - - void Pause() { - evcom_stream_read_pause(&stream_); - } - - void Resume() { - 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(); - virtual void OnDrain(); - - v8::Local GetProtocol(); - - enum evcom_stream_state ReadyState() { - return evcom_stream_state(&stream_); - } - - enum encoding encoding_; - bool resolving_; - bool secure_; - #if EVCOM_HAVE_GNUTLS - gnutls_certificate_credentials_t credentials; - #endif - - 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->refs_); - 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); - - #if EVCOM_HAVE_GNUTLS - if (connection->secure_) { - if (connection->stream_.session) { - gnutls_deinit(connection->stream_.session); - connection->stream_.session = NULL; - } - if (!connection->stream_.server && connection->credentials) { - gnutls_certificate_free_credentials(connection->credentials); - connection->credentials = NULL; - } - } - #endif - - connection->OnClose(); - - assert(connection->refs_); - - connection->Unref(); - } - - static void on_timeout(evcom_stream *s) { - Connection *connection = static_cast(s->data); - connection->OnTimeout(); - } - - static void on_drain(evcom_stream *s) { - Connection *connection = static_cast(s->data); - connection->OnDrain(); - } - - 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); - #if EVCOM_HAVE_GNUTLS - static v8::Handle SetSecure(const v8::Arguments& args); - #endif - - Server() : EventEmitter() { - evcom_server_init(&server_); - server_.on_connection = Server::on_connection; - server_.on_close = Server::on_close; - server_.data = this; - secure_ = false; - } - - 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_); - Ref(); - 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->Unref(); - } - - evcom_server server_; - - #if EVCOM_HAVE_GNUTLS - gnutls_certificate_credentials_t credentials; - #endif - bool secure_; -}; - -} // namespace node -#endif // SRC_NET_H_ - -#if EVCOM_HAVE_GNUTLS -void init_tls_session(evcom_stream* stream_, - gnutls_certificate_credentials_t credentials, - gnutls_connection_end_t session_type); - -int verify_certificate_chain(gnutls_session_t session, - const char *hostname, - const gnutls_datum_t * cert_chain, - int cert_chain_length, - gnutls_x509_crl_t *crl_list, - int crl_list_size, - gnutls_x509_crt_t *ca_list, - int ca_list_size); - -int verify_cert2(gnutls_x509_crt_t crt, - gnutls_x509_crt_t issuer, - gnutls_x509_crl_t * crl_list, - int crl_list_size); - -int verify_last_cert(gnutls_x509_crt_t crt, - gnutls_x509_crt_t * ca_list, - int ca_list_size, - gnutls_x509_crl_t * crl_list, - int crl_list_size); - -#define JS_GNUTLS_CERT_VALIDATED 1 -#define JS_GNUTLS_CERT_UNDEFINED 0 - -#define JS_GNUTLS_CERT_SIGNER_NOT_FOUND -100 -#define JS_GNUTLS_CERT_SIGNER_NOT_CA -101 -#define JS_GNUTLS_CERT_INVALID -102 -#define JS_GNUTLS_CERT_NOT_ACTIVATED -103 -#define JS_GNUTLS_CERT_EXPIRED -104 -#define JS_GNUTLS_CERT_REVOKED -105 -#define JS_GNUTLS_CERT_DOES_NOT_MATCH_HOSTNAME -106 - -#endif diff --git a/src/node_net2.cc b/src/node_net2.cc index b554c69ac3..4d0eacd64b 100644 --- a/src/node_net2.cc +++ b/src/node_net2.cc @@ -14,6 +14,8 @@ #include #include /* inet_pton */ +#include + #include #include diff --git a/wscript b/wscript index d6ea5dd621..f40dec4aa9 100644 --- a/wscript +++ b/wscript @@ -295,22 +295,6 @@ def build(bld): bld.add_subdirs('deps/libeio') - - ### evcom - evcom = bld.new_task_gen("cc") - evcom.source = "deps/evcom/evcom.c" - if not bld.env["USE_SYSTEM"]: - evcom.includes = "deps/evcom/ deps/libev/" - else: - evcom.includes = "deps/evcom/" - evcom.name = "evcom" - evcom.target = "evcom" - evcom.uselib = "GPGERROR GNUTLS" - evcom.install_path = None - if bld.env["USE_DEBUG"]: - evcom.clone("debug") - bld.install_files('${PREFIX}/include/node/', 'deps/evcom/evcom.h') - ### http_parser http_parser = bld.new_task_gen("cc") http_parser.source = "deps/http_parser/http_parser.c" @@ -397,8 +381,6 @@ def build(bld): src/node_cares.cc src/node_events.cc src/node_file.cc - src/node_http.cc - src/node_net.cc src/node_signal_watcher.cc src/node_stat_watcher.cc src/node_stdio.cc @@ -415,7 +397,6 @@ def build(bld): deps/libev deps/c-ares deps/libeio - deps/evcom deps/http_parser deps/coupling """ @@ -423,18 +404,17 @@ def build(bld): node.includes += ' deps/c-ares/' + bld.env['DEST_OS'] + '-' + bld.env['DEST_CPU'] - node.add_objects = 'cares ev eio evcom http_parser coupling' + node.add_objects = 'cares ev eio http_parser coupling' node.uselib_local = '' node.uselib = 'RT OPENSSL GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL' else: node.includes = """ src/ deps/libeio - deps/evcom deps/http_parser deps/coupling """ - node.add_objects = 'eio evcom http_parser coupling' + node.add_objects = 'eio http_parser coupling' node.uselib_local = 'eio' node.uselib = 'RT EV OPENSSL GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL' @@ -478,7 +458,6 @@ def build(bld): src/node.h src/node_object_wrap.h src/node_events.h - src/node_net.h """) # Only install the man page if it exists.