win, unix: add pipe_peername implementation

PR-URL: https://github.com/libuv/libuv/pull/166
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Andrius Bentkus 2015-01-26 16:23:06 +01:00 committed by Saúl Ibarra Corretgé
parent ba09b39b1c
commit 39a0936fec
5 changed files with 174 additions and 35 deletions

View File

@ -68,6 +68,18 @@ API
.. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
and the buffer is not null terminated.
.. c:function:: int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size)
Get the name of the Unix domain socket or the named pipe to which the handle
is connected.
A preallocated buffer must be provided. The size parameter holds the length
of the buffer and it's set to the number of bytes written to the buffer on
output. If the buffer is not big enough ``UV_ENOBUFS`` will be returned and
len will contain the required size.
.. versionadded:: 1.3.0
.. c:function:: void uv_pipe_pending_instances(uv_pipe_t* handle, int count)
Set the number of pending pipe instance handles when the pipe server is

View File

@ -677,6 +677,9 @@ UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
char* buffer,
size_t* size);
UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
char* buffer,
size_t* size);
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);

View File

@ -206,23 +206,31 @@ out:
}
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
uv__peersockfunc func,
char* buffer,
size_t* size) {
struct sockaddr_un sa;
socklen_t addrlen;
int err;
addrlen = sizeof(sa);
memset(&sa, 0, addrlen);
err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
if (err < 0) {
*size = 0;
return -errno;
}
#if defined(__linux__)
if (sa.sun_path[0] == 0)
/* Linux abstract namespace */
addrlen -= offsetof(struct sockaddr_un, sun_path);
else
#endif
addrlen = strlen(sa.sun_path);
@ -238,6 +246,16 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
}
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
}
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
}
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
}

View File

@ -1910,7 +1910,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
}
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_NAME_INFORMATION tmp_name_info;
@ -2031,6 +2031,32 @@ int uv_pipe_pending_count(uv_pipe_t* handle) {
}
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
if (handle->flags & UV_HANDLE_BOUND)
return uv__pipe_getname(handle, buffer, size);
if (handle->flags & UV_HANDLE_CONNECTION ||
handle->handle != INVALID_HANDLE_VALUE) {
*size = 0;
return 0;
}
return UV_EBADF;
}
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
/* emulate unix behaviour */
if (handle->flags & UV_HANDLE_BOUND)
return UV_ENOTCONN;
if (handle->handle != INVALID_HANDLE_VALUE)
return uv__pipe_getname(handle, buffer, size);
return UV_EBADF;
}
uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (!handle->ipc)
return UV_UNKNOWN_HANDLE;

View File

@ -36,39 +36,121 @@
# include <fcntl.h>
#endif
static uv_pipe_t pipe_client;
static uv_pipe_t pipe_server;
static uv_connect_t connect_req;
static int close_cb_called = 0;
static int pipe_close_cb_called = 0;
static int pipe_client_connect_cb_called = 0;
static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
static void pipe_close_cb(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &pipe_client ||
handle == (uv_handle_t*) &pipe_server);
pipe_close_cb_called++;
}
TEST_IMPL(pipe_getsockname) {
uv_pipe_t server;
static void pipe_client_connect_cb(uv_connect_t* req, int status) {
char buf[1024];
size_t len;
int r;
r = uv_pipe_init(uv_default_loop(), &server, 0);
ASSERT(req == &connect_req);
ASSERT(status == 0);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);
r = uv_pipe_bind(&server, TEST_PIPENAME);
ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == 0 && len == 0);
pipe_client_connect_cb_called++;
uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
}
static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
/* This function *may* be called, depending on whether accept or the
* connection callback is called first.
*/
ASSERT(status == 0);
}
TEST_IMPL(pipe_getsockname) {
uv_loop_t* loop;
char buf[1024];
size_t len;
int r;
loop = uv_default_loop();
ASSERT(loop != NULL);
r = uv_pipe_init(loop, &pipe_server, 0);
ASSERT(r == 0);
len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == UV_EBADF);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_server, buf, &len);
ASSERT(r == UV_EBADF);
r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
ASSERT(r == 0);
len = sizeof buf;
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
uv_close((uv_handle_t*)&server, close_cb);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_server, buf, &len);
ASSERT(r == UV_ENOTCONN);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
ASSERT(r == 0);
ASSERT(close_cb_called == 1);
r = uv_pipe_init(loop, &pipe_client, 0);
ASSERT(r == 0);
len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == UV_EBADF);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == UV_EBADF);
uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
ASSERT(r == 0 && len == 0);
len = sizeof buf;
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(pipe_client_connect_cb_called == 1);
ASSERT(pipe_close_cb_called == 2);
MAKE_VALGRIND_HAPPY();
return 0;
@ -77,7 +159,6 @@ TEST_IMPL(pipe_getsockname) {
TEST_IMPL(pipe_getsockname_abstract) {
#if defined(__linux__)
uv_pipe_t server;
char buf[1024];
size_t len;
int r;
@ -97,24 +178,24 @@ TEST_IMPL(pipe_getsockname_abstract) {
r = bind(sock, (struct sockaddr*)&sun, sun_len);
ASSERT(r == 0);
r = uv_pipe_init(uv_default_loop(), &server, 0);
r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
ASSERT(r == 0);
r = uv_pipe_open(&server, sock);
r = uv_pipe_open(&pipe_server, sock);
ASSERT(r == 0);
len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);
ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
uv_close((uv_handle_t*)&server, close_cb);
uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
close(sock);
ASSERT(close_cb_called == 1);
ASSERT(pipe_close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
#else
@ -125,7 +206,6 @@ TEST_IMPL(pipe_getsockname_abstract) {
TEST_IMPL(pipe_getsockname_blocking) {
#ifdef _WIN32
uv_pipe_t reader;
HANDLE readh, writeh;
int readfd;
char buf1[1024], buf2[1024];
@ -135,44 +215,44 @@ TEST_IMPL(pipe_getsockname_blocking) {
r = CreatePipe(&readh, &writeh, NULL, 65536);
ASSERT(r != 0);
r = uv_pipe_init(uv_default_loop(), &reader, 0);
r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
ASSERT(r == 0);
readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
ASSERT(r != -1);
r = uv_pipe_open(&reader, readfd);
r = uv_pipe_open(&pipe_client, readfd);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*)&reader, NULL, NULL);
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
ASSERT(r == 0);
Sleep(100);
r = uv_read_stop((uv_stream_t*)&reader);
r = uv_read_stop((uv_stream_t*)&pipe_client);
ASSERT(r == 0);
len1 = sizeof buf1;
r = uv_pipe_getsockname(&reader, buf1, &len1);
r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
ASSERT(r == 0);
ASSERT(buf1[len1 - 1] != 0);
r = uv_read_start((uv_stream_t*)&reader, NULL, NULL);
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
ASSERT(r == 0);
Sleep(100);
len2 = sizeof buf2;
r = uv_pipe_getsockname(&reader, buf2, &len2);
r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
ASSERT(r == 0);
ASSERT(buf2[len2 - 1] != 0);
r = uv_read_stop((uv_stream_t*)&reader);
r = uv_read_stop((uv_stream_t*)&pipe_client);
ASSERT(r == 0);
ASSERT(len1 == len2);
ASSERT(memcmp(buf1, buf2, len1) == 0);
close_cb_called = 0;
uv_close((uv_handle_t*)&reader, close_cb);
pipe_close_cb_called = 0;
uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(close_cb_called == 1);
ASSERT(pipe_close_cb_called == 1);
_close(readfd);
CloseHandle(writeh);