tests: add test_echo_tcp_sendmmsg_recvmmsg
[socket_wrapper.git] / tests / test_echo_tcp_sendmmsg_recvmmsg.c
1 #include <stdarg.h>
2 #include <stddef.h>
3 #include <setjmp.h>
4 #include <cmocka.h>
5
6 #include "config.h"
7 #include "torture.h"
8
9 #include <errno.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <unistd.h>
17
18 static int setup_echo_srv_tcp_ipv4(void **state)
19 {
20         torture_setup_echo_srv_tcp_ipv4(state);
21
22         return 0;
23 }
24
25 #ifdef HAVE_IPV6
26 static int setup_echo_srv_tcp_ipv6(void **state)
27 {
28         torture_setup_echo_srv_tcp_ipv6(state);
29
30         return 0;
31 }
32 #endif
33
34 static int teardown(void **state)
35 {
36         torture_teardown_echo_srv(state);
37
38         return 0;
39 }
40
41 static void test_sendmmsg_recvmmsg_ipv4_ignore(void **state)
42 {
43         struct torture_address addr = {
44                 .sa_socklen = sizeof(struct sockaddr_storage),
45         };
46         struct {
47                 struct torture_address reply_addr;
48                 struct iovec s_iov;
49                 struct iovec r_iov;
50                 char send_buf[64];
51                 char recv_buf[64];
52         } tmsgs[10] = {};
53         struct mmsghdr s_msgs[10] = {};
54         struct mmsghdr r_msgs[10] = {};
55         ssize_t ret;
56         int rc;
57         int i;
58         int s;
59
60         (void) state; /* unused */
61
62         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
63         assert_int_not_equal(s, -1);
64
65         addr.sa.in.sin_family = AF_INET;
66         addr.sa.in.sin_port = htons(torture_server_port());
67
68         rc = inet_pton(AF_INET,
69                        torture_server_address(AF_INET),
70                        &addr.sa.in.sin_addr);
71         assert_int_equal(rc, 1);
72
73         rc = connect(s, &addr.sa.s, addr.sa_socklen);
74         assert_return_code(rc, errno);
75
76         /* This should be ignored */
77         rc = inet_pton(AF_INET,
78                        "127.0.0.1",
79                        &addr.sa.in.sin_addr);
80         assert_int_equal(rc, 1);
81
82         for (i = 0; i < 10; i++) {
83                 tmsgs[i].reply_addr = (struct torture_address){
84                         .sa_socklen = sizeof(struct sockaddr_storage),
85                 };
86
87                 snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i);
88
89                 tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf;
90                 tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf);
91
92                 s_msgs[i].msg_hdr.msg_name = &addr.sa.s;
93                 s_msgs[i].msg_hdr.msg_namelen = addr.sa_socklen;
94                 s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov;
95                 s_msgs[i].msg_hdr.msg_iovlen = 1;
96
97                 tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf;
98                 tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf);
99
100                 r_msgs[i].msg_hdr.msg_name = &tmsgs[i].reply_addr.sa.s;
101                 r_msgs[i].msg_hdr.msg_namelen = tmsgs[i].reply_addr.sa_socklen;
102                 r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov;
103                 r_msgs[i].msg_hdr.msg_iovlen = 1;
104         }
105
106         ret = sendmmsg(s, s_msgs, 10, 0);
107         assert_int_equal(ret, 10);
108
109         ret = recvmmsg(s, r_msgs, 10, 0, NULL);
110         assert_int_equal(ret, 10);
111
112         for (i = 0; i < 10; i++) {
113                 assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0);
114                 assert_ptr_equal(r_msgs[i].msg_hdr.msg_name, &tmsgs[i].reply_addr.sa.s);
115
116                 assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len);
117                 assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf));
118         }
119
120         rc = close(s);
121         assert_int_equal(rc, 0);
122 }
123
124 #ifdef HAVE_IPV6
125 static void test_sendmmsg_recvmmsg_ipv6(void **state)
126 {
127         struct torture_address addr = {
128                 .sa_socklen = sizeof(struct sockaddr_storage),
129         };
130         struct {
131                 struct torture_address reply_addr;
132                 struct iovec s_iov;
133                 struct iovec r_iov;
134                 char send_buf[64];
135                 char recv_buf[64];
136         } tmsgs[10] = {};
137         struct mmsghdr s_msgs[10] = {};
138         struct mmsghdr r_msgs[10] = {};
139         ssize_t ret;
140         int rc;
141         int i;
142         int s;
143
144         (void) state; /* unused */
145
146         s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
147         assert_int_not_equal(s, -1);
148
149         addr.sa.in.sin_family = AF_INET6;
150         addr.sa.in.sin_port = htons(torture_server_port());
151
152         rc = inet_pton(AF_INET6,
153                        torture_server_address(AF_INET6),
154                        &addr.sa.in6.sin6_addr);
155         assert_int_equal(rc, 1);
156
157         rc = connect(s, &addr.sa.s, addr.sa_socklen);
158         assert_return_code(rc, errno);
159
160         for (i = 0; i < 10; i++) {
161                 tmsgs[i].reply_addr = (struct torture_address){
162                         .sa_socklen = sizeof(struct sockaddr_storage),
163                 };
164
165                 snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i);
166
167                 tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf;
168                 tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf);
169
170                 s_msgs[i].msg_hdr.msg_name = &addr.sa.s;
171                 s_msgs[i].msg_hdr.msg_namelen = addr.sa_socklen;
172                 s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov;
173                 s_msgs[i].msg_hdr.msg_iovlen = 1;
174
175                 tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf;
176                 tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf);
177
178                 r_msgs[i].msg_hdr.msg_name = &tmsgs[i].reply_addr.sa.s;
179                 r_msgs[i].msg_hdr.msg_namelen = tmsgs[i].reply_addr.sa_socklen;
180                 r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov;
181                 r_msgs[i].msg_hdr.msg_iovlen = 1;
182         }
183
184         ret = sendmmsg(s, s_msgs, 10, 0);
185         assert_int_equal(ret, 10);
186
187         ret = recvmmsg(s, r_msgs, 10, 0, NULL);
188         assert_int_equal(ret, 10);
189
190         for (i = 0; i < 10; i++) {
191                 assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0);
192                 assert_ptr_equal(r_msgs[i].msg_hdr.msg_name, &tmsgs[i].reply_addr.sa.s);
193
194                 assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len);
195                 assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf));
196         }
197
198         rc = close(s);
199         assert_int_equal(rc, 0);
200 }
201 #endif
202
203 static void test_sendmmsg_recvmmsg_ipv4_null(void **state)
204 {
205         struct torture_address addr = {
206                 .sa_socklen = sizeof(struct sockaddr_storage),
207         };
208         struct {
209                 struct torture_address reply_addr;
210                 struct iovec s_iov;
211                 struct iovec r_iov;
212                 char send_buf[64];
213                 char recv_buf[64];
214         } tmsgs[10] = {};
215         struct mmsghdr s_msgs[10] = {};
216         struct mmsghdr r_msgs[10] = {};
217         ssize_t ret;
218         int rc;
219         int i;
220         int s;
221
222         (void) state; /* unused */
223
224         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
225         assert_int_not_equal(s, -1);
226
227         addr.sa.in.sin_family = AF_INET;
228         addr.sa.in.sin_port = htons(torture_server_port());
229
230         rc = inet_pton(AF_INET,
231                        torture_server_address(AF_INET),
232                        &addr.sa.in.sin_addr);
233         assert_int_equal(rc, 1);
234
235         rc = connect(s, &addr.sa.s, addr.sa_socklen);
236         assert_return_code(rc, errno);
237
238         for (i = 0; i < 10; i++) {
239                 tmsgs[i].reply_addr = (struct torture_address){
240                         .sa_socklen = sizeof(struct sockaddr_storage),
241                 };
242
243                 snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i);
244
245                 tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf;
246                 tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf);
247
248                 s_msgs[i].msg_hdr.msg_name = NULL;
249                 s_msgs[i].msg_hdr.msg_namelen = 0;
250                 s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov;
251                 s_msgs[i].msg_hdr.msg_iovlen = 1;
252
253                 tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf;
254                 tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf);
255
256                 r_msgs[i].msg_hdr.msg_name = NULL;
257                 r_msgs[i].msg_hdr.msg_namelen = 0;
258                 r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov;
259                 r_msgs[i].msg_hdr.msg_iovlen = 1;
260         }
261
262         ret = sendmmsg(s, s_msgs, 10, 0);
263         assert_int_equal(ret, 10);
264
265         ret = recvmmsg(s, r_msgs, 10, 0, NULL);
266         assert_int_equal(ret, 10);
267
268         for (i = 0; i < 10; i++) {
269                 assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0);
270                 assert_null(r_msgs[i].msg_hdr.msg_name);
271
272                 assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len);
273                 assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf));
274         }
275
276         rc = close(s);
277         assert_int_equal(rc, 0);
278 }
279
280 int main(void) {
281         int rc;
282
283         const struct CMUnitTest sendmsg_tests[] = {
284                 cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv4_ignore,
285                                                 setup_echo_srv_tcp_ipv4,
286                                                 teardown),
287                 cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv4_null,
288                                                 setup_echo_srv_tcp_ipv4,
289                                                 teardown),
290 #ifdef HAVE_IPV6
291                 cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv6,
292                                                 setup_echo_srv_tcp_ipv6,
293                                                 teardown),
294 #endif
295         };
296
297         rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL);
298
299         return rc;
300 }