int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
+/* Enable/disable Nagle's algorithm. */
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
+
+/* Enable/disable TCP keep-alive.
+ *
+ * `ms` is the initial delay in seconds, ignored when `enable` is zero.
+ */
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay);
+
int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in);
int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6);
int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
void uv_freeaddrinfo(struct addrinfo* ai) {
- freeaddrinfo(ai);
+ if (ai)
+ freeaddrinfo(ai);
}
/* flags */
enum {
- UV_CLOSING = 0x00000001, /* uv_close() called but not finished. */
- UV_CLOSED = 0x00000002, /* close(2) finished. */
- UV_READING = 0x00000004, /* uv_read_start() called. */
- UV_SHUTTING = 0x00000008, /* uv_shutdown() called but not complete. */
- UV_SHUT = 0x00000010, /* Write side closed. */
- UV_READABLE = 0x00000020, /* The stream is readable */
- UV_WRITABLE = 0x00000040 /* The stream is writable */
+ UV_CLOSING = 0x01, /* uv_close() called but not finished. */
+ UV_CLOSED = 0x02, /* close(2) finished. */
+ UV_READING = 0x04, /* uv_read_start() called. */
+ UV_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
+ UV_SHUT = 0x10, /* Write side closed. */
+ UV_READABLE = 0x20, /* The stream is readable */
+ UV_WRITABLE = 0x40, /* The stream is writable */
+ UV_TCP_NODELAY = 0x080, /* Disable Nagle. */
+ UV_TCP_KEEPALIVE = 0x100 /* Turn on keep-alive. */
};
size_t uv__strlcpy(char* dst, const char* src, size_t size);
/* tcp */
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
+int uv__tcp_nodelay(uv_tcp_t* handle, int enable);
+int uv__tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay);
/* pipe */
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
stream->flags |= flags;
- /* Reuse the port address if applicable. */
- yes = 1;
- if (stream->type == UV_TCP
- && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- uv__set_sys_error(stream->loop, errno);
- return -1;
+ if (stream->type == UV_TCP) {
+ /* Reuse the port address if applicable. */
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) {
+ uv__set_sys_error(stream->loop, errno);
+ return -1;
+ }
+
+ if ((stream->flags & UV_TCP_NODELAY) &&
+ uv__tcp_nodelay((uv_tcp_t*)stream, 1)) {
+ return -1;
+ }
+
+ /* TODO Use delay the user passed in. */
+ if ((stream->flags & UV_TCP_KEEPALIVE) &&
+ uv__tcp_keepalive((uv_tcp_t*)stream, 1, 60)) {
+ return -1;
+ }
}
/* Associate the fd with each ev_io watcher. */
errno = saved_errno;
return status;
}
+
+
+int uv__tcp_nodelay(uv_tcp_t* handle, int enable) {
+ if (setsockopt(handle->fd,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ &enable,
+ sizeof enable) == -1) {
+ uv__set_sys_error(handle->loop, errno);
+ return -1;
+ }
+ return 0;
+}
+
+
+int uv__tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
+ if (setsockopt(handle->fd,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ &enable,
+ sizeof enable) == -1) {
+ uv__set_sys_error(handle->loop, errno);
+ return -1;
+ }
+
+#ifdef TCP_KEEPIDLE
+ if (enable && setsockopt(handle->fd,
+ IPPROTO_TCP,
+ TCP_KEEPIDLE,
+ &delay,
+ sizeof delay) == -1) {
+ uv__set_sys_error(handle->loop, errno);
+ return -1;
+ }
+#endif
+
+#ifdef TCP_KEEPALIVE
+ if (enable && setsockopt(handle->fd,
+ IPPROTO_TCP,
+ TCP_KEEPALIVE,
+ &delay,
+ sizeof delay) == -1) {
+ uv__set_sys_error(handle->loop, errno);
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
+ if (handle->fd != -1 && uv__tcp_nodelay(handle, enable))
+ return -1;
+
+ if (enable)
+ handle->flags |= UV_TCP_NODELAY;
+ else
+ handle->flags &= ~UV_TCP_NODELAY;
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
+ if (handle->fd != -1 && uv__tcp_keepalive(handle, enable, delay))
+ return -1;
+
+ if (enable)
+ handle->flags |= UV_TCP_KEEPALIVE;
+ else
+ handle->flags &= ~UV_TCP_KEEPALIVE;
+
+ /* TODO Store delay if handle->fd == -1 but don't want to enlarge
+ * uv_tcp_t with an int that's almost never used...
+ */
+
+ return 0;
+}
return uv_tcp_set_socket(tcp->loop, tcp, socket, 1);
}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
+ uv__set_artificial_error(handle->loop, UV_ENOSYS);
+ return -1;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, int delay) {
+ uv__set_artificial_error(handle->loop, UV_ENOSYS);
+ return -1;
+}
TEST_DECLARE (tcp_bind_localhost_ok)
TEST_DECLARE (tcp_listen_without_bind)
TEST_DECLARE (tcp_close)
+TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_error)
TEST_DECLARE (tcp_bind6_error_addrinuse)
TEST_DECLARE (tcp_bind6_error_addrnotavail)
TEST_ENTRY (tcp_bind_localhost_ok)
TEST_ENTRY (tcp_listen_without_bind)
TEST_ENTRY (tcp_close)
+ TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_error)
TEST_ENTRY (tcp_bind6_error_addrinuse)
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+TEST_IMPL(tcp_flags) {
+ uv_loop_t* loop;
+ uv_tcp_t handle;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_tcp_init(loop, &handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_nodelay(&handle, 1);
+ ASSERT(r == 0);
+
+ r = uv_tcp_keepalive(&handle, 1, 60);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&handle, NULL);
+
+ r = uv_run(loop);
+ ASSERT(r == 0);
+
+ return 0;
+}
'test/test-tcp-bind-error.c',
'test/test-tcp-bind6-error.c',
'test/test-tcp-close.c',
+ 'test/test-tcp-flags.c',
'test/test-tcp-connect-error.c',
'test/test-tcp-connect6-error.c',
'test/test-tcp-write-error.c',