linux: support abstract unix sockets (#4030)
Add two new APIs for binding and connecting to abstract UNIX sockets. Fixes: https://github.com/libuv/libuv/issues/4028
This commit is contained in:
parent
e8ec610f28
commit
b9b6db052b
@ -55,17 +55,55 @@ API
|
|||||||
|
|
||||||
Bind the pipe to a file path (Unix) or a name (Windows).
|
Bind the pipe to a file path (Unix) or a name (Windows).
|
||||||
|
|
||||||
|
Does not support Linux abstract namespace sockets,
|
||||||
|
unlike :c:func:`uv_pipe_bind2`.
|
||||||
|
|
||||||
|
Alias for ``uv_pipe_bind2(handle, name, strlen(name), 0)``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
|
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||||
92 and 108 bytes.
|
typically between 92 and 108 bytes.
|
||||||
|
|
||||||
|
.. c:function:: int uv_pipe_bind2(uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags)
|
||||||
|
|
||||||
|
Bind the pipe to a file path (Unix) or a name (Windows).
|
||||||
|
|
||||||
|
``flags`` must be zero. Returns ``UV_EINVAL`` for unsupported flags
|
||||||
|
without performing the bind operation.
|
||||||
|
|
||||||
|
Supports Linux abstract namespace sockets. ``namelen`` must include
|
||||||
|
the leading nul byte but not the trailing nul byte.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||||
|
typically between 92 and 108 bytes.
|
||||||
|
|
||||||
.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)
|
.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)
|
||||||
|
|
||||||
Connect to the Unix domain socket or the named pipe.
|
Connect to the Unix domain socket or the Windows named pipe.
|
||||||
|
|
||||||
|
Does not support Linux abstract namespace sockets,
|
||||||
|
unlike :c:func:`uv_pipe_connect2`.
|
||||||
|
|
||||||
|
Alias for ``uv_pipe_connect2(req, handle, name, strlen(name), 0, cb)``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
|
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||||
92 and 108 bytes.
|
typically between 92 and 108 bytes.
|
||||||
|
|
||||||
|
.. c:function:: void uv_pipe_connect2(uv_connect_t* req, uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags, uv_connect_cb cb)
|
||||||
|
|
||||||
|
Connect to the Unix domain socket or the Windows named pipe.
|
||||||
|
|
||||||
|
``flags`` must be zero. Returns ``UV_EINVAL`` for unsupported flags
|
||||||
|
without performing the connect operation.
|
||||||
|
|
||||||
|
Supports Linux abstract namespace sockets. ``namelen`` must include
|
||||||
|
the leading nul byte but not the trailing nul byte.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes,
|
||||||
|
typically between 92 and 108 bytes.
|
||||||
|
|
||||||
.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)
|
.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)
|
||||||
|
|
||||||
|
|||||||
10
include/uv.h
10
include/uv.h
@ -823,10 +823,20 @@ struct uv_pipe_s {
|
|||||||
UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
|
UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
|
||||||
UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
|
UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
|
||||||
UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
|
UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
|
||||||
|
UV_EXTERN int uv_pipe_bind2(uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
size_t namelen,
|
||||||
|
unsigned int flags);
|
||||||
UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
|
UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
|
||||||
uv_pipe_t* handle,
|
uv_pipe_t* handle,
|
||||||
const char* name,
|
const char* name,
|
||||||
uv_connect_cb cb);
|
uv_connect_cb cb);
|
||||||
|
UV_EXTERN int uv_pipe_connect2(uv_connect_t* req,
|
||||||
|
uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
size_t namelen,
|
||||||
|
unsigned int flags,
|
||||||
|
uv_connect_cb cb);
|
||||||
UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
|
UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
|
||||||
char* buffer,
|
char* buffer,
|
||||||
size_t* size);
|
size_t* size);
|
||||||
|
|||||||
@ -304,7 +304,7 @@ typedef struct {
|
|||||||
struct uv__queue write_completed_queue; \
|
struct uv__queue write_completed_queue; \
|
||||||
|
|
||||||
#define UV_PIPE_PRIVATE_FIELDS \
|
#define UV_PIPE_PRIVATE_FIELDS \
|
||||||
const char* pipe_fname; /* strdup'ed */
|
const char* pipe_fname; /* NULL or strdup'ed */
|
||||||
|
|
||||||
#define UV_POLL_PRIVATE_FIELDS \
|
#define UV_POLL_PRIVATE_FIELDS \
|
||||||
uv__io_t io_watcher;
|
uv__io_t io_watcher;
|
||||||
|
|||||||
@ -41,26 +41,56 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
|||||||
|
|
||||||
|
|
||||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||||
|
return uv_pipe_bind2(handle, name, strlen(name), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_pipe_bind2(uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
size_t namelen,
|
||||||
|
unsigned int flags) {
|
||||||
struct sockaddr_un saddr;
|
struct sockaddr_un saddr;
|
||||||
const char* pipe_fname;
|
char* pipe_fname;
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
pipe_fname = NULL;
|
pipe_fname = NULL;
|
||||||
|
|
||||||
|
if (flags != 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (namelen == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
#ifndef __linux__
|
||||||
|
/* Abstract socket namespace only works on Linux. */
|
||||||
|
if (*name == '\0')
|
||||||
|
return UV_EINVAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Truncate long paths. Documented behavior. */
|
||||||
|
if (namelen > sizeof(saddr.sun_path))
|
||||||
|
namelen = sizeof(saddr.sun_path);
|
||||||
|
|
||||||
/* Already bound? */
|
/* Already bound? */
|
||||||
if (uv__stream_fd(handle) >= 0)
|
if (uv__stream_fd(handle) >= 0)
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
if (uv__is_closing(handle)) {
|
|
||||||
return UV_EINVAL;
|
|
||||||
}
|
|
||||||
/* Make a copy of the file name, it outlives this function's scope. */
|
|
||||||
pipe_fname = uv__strdup(name);
|
|
||||||
if (pipe_fname == NULL)
|
|
||||||
return UV_ENOMEM;
|
|
||||||
|
|
||||||
/* We've got a copy, don't touch the original any more. */
|
if (uv__is_closing(handle))
|
||||||
name = NULL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
/* Make a copy of the file path unless it is an abstract socket.
|
||||||
|
* We unlink the file later but abstract sockets disappear
|
||||||
|
* automatically since they're not real file system entities.
|
||||||
|
*/
|
||||||
|
if (*name != '\0') {
|
||||||
|
pipe_fname = uv__strdup(name);
|
||||||
|
if (pipe_fname == NULL)
|
||||||
|
return UV_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@ -68,7 +98,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
|||||||
sockfd = err;
|
sockfd = err;
|
||||||
|
|
||||||
memset(&saddr, 0, sizeof saddr);
|
memset(&saddr, 0, sizeof saddr);
|
||||||
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
|
memcpy(&saddr.sun_path, name, namelen);
|
||||||
saddr.sun_family = AF_UNIX;
|
saddr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
||||||
@ -83,12 +113,12 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
|||||||
|
|
||||||
/* Success. */
|
/* Success. */
|
||||||
handle->flags |= UV_HANDLE_BOUND;
|
handle->flags |= UV_HANDLE_BOUND;
|
||||||
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
|
handle->pipe_fname = pipe_fname; /* NULL or a strdup'ed copy. */
|
||||||
handle->io_watcher.fd = sockfd;
|
handle->io_watcher.fd = sockfd;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_socket:
|
err_socket:
|
||||||
uv__free((void*)pipe_fname);
|
uv__free(pipe_fname);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,11 +206,40 @@ void uv_pipe_connect(uv_connect_t* req,
|
|||||||
uv_pipe_t* handle,
|
uv_pipe_t* handle,
|
||||||
const char* name,
|
const char* name,
|
||||||
uv_connect_cb cb) {
|
uv_connect_cb cb) {
|
||||||
|
uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_pipe_connect2(uv_connect_t* req,
|
||||||
|
uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
size_t namelen,
|
||||||
|
unsigned int flags,
|
||||||
|
uv_connect_cb cb) {
|
||||||
struct sockaddr_un saddr;
|
struct sockaddr_un saddr;
|
||||||
int new_sock;
|
int new_sock;
|
||||||
int err;
|
int err;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
if (flags != 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (namelen == 0)
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
#ifndef __linux__
|
||||||
|
/* Abstract socket namespace only works on Linux. */
|
||||||
|
if (*name == '\0')
|
||||||
|
return UV_EINVAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Truncate long paths. Documented behavior. */
|
||||||
|
if (namelen > sizeof(saddr.sun_path))
|
||||||
|
namelen = sizeof(saddr.sun_path);
|
||||||
|
|
||||||
new_sock = (uv__stream_fd(handle) == -1);
|
new_sock = (uv__stream_fd(handle) == -1);
|
||||||
|
|
||||||
if (new_sock) {
|
if (new_sock) {
|
||||||
@ -191,7 +250,7 @@ void uv_pipe_connect(uv_connect_t* req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&saddr, 0, sizeof saddr);
|
memset(&saddr, 0, sizeof saddr);
|
||||||
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
|
memcpy(&saddr.sun_path, name, namelen);
|
||||||
saddr.sun_family = AF_UNIX;
|
saddr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -236,6 +295,7 @@ out:
|
|||||||
if (err)
|
if (err)
|
||||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -694,20 +694,42 @@ void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
|
|||||||
|
|
||||||
/* Creates a pipe server. */
|
/* Creates a pipe server. */
|
||||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||||
|
return uv_pipe_bind2(handle, name, strlen(name), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_pipe_bind2(uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
size_t namelen,
|
||||||
|
unsigned int flags) {
|
||||||
uv_loop_t* loop = handle->loop;
|
uv_loop_t* loop = handle->loop;
|
||||||
int i, err, nameSize;
|
int i, err, nameSize;
|
||||||
uv_pipe_accept_t* req;
|
uv_pipe_accept_t* req;
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namelen == 0) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*name == '\0') {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (handle->flags & UV_HANDLE_BOUND) {
|
if (handle->flags & UV_HANDLE_BOUND) {
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
return UV_EINVAL;
|
|
||||||
}
|
|
||||||
if (uv__is_closing(handle)) {
|
if (uv__is_closing(handle)) {
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
|
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
|
||||||
handle->pipe.serv.pending_instances = default_pending_pipe_instances;
|
handle->pipe.serv.pending_instances = default_pending_pipe_instances;
|
||||||
}
|
}
|
||||||
@ -818,13 +840,41 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
void uv_pipe_connect(uv_connect_t* req,
|
||||||
const char* name, uv_connect_cb cb) {
|
uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
uv_connect_cb cb) {
|
||||||
|
uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_pipe_connect2(uv_connect_t* req,
|
||||||
|
uv_pipe_t* handle,
|
||||||
|
const char* name,
|
||||||
|
size_t namelen,
|
||||||
|
unsigned int flags,
|
||||||
|
uv_connect_cb cb) {
|
||||||
uv_loop_t* loop = handle->loop;
|
uv_loop_t* loop = handle->loop;
|
||||||
int err, nameSize;
|
int err, nameSize;
|
||||||
HANDLE pipeHandle = INVALID_HANDLE_VALUE;
|
HANDLE pipeHandle = INVALID_HANDLE_VALUE;
|
||||||
DWORD duplex_flags;
|
DWORD duplex_flags;
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namelen == 0) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*name == '\0') {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
UV_REQ_INIT(req, UV_CONNECT);
|
UV_REQ_INIT(req, UV_CONNECT);
|
||||||
req->handle = (uv_stream_t*) handle;
|
req->handle = (uv_stream_t*) handle;
|
||||||
req->cb = cb;
|
req->cb = cb;
|
||||||
@ -882,7 +932,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
|||||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
|
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = GetLastError();
|
err = GetLastError();
|
||||||
@ -895,7 +945,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
|||||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (handle->name) {
|
if (handle->name) {
|
||||||
@ -911,7 +961,7 @@ error:
|
|||||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,11 +25,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# include <unistd.h> /* close */
|
# include <unistd.h> /* close */
|
||||||
#else
|
#else
|
||||||
@ -63,8 +58,14 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) {
|
|||||||
r = uv_pipe_getpeername(&pipe_client, buf, &len);
|
r = uv_pipe_getpeername(&pipe_client, buf, &len);
|
||||||
ASSERT(r == 0);
|
ASSERT(r == 0);
|
||||||
|
|
||||||
ASSERT(buf[len - 1] != 0);
|
if (*buf == '\0') { /* Linux abstract socket. */
|
||||||
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
|
const char expected[] = "\0" TEST_PIPENAME;
|
||||||
|
ASSERT_GE(len, sizeof(expected));
|
||||||
|
ASSERT_MEM_EQ(buf, expected, sizeof(expected));
|
||||||
|
} else {
|
||||||
|
ASSERT_NE(0, buf[len - 1]);
|
||||||
|
ASSERT_MEM_EQ(buf, TEST_PIPENAME, len);
|
||||||
|
}
|
||||||
|
|
||||||
len = sizeof buf;
|
len = sizeof buf;
|
||||||
r = uv_pipe_getsockname(&pipe_client, buf, &len);
|
r = uv_pipe_getsockname(&pipe_client, buf, &len);
|
||||||
@ -72,7 +73,6 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) {
|
|||||||
|
|
||||||
pipe_client_connect_cb_called++;
|
pipe_client_connect_cb_called++;
|
||||||
|
|
||||||
|
|
||||||
uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
|
uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
|
||||||
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
|
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
|
||||||
}
|
}
|
||||||
@ -162,47 +162,48 @@ TEST_IMPL(pipe_getsockname) {
|
|||||||
|
|
||||||
|
|
||||||
TEST_IMPL(pipe_getsockname_abstract) {
|
TEST_IMPL(pipe_getsockname_abstract) {
|
||||||
|
/* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */
|
||||||
|
static const char name[] = "\0" TEST_PIPENAME;
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
char buf[1024];
|
char buf[256];
|
||||||
size_t len;
|
size_t buflen;
|
||||||
int r;
|
|
||||||
int sock;
|
|
||||||
struct sockaddr_un sun;
|
|
||||||
socklen_t sun_len;
|
|
||||||
char abstract_pipe[] = "\0test-pipe";
|
|
||||||
|
|
||||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
buflen = sizeof(buf);
|
||||||
ASSERT(sock != -1);
|
memset(buf, 0, sizeof(buf));
|
||||||
|
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0));
|
||||||
sun_len = sizeof sun;
|
ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name), 0));
|
||||||
memset(&sun, 0, sun_len);
|
ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen));
|
||||||
sun.sun_family = AF_UNIX;
|
ASSERT_MEM_EQ(name, buf, sizeof(name));
|
||||||
memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);
|
ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server,
|
||||||
|
0,
|
||||||
r = bind(sock, (struct sockaddr*)&sun, sun_len);
|
pipe_server_connection_cb));
|
||||||
ASSERT(r == 0);
|
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0));
|
||||||
|
ASSERT_OK(uv_pipe_connect2(&connect_req,
|
||||||
r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
|
&pipe_client,
|
||||||
ASSERT(r == 0);
|
name,
|
||||||
r = uv_pipe_open(&pipe_server, sock);
|
sizeof(name),
|
||||||
ASSERT(r == 0);
|
0,
|
||||||
|
pipe_client_connect_cb));
|
||||||
len = sizeof buf;
|
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||||
r = uv_pipe_getsockname(&pipe_server, buf, &len);
|
ASSERT_EQ(1, pipe_client_connect_cb_called);
|
||||||
ASSERT(r == 0);
|
ASSERT_EQ(2, pipe_close_cb_called);
|
||||||
|
|
||||||
ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
|
|
||||||
|
|
||||||
uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
|
|
||||||
|
|
||||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
|
||||||
|
|
||||||
close(sock);
|
|
||||||
|
|
||||||
ASSERT(pipe_close_cb_called == 1);
|
|
||||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
|
/* On other platforms it should simply fail with UV_EINVAL. */
|
||||||
|
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0));
|
||||||
|
ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe_server, name, sizeof(name), 0));
|
||||||
|
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0));
|
||||||
|
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
|
||||||
|
ASSERT_EQ(UV_EINVAL, uv_pipe_connect2(&connect_req,
|
||||||
|
&pipe_client,
|
||||||
|
name,
|
||||||
|
sizeof(name),
|
||||||
|
0,
|
||||||
|
(uv_connect_cb) abort));
|
||||||
|
uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
|
||||||
|
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||||
|
ASSERT_EQ(2, pipe_close_cb_called);
|
||||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user