Implement getpeername(2) and getsockname(2).

This commit is contained in:
Jonas 'Sortie' Termansen 2017-02-23 20:12:26 +01:00
parent 4eb9caaa39
commit ef2e478607
12 changed files with 273 additions and 12 deletions

View File

@ -1057,4 +1057,14 @@ int Descriptor::shutdown(ioctx_t* ctx, int how)
return vnode->shutdown(ctx, how);
}
int Descriptor::getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize)
{
return vnode->getpeername(ctx, addr, addrsize);
}
int Descriptor::getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize)
{
return vnode->getsockname(ctx, addr, addrsize);
}
} // namespace Sortix

View File

@ -267,6 +267,8 @@ public:
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
virtual int shutdown(ioctx_t* ctx, int how);
virtual int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
virtual int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
private:
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
@ -1748,6 +1750,18 @@ int Unode::shutdown(ioctx_t* ctx, int how)
return ret;
}
int Unode::getpeername(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrsize*/)
{
return errno = ENOTSOCK, -1;
}
int Unode::getsockname(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrsize*/)
{
return errno = ENOTSOCK, -1;
}
bool Bootstrap(Ref<Inode>* out_root,
Ref<Inode>* out_server,
const struct stat* rootst)

View File

@ -121,6 +121,8 @@ public:
int tcsendbreak(ioctx_t* ctx, int duration);
int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
int shutdown(ioctx_t* ctx, int how);
int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
private:
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags,

View File

@ -130,6 +130,8 @@ public:
virtual int tcsendbreak(ioctx_t* ctx, int duration) = 0;
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio) = 0;
virtual int shutdown(ioctx_t* ctx, int how) = 0;
virtual int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize) = 0;
virtual int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize) = 0;
};
@ -235,6 +237,8 @@ public:
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
virtual int shutdown(ioctx_t* ctx, int how);
virtual int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
virtual int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
};

View File

@ -95,13 +95,13 @@ uid_t sys_geteuid(void);
gid_t sys_getgid(void);
int sys_gethostname(char*, size_t);
size_t sys_getpagesize(void);
int sys_getpeername(int, struct sockaddr*, socklen_t*);
int sys_getpeername(int, void*, size_t*);
pid_t sys_getpgid(pid_t);
pid_t sys_getpid(void);
pid_t sys_getppid(void);
int sys_getpriority(int, id_t);
pid_t sys_getsid(pid_t);
int sys_getsockname(int, struct sockaddr*, socklen_t*);
int sys_getsockname(int, void*, size_t*);
int sys_getsockopt(int, int, int, void*, size_t*);
int sys_gettermmode(int, unsigned*);
uid_t sys_getuid(void);

View File

@ -118,6 +118,8 @@ public:
int tcsendbreak(ioctx_t* ctx, int duration);
int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
int shutdown(ioctx_t* ctx, int how);
int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
public /*TODO: private*/:
Ref<Inode> inode;

View File

@ -626,4 +626,16 @@ int AbstractInode::shutdown(ioctx_t* /*ctx*/, int /*how*/)
return errno = ENOTSOCK, -1;
}
int AbstractInode::getpeername(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrsize*/)
{
return errno = ENOTSOCK, -1;
}
int AbstractInode::getsockname(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrsize*/)
{
return errno = ENOTSOCK, -1;
}
} // namespace Sortix

View File

@ -928,20 +928,22 @@ ssize_t sys_tcsetblob(int fd, const char* name, const void* buffer, size_t count
return result;
}
int sys_getpeername(int fd, struct sockaddr* addr, socklen_t* addrsize)
int sys_getpeername(int fd, void* addr, size_t* addrsize)
{
(void) fd;
(void) addr;
(void) addrsize;
return errno = ENOSYS, -1;
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->getpeername(&ctx, (uint8_t*) addr, addrsize);
}
int sys_getsockname(int fd, struct sockaddr* addr, socklen_t* addrsize)
int sys_getsockname(int fd, void* addr, size_t* addrsize)
{
(void) fd;
(void) addr;
(void) addrsize;
return errno = ENOSYS, -1;
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->getsockname(&ctx, (uint8_t*) addr, addrsize);
}
int sys_shutdown(int fd, int how)

View File

@ -103,6 +103,8 @@ public:
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
const void* option_value, size_t option_size);
virtual int shutdown(ioctx_t* ctx, int how);
virtual int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
virtual int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
private:
int do_bind(ioctx_t* ctx, const uint8_t* addr, size_t addrsize);
@ -118,6 +120,7 @@ public: /* For use by Manager. */
StreamSocket* last_pending;
struct sockaddr_un* bound_address;
size_t bound_address_size;
int shutdown_flags;
bool is_listening;
bool is_connected;
bool is_refused;
@ -170,6 +173,7 @@ StreamSocket::StreamSocket(uid_t owner, gid_t group, mode_t mode,
this->last_pending = NULL;
this->bound_address = NULL;
this->bound_address_size = 0;
this->shutdown_flags = 0;
this->is_listening = false;
this->is_connected = false;
this->is_refused = false;
@ -386,6 +390,41 @@ int StreamSocket::shutdown(ioctx_t* /*ctx*/, int how)
incoming.Disconnect();
if ( how & SHUT_WR )
outgoing.Disconnect();
shutdown_flags |= how;
return 0;
}
int StreamSocket::getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize)
{
ScopedLock lock(&socket_lock);
if ( !is_connected )
return errno = ENOTCONN, -1;
if ( shutdown_flags & SHUT_WR )
return errno = EINVAL, -1;
size_t used_addrsize;
if ( !ctx->copy_from_src(&used_addrsize, addrsize, sizeof(used_addrsize)) )
return -1;
if ( bound_address_size < used_addrsize )
used_addrsize = bound_address_size;
if ( !ctx->copy_to_dest(addr, bound_address, bound_address_size) )
return -1;
if ( !ctx->copy_to_dest(addrsize, &used_addrsize, sizeof(used_addrsize)) )
return -1;
return 0;
}
int StreamSocket::getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize)
{
ScopedLock lock(&socket_lock);
size_t used_addrsize;
if ( !ctx->copy_from_src(&used_addrsize, addrsize, sizeof(used_addrsize)) )
return -1;
if ( bound_address_size < used_addrsize )
used_addrsize = bound_address_size;
if ( !ctx->copy_to_dest(addr, bound_address, bound_address_size) )
return -1;
if ( !ctx->copy_to_dest(addrsize, &used_addrsize, sizeof(used_addrsize)) )
return -1;
return 0;
}
@ -496,6 +535,13 @@ Ref<StreamSocket> Manager::Accept(StreamSocket* socket, ioctx_t* ctx,
if ( !server )
return Ref<StreamSocket>(NULL);
server->bound_address = (struct sockaddr_un*) malloc(bound_address_size);
if ( !server->bound_address )
return Ref<StreamSocket>(NULL);
server->bound_address_size = bound_address_size;
memcpy(server->bound_address, bound_address, bound_address_size);
StreamSocket* client = socket->first_pending;
QueuePop(&socket->first_pending, &socket->last_pending);

View File

@ -498,4 +498,14 @@ int Vnode::shutdown(ioctx_t* ctx, int how)
return inode->shutdown(ctx, how);
}
int Vnode::getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize)
{
return inode->getpeername(ctx, addr, addrsize);
}
int Vnode::getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize)
{
return inode->getsockname(ctx, addr, addrsize);
}
} // namespace Sortix

View File

@ -25,6 +25,7 @@ test-pthread-once \
test-pthread-self \
test-pthread-tls \
test-signal-raise \
test-unix-socket-name \
test-unix-socket-shutdown \
all: $(BINARIES) $(TESTS)

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* test-unix-socket-name.c
* Tests whether unix sockets return the right names.
*/
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <unistd.h>
#include "test.h"
static pid_t main_pid;
static char tmpdir[] = "/tmp/test-unix-socket-name.XXXXXX";
static char sockpath[(sizeof(tmpdir) - 1) + 1 + 6 + 1];
static bool made_tmpdir = false;
static bool made_socket = false;
void exit_handler(void)
{
if ( getpid() != main_pid )
return;
if ( made_socket )
unlink(sockpath);
if ( made_tmpdir )
rmdir(tmpdir);
}
int main(void)
{
main_pid = getpid();
test_assert(atexit(exit_handler) == 0);
test_assert(mkdtemp(tmpdir));
made_tmpdir = true;
int server;
test_assert(0 <= (server = socket(AF_UNIX, SOCK_STREAM, 0)));
test_assert(snprintf(sockpath, sizeof(sockpath), "%s/socket", tmpdir) <
(int) sizeof(sockpath));
socklen_t sockaddr_actual_len =
offsetof(struct sockaddr_un, sun_path) + strlen(sockpath) + 1;
struct sockaddr_un sockaddr;
test_assert(sockaddr_actual_len <= sizeof(sockaddr));
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sun_family = AF_UNIX;
strlcpy(sockaddr.sun_path, sockpath, sizeof(sockaddr.sun_path));
socklen_t sockaddr_len = sizeof(sockaddr);
test_assert(bind(server, (struct sockaddr*) &sockaddr, sockaddr_len) == 0);
test_assert(listen(server, 1) == 0 );
made_socket = true;
struct sockaddr_un addr;
socklen_t addr_len;
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
test_assert(getsockname(server, (struct sockaddr*) &addr,
&addr_len) == 0);
test_assert(sockaddr_actual_len <= addr_len);
test_assert(addr_len <= sizeof(addr));
test_assert(addr.sun_family == AF_UNIX);
test_assert(strcmp(sockpath, addr.sun_path) == 0);
test_assert(getpeername(server, (struct sockaddr*) &addr,
&addr_len) == -1);
test_assert(errno == ENOTCONN);
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
int client;
pid_t pid;
test_assert(0 <= (pid = fork()));
if ( pid == 0 )
{
test_assert(0 <= (client = socket(AF_UNIX, SOCK_STREAM, 0)));
test_assert(connect(client, (struct sockaddr*) &sockaddr,
sockaddr_len) == 0);
#if defined(__sortix__) // Linux returns an empty struct sockaddr_un.
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
test_assert(getsockname(client, (struct sockaddr*) &addr,
&addr_len) == 0);
test_assert(sockaddr_actual_len <= addr_len);
test_assert(addr_len <= sizeof(addr));
test_assert(addr.sun_family == AF_UNIX);
test_assert(strcmp(sockpath, addr.sun_path) == 0);
#endif
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
test_assert(getpeername(client, (struct sockaddr*) &addr,
&addr_len) == 0);
test_assert(sockaddr_actual_len <= addr_len);
test_assert(addr_len <= sizeof(addr));
test_assert(addr.sun_family == AF_UNIX);
test_assert(strcmp(sockpath, addr.sun_path) == 0);
_exit(0);
}
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
test_assert(0 <= (client = accept(server, (struct sockaddr*) &addr,
&addr_len)));
test_assert(sockaddr_actual_len <= addr_len);
test_assert(addr_len <= sizeof(addr));
test_assert(addr.sun_family == AF_UNIX);
test_assert(strcmp(sockpath, addr.sun_path) == 0);
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
test_assert(getsockname(client, (struct sockaddr*) &addr,
&addr_len) == 0);
test_assert(sockaddr_actual_len <= addr_len);
test_assert(addr_len <= sizeof(addr));
test_assert(addr.sun_family == AF_UNIX);
test_assert(strcmp(sockpath, addr.sun_path) == 0);
#if defined(__sortix__) // Linux returns an empty struct sockaddr_un.
memset(&addr, 0, sizeof(addr));
addr_len = sizeof(addr);
test_assert(getpeername(client, (struct sockaddr*) &addr,
&addr_len) == 0);
test_assert(sockaddr_actual_len <= addr_len);
test_assert(addr_len <= sizeof(addr));
test_assert(addr.sun_family == AF_UNIX);
test_assert(strcmp(sockpath, addr.sun_path) == 0);
#endif
int status = 0;
waitpid(pid, &status, 0);
if ( !WIFEXITED(status) || WEXITSTATUS(status) != 0 )
return 1;
return 0;
}