xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/accept4/accept4_01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (C) 2008, Linux Foundation,
5  * Copyright (c) 2020 Petr Vorel <[email protected]>
6  * written by Michael Kerrisk <[email protected]>
7  * Initial Porting to LTP by Subrata <[email protected]>
8  */
9 
10 #define _GNU_SOURCE
11 #include <unistd.h>
12 #include <sys/syscall.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <linux/net.h>
20 
21 #include "tst_test.h"
22 #include "lapi/fcntl.h"
23 #include "lapi/syscalls.h"
24 
25 static const char *variant_desc[] = {
26 	"libc accept4()",
27 	"__NR_accept4 syscall",
28 	"__NR_socketcall SYS_ACCEPT4 syscall"};
29 
30 static struct sockaddr_in *conn_addr, *accept_addr;
31 static int listening_fd;
32 
socketcall_accept4(int fd,struct sockaddr * sockaddr,socklen_t * addrlen,int flags)33 static int socketcall_accept4(int fd, struct sockaddr *sockaddr, socklen_t
34 			      *addrlen, int flags)
35 {
36 	long args[6];
37 
38 	args[0] = fd;
39 	args[1] = (long)sockaddr;
40 	args[2] = (long)addrlen;
41 	args[3] = flags;
42 
43 	return tst_syscall(__NR_socketcall, SYS_ACCEPT4, args);
44 }
45 
create_listening_socket(void)46 static int create_listening_socket(void)
47 {
48 	struct sockaddr_in svaddr;
49 	int lfd;
50 	int optval;
51 
52 	memset(&svaddr, 0, sizeof(struct sockaddr_in));
53 	svaddr.sin_family = AF_INET;
54 	svaddr.sin_addr.s_addr = htonl(INADDR_ANY);
55 	svaddr.sin_port = 0;
56 
57 	lfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
58 
59 	optval = 1;
60 	SAFE_SETSOCKOPT(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
61 	SAFE_BIND(lfd, (struct sockaddr *)&svaddr, sizeof(struct sockaddr_in));
62 	SAFE_LISTEN(lfd, 5);
63 
64 	return lfd;
65 }
66 
setup(void)67 static void setup(void)
68 {
69 	socklen_t slen = sizeof(*conn_addr);
70 
71 	tst_res(TINFO, "Testing variant: %s", variant_desc[tst_variant]);
72 
73 	listening_fd = create_listening_socket();
74 
75 	memset(conn_addr, 0, sizeof(*conn_addr));
76 	SAFE_GETSOCKNAME(listening_fd, (struct sockaddr *)conn_addr, &slen);
77 	conn_addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
78 	tst_res(TINFO, "server listening on: %d", ntohs(conn_addr->sin_port));
79 }
80 
cleanup(void)81 static void cleanup(void)
82 {
83 	SAFE_CLOSE(listening_fd);
84 }
85 
86 static struct test_case {
87 	int cloexec;
88 	int nonblock;
89 } tcases[] = {
90 	{ 0, 0 },
91 	{ SOCK_CLOEXEC, 0 },
92 	{ 0, SOCK_NONBLOCK },
93 	{ SOCK_CLOEXEC, SOCK_NONBLOCK },
94 };
95 
verify_accept4(unsigned int nr)96 static void verify_accept4(unsigned int nr)
97 {
98 	struct test_case *tcase = &tcases[nr];
99 	int flags = tcase->cloexec | tcase->nonblock;
100 	int connfd, acceptfd;
101 	int fdf, flf, fdf_pass, flf_pass, fd_cloexec, fd_nonblock;
102 	socklen_t addrlen;
103 
104 	connfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
105 	SAFE_CONNECT(connfd, (struct sockaddr *)conn_addr, sizeof(*conn_addr));
106 	addrlen = sizeof(*accept_addr);
107 
108 	switch (tst_variant) {
109 	case 0:
110 		TEST(accept4(listening_fd, (struct sockaddr *)accept_addr,
111 			     &addrlen, flags));
112 	break;
113 	case 1:
114 		TEST(tst_syscall(__NR_accept4, listening_fd,
115 				 (struct sockaddr *)accept_addr,
116 				 &addrlen, flags));
117 	break;
118 	case 2:
119 		TEST(socketcall_accept4(listening_fd, (struct sockaddr *)accept_addr,
120 				&addrlen, flags));
121 	break;
122 	}
123 
124 	if (TST_RET == -1)
125 		tst_brk(TBROK | TTERRNO, "accept4 failed");
126 
127 	acceptfd = TST_RET;
128 
129 	/* Test to see if O_CLOEXEC is as expected */
130 	fdf = SAFE_FCNTL(acceptfd, F_GETFD);
131 	fd_cloexec = !!(fdf & FD_CLOEXEC);
132 	fdf_pass = fd_cloexec == !!tcase->cloexec;
133 	if (!fdf_pass) {
134 		tst_res(TFAIL, "Close-on-exec flag mismatch, %d vs %d",
135 			fd_cloexec, !!tcase->cloexec);
136 	}
137 
138 	/* Test to see if O_NONBLOCK is as expected */
139 	flf = SAFE_FCNTL(acceptfd, F_GETFL);
140 	fd_nonblock = !!(flf & O_NONBLOCK);
141 	flf_pass = fd_nonblock == !!tcase->nonblock;
142 	if (!flf_pass) {
143 		tst_res(TFAIL, "nonblock flag mismatch, %d vs %d",
144 		        fd_nonblock, !!tcase->nonblock);
145 	}
146 
147 	SAFE_CLOSE(acceptfd);
148 	SAFE_CLOSE(connfd);
149 
150 	if (fdf_pass && flf_pass) {
151 		tst_res(TPASS, "Close-on-exec %d, nonblock %d",
152 				fd_cloexec, fd_nonblock);
153 	}
154 }
155 
156 static struct tst_test test = {
157 	.tcnt = ARRAY_SIZE(tcases),
158 	.setup = setup,
159 	.cleanup = cleanup,
160 	.test_variants = ARRAY_SIZE(variant_desc),
161 	.test = verify_accept4,
162 	.bufs = (struct tst_buffers []) {
163 		{&conn_addr, .size = sizeof(*conn_addr)},
164 		{&accept_addr, .size = sizeof(*accept_addr)},
165 		{},
166 	}
167 };
168