static int server_closed;
static uv_tcp_t server;
+static int server6_closed;
+static uv_tcp_t server6;
+
static void after_write(uv_req_t* req, int status);
static void after_read(uv_stream_t*, ssize_t nread, uv_buf_t buf);
if (buf.base[i] == 'Q') {
uv_close((uv_handle_t*)&server, on_server_close);
server_closed = 1;
+ uv_close((uv_handle_t*)&server6, on_server_close);
+ server6_closed = 1;
}
}
}
uv_tcp_t* handle;
int r;
+ if (status != 0) {
+ fprintf(stderr, "Connect error %d\n", uv_last_error());
+ }
ASSERT(status == 0);
handle = (uv_tcp_t*) malloc(sizeof *handle);
uv_tcp_init(handle);
+ /* associate server with stream */
+ handle->data = server;
+
r = uv_accept(server, (uv_stream_t*)handle);
ASSERT(r == 0);
static void on_server_close(uv_handle_t* handle) {
- ASSERT(handle == (uv_handle_t*)&server);
+ ASSERT(handle == (uv_handle_t*)&server || handle == (uv_handle_t*)&server6);
}
static int echo_start(int port) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);
+ struct sockaddr_in6 addr6 = uv_ip6_addr("::1", port);
int r;
r = uv_tcp_init(&server);
return 1;
}
+ r = uv_tcp_init(&server6);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind6(&server6, addr6);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Bind6 error\n");
+ return 1;
+ }
+
+ r = uv_tcp_listen(&server6, 128, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
return 0;
}
/* Pop the req off tcp->write_queue. */
ngx_queue_remove(&req->queue);
- free(req->bufs); /* FIXME: we should not be allocing for each read */
+ if (req->bufs != req->bufsml) {
+ free(req->bufs);
+ }
req->bufs = NULL;
/* Add it to the write_completed_queue where it will have its
}
+/* TODO: Implement IPv6 Connect for UNIX */
+int uv_tcp_connect6(uv_req_t* req, struct sockaddr_in6 addr) {
+ uv_err_new_artificial((uv_handle_t*)req->handle, UV_EAFNOSUPPORT);
+ return -1;
+}
+
+
static size_t uv__buf_count(uv_buf_t bufs[], int bufcnt) {
size_t total = 0;
int i;
ngx_queue_init(&req->queue);
req->type = UV_WRITE;
- /* TODO: Don't malloc for each write... */
- req->bufs = malloc(sizeof(uv_buf_t) * bufcnt);
+
+ if (bufcnt < UV_REQ_BUFSML_SIZE) {
+ req->bufs = req->bufsml;
+ }
+ else {
+ req->bufs = malloc(sizeof(uv_buf_t) * bufcnt);
+ }
+
memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t));
req->bufcnt = bufcnt;
+ // fprintf(stderr, "cnt: %d bufs: %p bufsml: %p\n", bufcnt, req->bufs, req->bufsml);
+
req->write_index = 0;
tcp->write_queue_size += uv__buf_count(bufs, bufcnt);
static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs;
static LPFN_DISCONNECTEX pDisconnectEx;
static LPFN_TRANSMITFILE pTransmitFile;
+/* need IPv6 versions of winsock extension functions */
+static LPFN_CONNECTEX pConnectEx6;
+static LPFN_ACCEPTEX pAcceptEx6;
+static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6;
+static LPFN_DISCONNECTEX pDisconnectEx6;
+static LPFN_TRANSMITFILE pTransmitFile6;
/*
#define UV_HANDLE_SHUT 0x0200
#define UV_HANDLE_ENDGAME_QUEUED 0x0400
#define UV_HANDLE_BIND_ERROR 0x1000
+#define UV_HANDLE_IPV6 0x2000
/*
* Private uv_req flags.
/* Ip address used to bind to any port at any interface */
static struct sockaddr_in uv_addr_ip4_any_;
+static struct sockaddr_in6 uv_addr_ip6_any_;
/* A zero-size buffer for use by uv_read */
int errorno;
LARGE_INTEGER timer_frequency;
SOCKET dummy;
+ SOCKET dummy6;
/* Initialize winsock */
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
/* Set implicit binding address used by connectEx */
uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0);
+ uv_addr_ip6_any_ = uv_ip6_addr("::1", 0);
/* Retrieve the needed winsock extension function pointers. */
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
uv_fatal_error(WSAGetLastError(), "closesocket");
}
+/* need IPv6 versions of winsock extension functions */
+ dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
+ if (dummy == INVALID_SOCKET) {
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+
+ uv_get_extension_function(dummy6,
+ wsaid_connectex,
+ (void**)&pConnectEx6);
+ uv_get_extension_function(dummy6,
+ wsaid_acceptex,
+ (void**)&pAcceptEx6);
+ uv_get_extension_function(dummy6,
+ wsaid_getacceptexsockaddrs,
+ (void**)&pGetAcceptExSockAddrs6);
+ uv_get_extension_function(dummy6,
+ wsaid_disconnectex,
+ (void**)&pDisconnectEx6);
+ uv_get_extension_function(dummy6,
+ wsaid_transmitfile,
+ (void**)&pTransmitFile6);
+
+ if (closesocket(dummy6) == SOCKET_ERROR) {
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+ }
+
+
/* Create an I/O completion port */
uv_iocp_ = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
if (uv_iocp_ == NULL) {
uv_set_sys_error(WSAEFAULT);
return -1;
}
-
+ handle->flags |= UV_HANDLE_IPV6;
return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6));
}
BOOL success;
DWORD bytes;
SOCKET accept_socket;
+ short family;
+ LPFN_ACCEPTEX pAcceptExFamily;
assert(handle->flags & UV_HANDLE_LISTENING);
assert(handle->accept_socket == INVALID_SOCKET);
req->type = UV_ACCEPT;
req->flags |= UV_REQ_PENDING;
+ /* choose family and extension function */
+ if ((handle->flags & UV_HANDLE_IPV6) != 0) {
+ family = AF_INET6;
+ pAcceptExFamily = pAcceptEx6;
+ } else {
+ family = AF_INET;
+ pAcceptExFamily = pAcceptEx;
+ }
+
/* Open a socket for the accepted connection. */
- accept_socket = socket(AF_INET, SOCK_STREAM, 0);
+ accept_socket = socket(family, SOCK_STREAM, 0);
if (accept_socket == INVALID_SOCKET) {
req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req);
/* Prepare the overlapped structure. */
memset(&(req->overlapped), 0, sizeof(req->overlapped));
- success = pAcceptEx(handle->socket,
- accept_socket,
- (void*)&handle->accept_buffer,
- 0,
- sizeof(struct sockaddr_storage),
- sizeof(struct sockaddr_storage),
- &bytes,
- &req->overlapped);
+ success = pAcceptExFamily(handle->socket,
+ accept_socket,
+ (void*)&handle->accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &req->overlapped);
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
/* Make this req pending reporting an error. */
}
+int uv_tcp_connect6(uv_req_t* req, struct sockaddr_in6 addr) {
+ int addrsize = sizeof(struct sockaddr_in6);
+ BOOL success;
+ DWORD bytes;
+ uv_tcp_t* handle = (uv_tcp_t*)req->handle;
+
+ assert(!(req->flags & UV_REQ_PENDING));
+
+ if (handle->flags & UV_HANDLE_BIND_ERROR) {
+ uv_last_error_ = handle->error;
+ return -1;
+ }
+
+ if (addr.sin6_family != AF_INET6) {
+ uv_set_sys_error(WSAEFAULT);
+ return -1;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND) &&
+ uv_tcp_bind6(handle, uv_addr_ip6_any_) < 0)
+ return -1;
+
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
+ req->type = UV_CONNECT;
+
+ success = pConnectEx6(handle->socket,
+ (struct sockaddr*)&addr,
+ addrsize,
+ NULL,
+ 0,
+ &bytes,
+ &req->overlapped);
+
+ if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+ uv_set_sys_error(WSAGetLastError());
+ return -1;
+ }
+
+ req->flags |= UV_REQ_PENDING;
+ handle->reqs_pending++;
+
+ return 0;
+}
+
+
static size_t uv_count_bufs(uv_buf_t bufs[], int count) {
size_t bytes = 0;
int i;