xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/send/send02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 SUSE LLC <[email protected]>
4  */
5 
6 /*\
7  * [Description]
8  *
9  * Check that the kernel correctly handles send()/sendto()/sendmsg() calls
10  * with MSG_MORE flag.
11  */
12 
13 #define _GNU_SOURCE
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <sys/ioctl.h>
18 #include <net/if.h>
19 #include <sched.h>
20 
21 #include "tst_test.h"
22 #include "tst_net.h"
23 
24 #define SENDSIZE 16
25 #define RECVSIZE 32
26 
27 static int sock = -1, dst_sock = -1, listen_sock = -1;
28 static struct sockaddr_in addr;
29 static char sendbuf[SENDSIZE];
30 
do_send(int sock,void * buf,size_t size,int flags)31 static void do_send(int sock, void *buf, size_t size, int flags)
32 {
33 	SAFE_SEND(1, sock, buf, size, flags);
34 }
35 
do_sendto(int sock,void * buf,size_t size,int flags)36 static void do_sendto(int sock, void *buf, size_t size, int flags)
37 {
38 	SAFE_SENDTO(1, sock, buf, size, flags, (struct sockaddr *)&addr,
39 		sizeof(addr));
40 }
41 
do_sendmsg(int sock,void * buf,size_t size,int flags)42 static void do_sendmsg(int sock, void *buf, size_t size, int flags)
43 {
44 	struct msghdr msg;
45 	struct iovec iov;
46 
47 	iov.iov_base = buf;
48 	iov.iov_len = size;
49 	msg.msg_name = &addr;
50 	msg.msg_namelen = sizeof(addr);
51 	msg.msg_iov = &iov;
52 	msg.msg_iovlen = 1;
53 	msg.msg_control = NULL;
54 	msg.msg_controllen = 0;
55 	msg.msg_flags = 0;
56 	SAFE_SENDMSG(size, sock, &msg, flags);
57 }
58 
59 static struct test_case {
60 	int domain, type, protocol;
61 	void (*send)(int sock, void *buf, size_t size, int flags);
62 	int needs_connect, needs_accept;
63 	const char *name;
64 } testcase_list[] = {
65 	{AF_INET, SOCK_STREAM, 0, do_send, 1, 1, "TCP send"},
66 	{AF_INET, SOCK_DGRAM, 0, do_send, 1, 0, "UDP send"},
67 	{AF_INET, SOCK_DGRAM, 0, do_sendto, 0, 0, "UDP sendto"},
68 	{AF_INET, SOCK_DGRAM, 0, do_sendmsg, 0, 0, "UDP sendmsg"}
69 };
70 
setup(void)71 static void setup(void)
72 {
73 	memset(sendbuf, 0x42, SENDSIZE);
74 }
75 
check_recv(int sock,long expsize,int loop)76 static int check_recv(int sock, long expsize, int loop)
77 {
78 	char recvbuf[RECVSIZE] = {0};
79 
80 	while (1) {
81 		TEST(recv(sock, recvbuf, RECVSIZE, MSG_DONTWAIT));
82 
83 		if (TST_RET == -1) {
84 			/* expected error immediately after send(MSG_MORE) */
85 			if (TST_ERR == EAGAIN || TST_ERR == EWOULDBLOCK) {
86 				if (expsize)
87 					continue;
88 				else
89 					break;
90 			}
91 
92 			/* unexpected error */
93 			tst_res(TFAIL | TTERRNO, "recv() error at step %d, expsize %ld",
94 				loop, expsize);
95 			return 0;
96 		}
97 
98 		if (TST_RET < 0) {
99 			tst_res(TFAIL | TTERRNO, "recv() returns %ld at step %d, expsize %ld",
100 				TST_RET, loop, expsize);
101 			return 0;
102 		}
103 
104 		if (TST_RET != expsize) {
105 			tst_res(TFAIL, "recv() read %ld bytes, expected %ld, step %d",
106 				TST_RET, expsize, loop);
107 			return 0;
108 		}
109 		return 1;
110 	}
111 
112 	return 1;
113 }
114 
cleanup(void)115 static void cleanup(void)
116 {
117 	if (sock >= 0)
118 		SAFE_CLOSE(sock);
119 
120 	if (dst_sock >= 0 && dst_sock != listen_sock)
121 		SAFE_CLOSE(dst_sock);
122 
123 	if (listen_sock >= 0)
124 		SAFE_CLOSE(listen_sock);
125 }
126 
run(unsigned int n)127 static void run(unsigned int n)
128 {
129 	int i, ret;
130 	struct test_case *tc = testcase_list + n;
131 	socklen_t len = sizeof(addr);
132 
133 	tst_res(TINFO, "Testing %s", tc->name);
134 
135 	tst_init_sockaddr_inet_bin(&addr, INADDR_LOOPBACK, 0);
136 	listen_sock = SAFE_SOCKET(tc->domain, tc->type, tc->protocol);
137 	dst_sock = listen_sock;
138 	SAFE_BIND(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
139 	SAFE_GETSOCKNAME(listen_sock, (struct sockaddr *)&addr, &len);
140 
141 	if (tc->needs_accept)
142 		SAFE_LISTEN(listen_sock, 1);
143 
144 	for (i = 0; i < 1000; i++) {
145 		sock = SAFE_SOCKET(tc->domain, tc->type, tc->protocol);
146 
147 		if (tc->needs_connect)
148 			SAFE_CONNECT(sock, (struct sockaddr *)&addr, len);
149 
150 		if (tc->needs_accept)
151 			dst_sock = SAFE_ACCEPT(listen_sock, NULL, NULL);
152 
153 		tc->send(sock, sendbuf, SENDSIZE, 0);
154 		ret = check_recv(dst_sock, SENDSIZE, i + 1);
155 
156 		if (!ret)
157 			break;
158 
159 		tc->send(sock, sendbuf, SENDSIZE, MSG_MORE);
160 		ret = check_recv(dst_sock, 0, i + 1);
161 
162 		if (!ret)
163 			break;
164 
165 		tc->send(sock, sendbuf, 1, 0);
166 		ret = check_recv(dst_sock, SENDSIZE + 1, i + 1);
167 
168 		if (!ret)
169 			break;
170 
171 		SAFE_CLOSE(sock);
172 
173 		if (dst_sock != listen_sock)
174 			SAFE_CLOSE(dst_sock);
175 	}
176 
177 	if (ret)
178 		tst_res(TPASS, "MSG_MORE works correctly");
179 
180 	cleanup();
181 	dst_sock = -1;
182 }
183 
184 static struct tst_test test = {
185 	.test = run,
186 	.tcnt = ARRAY_SIZE(testcase_list),
187 	.setup = setup,
188 	.cleanup = cleanup
189 };
190