diff --git a/src/unix/udp.c b/src/unix/udp.c index 68e2e4a8a..b578e7bc1 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -30,6 +30,7 @@ #if defined(__MVS__) #include #endif +#include #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -232,8 +233,16 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { h.msg_namelen = 0; } else { h.msg_name = &req->addr; - h.msg_namelen = req->addr.ss_family == AF_INET6 ? - sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); + if (req->addr.ss_family == AF_INET6) + h.msg_namelen = sizeof(struct sockaddr_in6); + else if (req->addr.ss_family == AF_INET) + h.msg_namelen = sizeof(struct sockaddr_in); + else if (req->addr.ss_family == AF_UNIX) + h.msg_namelen = sizeof(struct sockaddr_un); + else { + assert(0 && "unsupported address family"); + abort(); + } } h.msg_iov = (struct iovec*) req->bufs; h.msg_iovlen = req->nbufs; diff --git a/src/uv-common.c b/src/uv-common.c index 986103361..066eb31d0 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -34,6 +34,7 @@ # include /* malloc */ #else # include /* if_nametoindex */ +# include /* AF_UNIX, sockaddr_un */ #endif @@ -376,6 +377,10 @@ int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) { addrlen = sizeof(struct sockaddr_in); else if (addr->sa_family == AF_INET6) addrlen = sizeof(struct sockaddr_in6); +#if defined(AF_UNIX) && !defined(_WIN32) + else if (addr->sa_family == AF_UNIX) + addrlen = sizeof(struct sockaddr_un); +#endif else return UV_EINVAL; } else { diff --git a/test/test-list.h b/test/test-list.h index 51b9f7dc9..ace501c97 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -155,6 +155,9 @@ TEST_DECLARE (udp_open) TEST_DECLARE (udp_open_twice) TEST_DECLARE (udp_open_bound) TEST_DECLARE (udp_open_connect) +#ifndef _WIN32 +TEST_DECLARE (udp_send_unix) +#endif TEST_DECLARE (udp_try_send) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) @@ -657,6 +660,9 @@ TASK_LIST_START TEST_ENTRY (udp_open_bound) TEST_ENTRY (udp_open_connect) TEST_HELPER (udp_open_connect, udp4_echo_server) +#ifndef _WIN32 + TEST_ENTRY (udp_send_unix) +#endif TEST_ENTRY (pipe_bind_error_addrinuse) TEST_ENTRY (pipe_bind_error_addrnotavail) diff --git a/test/test-udp-open.c b/test/test-udp-open.c index 0390bae2e..dee408baa 100644 --- a/test/test-udp-open.c +++ b/test/test-udp-open.c @@ -27,6 +27,8 @@ #ifndef _WIN32 # include +# include +# include #endif static int send_cb_called = 0; @@ -296,3 +298,53 @@ TEST_IMPL(udp_open_connect) { MAKE_VALGRIND_HAPPY(); return 0; } + +#ifndef _WIN32 +TEST_IMPL(udp_send_unix) { + /* Test that "uv_udp_send()" supports sending over + a "sockaddr_un" address. */ + struct sockaddr_un addr; + uv_udp_t handle; + uv_udp_send_t req; + uv_loop_t* loop; + uv_buf_t buf = uv_buf_init("PING", 4); + int fd; + int r; + + loop = uv_default_loop(); + + memset(&addr, 0, sizeof addr); + addr.sun_family = AF_UNIX; + ASSERT(strlen(TEST_PIPENAME) < sizeof(addr.sun_path)); + memcpy(addr.sun_path, TEST_PIPENAME, strlen(TEST_PIPENAME)); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + ASSERT(fd >= 0); + + unlink(TEST_PIPENAME); + ASSERT(0 == bind(fd, (const struct sockaddr*)&addr, sizeof addr)); + ASSERT(0 == listen(fd, 1)); + + r = uv_udp_init(loop, &handle); + ASSERT(r == 0); + r = uv_udp_open(&handle, fd); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + r = uv_udp_send(&req, + &handle, + &buf, + 1, + (const struct sockaddr*) &addr, + NULL); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&handle, NULL); + uv_run(loop, UV_RUN_DEFAULT); + close(fd); + unlink(TEST_PIPENAME); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif