* Copyright (c) International Business Machines Corp., 2001
* 07/2001 Ported by Wayne Boyer
* Copyright (C) 2024 SUSE LLC Andrea Manzini <andrea.manzini@suse.com>
*/
* Verify that getpeername() returns the proper errno for various failure cases:
*
* - EBADF on invalid address.
* - ENOTSOCK on socket opened on /dev/null.
* - ENOTCONN on socket not connected.
* - EINVAL on negative addrlen.
* - EFAULT on invalid addr/addrlen pointers.
*/
#include "tst_test.h"
static struct sockaddr_in server_addr;
static struct sockaddr_in fsin1;
static socklen_t sinlen;
static socklen_t invalid_sinlen = -1;
static int sv[2];
static int sockfd = -1;
static void setup_fd_file(void)
{
sockfd = SAFE_OPEN("/dev/null", O_WRONLY, 0666);
}
static void setup_fd_stream(void)
{
sockfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
SAFE_BIND(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
}
static void cleanup_fd(void)
{
if (sockfd)
SAFE_CLOSE(sockfd);
}
static void setup_pair(void)
{
SAFE_SOCKETPAIR(PF_UNIX, SOCK_STREAM, 0, sv);
sockfd = sv[0];
}
static void cleanup_pair(void)
{
if (sv[0])
SAFE_CLOSE(sv[0]);
if (sv[1])
SAFE_CLOSE(sv[1]);
}
static struct test_case {
struct sockaddr *sockaddr;
socklen_t *addrlen;
int experrno;
void (*setup)(void);
void (*cleanup)(void);
} test_cases[] = {
{.addrlen = &sinlen, .experrno = EBADF},
{.addrlen = &sinlen, .experrno = ENOTSOCK, .setup = setup_fd_file,
.cleanup = cleanup_fd },
{.addrlen = &sinlen, .experrno = ENOTCONN, .setup = setup_fd_stream,
.cleanup = cleanup_fd },
{.addrlen = &invalid_sinlen, .experrno = EINVAL, .setup = setup_pair,
.cleanup = cleanup_pair},
{.sockaddr = (struct sockaddr *) -1, .addrlen = &sinlen, .experrno = EFAULT,
.setup = setup_pair, .cleanup = cleanup_pair},
{.experrno = EFAULT, .setup = setup_pair, .cleanup = cleanup_pair},
{.addrlen = (socklen_t *) 1, .experrno = EFAULT, .setup = setup_pair,
.cleanup = cleanup_pair },
};
static void verify_getpeername(unsigned int nr)
{
struct test_case *tc = &test_cases[nr];
if (tc->setup != NULL)
tc->setup();
if (!tc->sockaddr)
tc->sockaddr = (struct sockaddr *)&fsin1;
TST_EXP_FAIL(getpeername(sockfd, tc->sockaddr, tc->addrlen), tc->experrno);
if (tc->cleanup != NULL)
tc->cleanup();
}
static void setup(void)
{
server_addr.sin_family = AF_INET;
server_addr.sin_port = 0;
server_addr.sin_addr.s_addr = INADDR_ANY;
sinlen = sizeof(fsin1);
}
static struct tst_test test = {
.setup = setup,
.test = verify_getpeername,
.tcnt = ARRAY_SIZE(test_cases),
};