mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 11:53:24 +00:00
Add regression test for UNIX stream socket options
This commit is contained in:
231
test/apps/network/sockoption_unix.c
Normal file
231
test/apps/network/sockoption_unix.c
Normal file
@ -0,0 +1,231 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/*
|
||||
* UNIX stream socket-related socket options.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/wait.h>
|
||||
#include "../test.h"
|
||||
|
||||
static int sk_unbound;
|
||||
static int sk_listen;
|
||||
static int sk_connected;
|
||||
static int sk_accepted;
|
||||
static int sk_tcp;
|
||||
static struct sockaddr_un addr = { .sun_family = AF_UNIX,
|
||||
.sun_path = "/tmp/sock_option_test" };
|
||||
|
||||
FN_SETUP(create_sockets)
|
||||
{
|
||||
sk_unbound = CHECK(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||
|
||||
sk_listen = CHECK(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||
CHECK(bind(sk_listen, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
CHECK(listen(sk_listen, 3));
|
||||
|
||||
sk_connected = CHECK(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||
CHECK(connect(sk_connected, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
|
||||
sk_accepted = CHECK(accept(sk_listen, NULL, NULL));
|
||||
|
||||
sk_tcp = CHECK(socket(AF_INET, SOCK_STREAM, 0));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_TEST(priority)
|
||||
{
|
||||
int val = 0;
|
||||
socklen_t len = sizeof(val);
|
||||
|
||||
TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_PRIORITY, &val, &len),
|
||||
val == 0);
|
||||
|
||||
val = -1;
|
||||
TEST_SUCC(setsockopt(sk_listen, SOL_SOCKET, SO_PRIORITY, &val, len));
|
||||
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PRIORITY, &val, &len),
|
||||
val == -1);
|
||||
|
||||
val = 100;
|
||||
TEST_SUCC(setsockopt(sk_connected, SOL_SOCKET, SO_PRIORITY, &val, len));
|
||||
TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PRIORITY, &val, &len),
|
||||
val == 100);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_TEST(acceptconn)
|
||||
{
|
||||
int val = 0;
|
||||
socklen_t len = sizeof(val);
|
||||
|
||||
TEST_ERRNO(setsockopt(sk_unbound, SOL_SOCKET, SO_ACCEPTCONN, &val, len),
|
||||
ENOPROTOOPT);
|
||||
|
||||
TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_ACCEPTCONN, &val, &len),
|
||||
val == 0 && len == 4);
|
||||
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_ACCEPTCONN, &val, &len),
|
||||
val == 1 && len == 4);
|
||||
TEST_RES(getsockopt(sk_accepted, SOL_SOCKET, SO_ACCEPTCONN, &val, &len),
|
||||
val == 0 && len == 4);
|
||||
TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_ACCEPTCONN, &val,
|
||||
&len),
|
||||
val == 0 && len == 4);
|
||||
TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_ACCEPTCONN, &val, &len),
|
||||
val == 0 && len == 4);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_TEST(peer_cred)
|
||||
{
|
||||
struct cred {
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
struct cred ucred = {};
|
||||
socklen_t len = sizeof(ucred);
|
||||
|
||||
TEST_ERRNO(setsockopt(sk_unbound, SOL_SOCKET, SO_PEERCRED, &ucred, len),
|
||||
ENOPROTOOPT);
|
||||
TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
|
||||
ucred.pid == 0 && ucred.uid == -1 && ucred.gid == -1);
|
||||
|
||||
TEST_ERRNO(setsockopt(sk_unbound, SOL_SOCKET, SO_PEERCRED, &ucred, len),
|
||||
ENOPROTOOPT);
|
||||
TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
|
||||
ucred.pid == 0 && ucred.uid == -1 && ucred.gid == -1);
|
||||
|
||||
pid_t pid = getpid();
|
||||
uid_t uid = geteuid();
|
||||
gid_t gid = getegid();
|
||||
|
||||
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
|
||||
ucred.pid == pid && ucred.uid == uid && ucred.gid == gid);
|
||||
TEST_RES(getsockopt(sk_accepted, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
|
||||
ucred.pid == pid && ucred.uid == uid && ucred.gid == gid);
|
||||
TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PEERCRED, &ucred,
|
||||
&len),
|
||||
ucred.pid == pid && ucred.uid == uid && ucred.gid == gid);
|
||||
|
||||
// Test listen socket
|
||||
int child_pid = TEST_SUCC(fork());
|
||||
if (child_pid == 0) {
|
||||
// Child process
|
||||
int sk_connect_new = CHECK(socket(AF_UNIX, SOCK_STREAM, 0));
|
||||
CHECK(connect(sk_connect_new, (struct sockaddr *)&addr,
|
||||
sizeof(addr)));
|
||||
CHECK_WITH(getsockopt(sk_connect_new, SOL_SOCKET, SO_PEERCRED,
|
||||
&ucred, &len),
|
||||
ucred.pid == pid && ucred.uid == uid &&
|
||||
ucred.gid == gid);
|
||||
CHECK(close(sk_connect_new));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int sk_accepted_new = TEST_SUCC(accept(sk_listen, NULL, NULL));
|
||||
TEST_RES(getsockopt(sk_accepted_new, SOL_SOCKET, SO_PEERCRED, &ucred,
|
||||
&len),
|
||||
ucred.pid == child_pid && ucred.uid == uid &&
|
||||
ucred.gid == gid);
|
||||
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
|
||||
ucred.pid == pid && ucred.uid == uid && ucred.gid == gid);
|
||||
|
||||
int status = 0;
|
||||
TEST_RES(wait4(child_pid, &status, 0, NULL),
|
||||
_ret == child_pid && WIFEXITED(status) &&
|
||||
WEXITSTATUS(status) == 0);
|
||||
TEST_SUCC(close(sk_accepted_new));
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
bool is_groups_equal(gid_t *g1, gid_t *g2, int groups)
|
||||
{
|
||||
for (int i = 0; i < groups; i++) {
|
||||
if (g1[i] != g2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FN_TEST(peer_groups)
|
||||
{
|
||||
int groups = TEST_SUCC(getgroups(0, NULL));
|
||||
gid_t *buffer = (gid_t *)malloc(groups * sizeof(gid_t));
|
||||
TEST_SUCC(getgroups(groups, buffer));
|
||||
|
||||
TEST_ERRNO(setsockopt(sk_unbound, SOL_SOCKET, SO_PEERGROUPS, buffer,
|
||||
groups),
|
||||
EINVAL);
|
||||
|
||||
gid_t small_buffer[1];
|
||||
socklen_t buffer_len = 1;
|
||||
|
||||
TEST_ERRNO(getsockopt(sk_tcp, SOL_SOCKET, SO_PEERGROUPS, small_buffer,
|
||||
&buffer_len),
|
||||
ENODATA);
|
||||
TEST_ERRNO(getsockopt(sk_unbound, SOL_SOCKET, SO_PEERGROUPS,
|
||||
small_buffer, &buffer_len),
|
||||
ENODATA);
|
||||
buffer_len = 1;
|
||||
TEST_ERRNO(getsockopt(sk_listen, SOL_SOCKET, SO_PEERGROUPS,
|
||||
small_buffer, &buffer_len),
|
||||
ERANGE);
|
||||
buffer_len = 1;
|
||||
TEST_ERRNO(getsockopt(sk_accepted, SOL_SOCKET, SO_PEERGROUPS,
|
||||
small_buffer, &buffer_len),
|
||||
ERANGE);
|
||||
|
||||
gid_t big_buffer[100];
|
||||
|
||||
buffer_len = sizeof(big_buffer);
|
||||
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PEERGROUPS, big_buffer,
|
||||
&buffer_len),
|
||||
buffer_len == groups * sizeof(gid_t) &&
|
||||
is_groups_equal(big_buffer, buffer, groups));
|
||||
|
||||
buffer_len = sizeof(big_buffer);
|
||||
TEST_ERRNO(getsockopt(sk_connected, SOL_SOCKET, SO_PEERGROUPS, NULL,
|
||||
&buffer_len),
|
||||
EFAULT);
|
||||
|
||||
buffer_len = sizeof(big_buffer);
|
||||
TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PEERGROUPS, big_buffer,
|
||||
&buffer_len),
|
||||
buffer_len == groups * sizeof(gid_t) &&
|
||||
is_groups_equal(big_buffer, buffer, groups));
|
||||
|
||||
int fildes[2];
|
||||
|
||||
buffer_len = sizeof(big_buffer);
|
||||
TEST_SUCC(socketpair(PF_UNIX, SOCK_STREAM, 0, fildes));
|
||||
TEST_RES(getsockopt(fildes[0], SOL_SOCKET, SO_PEERGROUPS, big_buffer,
|
||||
&buffer_len),
|
||||
buffer_len == groups * sizeof(gid_t) &&
|
||||
is_groups_equal(big_buffer, buffer, groups));
|
||||
|
||||
TEST_SUCC(close(fildes[0]));
|
||||
TEST_SUCC(close(fildes[1]));
|
||||
free(buffer);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_SETUP(cleanup)
|
||||
{
|
||||
CHECK(close(sk_unbound));
|
||||
CHECK(close(sk_listen));
|
||||
CHECK(close(sk_accepted));
|
||||
CHECK(close(sk_connected));
|
||||
CHECK(close(sk_tcp));
|
||||
CHECK(unlink(addr.sun_path));
|
||||
}
|
||||
END_SETUP()
|
@ -27,6 +27,7 @@ sleep 0.2
|
||||
|
||||
./socketpair
|
||||
./sockoption
|
||||
./sockoption_unix
|
||||
./listen_backlog
|
||||
./send_buf_full
|
||||
./tcp_err
|
||||
|
Reference in New Issue
Block a user