riscv: Fix alignment-ignorant memcpy implementation
[glibc.git] / sysdeps / unix / sysv / linux / tst-socket-timestamp-compat.c
blobe0fb28d0b9b0edfa5fe05ce553dab1bd844a724a
1 /* Check recvmsg/recvmmsg 64-bit timestamp support.
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <arpa/inet.h>
20 #include <string.h>
21 #include <support/check.h>
22 #include <support/xsocket.h>
23 #include <support/xunistd.h>
24 #include <stdbool.h>
25 #include <socket-constants-time64.h>
27 /* AF_INET socket and address used to receive data. */
28 static int srv;
29 static struct sockaddr_in srv_addr;
31 static int
32 do_sendto (const struct sockaddr_in *addr, int payload)
34 int s = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
35 xconnect (s, (const struct sockaddr *) addr, sizeof (*addr));
37 xsendto (s, &payload, sizeof (payload), 0, (const struct sockaddr *) addr,
38 sizeof (*addr));
40 xclose (s);
42 return 0;
45 static void
46 do_recvmsg_ancillary (bool use_multi_call, struct mmsghdr *mmhdr,
47 void *msgbuf, size_t msgbuflen, int exp_payload)
49 int payload;
50 struct iovec iov =
52 .iov_base = &payload,
53 .iov_len = sizeof (payload)
55 mmhdr->msg_hdr.msg_name = NULL;
56 mmhdr->msg_hdr.msg_iov = &iov;
57 mmhdr->msg_hdr.msg_iovlen = 1;
58 mmhdr->msg_hdr.msg_control = msgbuf;
59 mmhdr->msg_hdr.msg_controllen = msgbuflen;
61 int r;
62 if (use_multi_call)
64 r = recvmmsg (srv, mmhdr, 1, 0, NULL);
65 if (r >= 0)
66 r = mmhdr->msg_len;
68 else
69 r = recvmsg (srv, &mmhdr->msg_hdr, 0);
70 TEST_COMPARE (r, sizeof (int));
71 TEST_COMPARE (payload, exp_payload);
74 /* Check if recvmsg create the additional 64 bit timestamp if only 32 bit
75 is enabled for 64 bit recvmsg symbol. */
76 static void
77 do_test_large_buffer (bool mc)
79 struct mmsghdr mmhdr = { 0 };
80 /* It should be large enough for either timeval/timespec and the
81 64 time type as well. */
83 union
85 struct cmsghdr cmsghdr;
86 char msgbuf[512];
87 } control;
89 /* Enable 32 bit timeval precision and check if no 64 bit timeval stamp
90 is created. */
92 int r = setsockopt (srv, SOL_SOCKET, COMPAT_SO_TIMESTAMP_OLD, &(int){1},
93 sizeof (int));
94 TEST_VERIFY_EXIT (r != -1);
96 do_sendto (&srv_addr, 42);
97 do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42);
99 bool found_timestamp = false;
100 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr);
101 cmsg != NULL;
102 cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg))
104 if (cmsg->cmsg_level != SOL_SOCKET)
105 continue;
107 if (sizeof (time_t) > 4 && cmsg->cmsg_type == COMPAT_SO_TIMESTAMP_NEW)
108 found_timestamp = true;
109 else
110 TEST_VERIFY (cmsg->cmsg_type != COMPAT_SO_TIMESTAMP_NEW);
113 TEST_COMPARE (found_timestamp, sizeof (time_t) > 4);
116 /* Same as before, but for timespec. */
118 int r = setsockopt (srv, SOL_SOCKET, COMPAT_SO_TIMESTAMPNS_OLD, &(int){1},
119 sizeof (int));
120 TEST_VERIFY_EXIT (r != -1);
122 do_sendto (&srv_addr, 42);
123 do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42);
125 bool found_timestamp = false;
126 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr);
127 cmsg != NULL;
128 cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg))
130 if (cmsg->cmsg_level != SOL_SOCKET)
131 continue;
133 if (sizeof (time_t) > 4 && cmsg->cmsg_type == COMPAT_SO_TIMESTAMPNS_NEW)
134 found_timestamp = true;
135 else
136 TEST_VERIFY (cmsg->cmsg_type != COMPAT_SO_TIMESTAMPNS_NEW);
139 TEST_COMPARE (found_timestamp, sizeof (time_t) > 4);
143 /* Check if recvmsg does not create the additional 64 bit timestamp if
144 only 32 bit timestamp is enabled if the ancillary buffer is not large
145 enough. Also checks if MSG_CTRUNC is set iff for 64 bit recvmsg
146 symbol. */
147 static void
148 do_test_small_buffer (bool mc)
150 struct mmsghdr mmhdr = { 0 };
152 /* Enable 32 bit timeval precision and check if no 64 bit timeval stamp
153 is created. */
155 int r = setsockopt (srv, SOL_SOCKET, COMPAT_SO_TIMESTAMP_OLD, &(int){1},
156 sizeof (int));
157 TEST_VERIFY_EXIT (r != -1);
159 union
161 struct cmsghdr cmsghdr;
162 char msgbuf[CMSG_SPACE (sizeof (struct timeval))];
163 } control;
165 do_sendto (&srv_addr, 42);
166 do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42);
168 bool found_timestamp = false;
169 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr);
170 cmsg != NULL;
171 cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg))
173 if (cmsg->cmsg_level != SOL_SOCKET)
174 continue;
176 if (sizeof (time_t) > 4 && cmsg->cmsg_type == COMPAT_SO_TIMESTAMP_NEW)
177 found_timestamp = true;
178 else
179 TEST_VERIFY (cmsg->cmsg_type != COMPAT_SO_TIMESTAMP_NEW);
182 if (sizeof (time_t) > 4)
184 TEST_VERIFY ((mmhdr.msg_hdr.msg_flags & MSG_CTRUNC));
185 TEST_COMPARE (found_timestamp, 0);
187 else
189 TEST_VERIFY (!(mmhdr.msg_hdr.msg_flags & MSG_CTRUNC));
190 TEST_COMPARE (found_timestamp, 0);
194 /* Same as before, but for timespec. */
196 int r = setsockopt (srv, SOL_SOCKET, COMPAT_SO_TIMESTAMPNS_OLD, &(int){1},
197 sizeof (int));
198 TEST_VERIFY_EXIT (r != -1);
200 union
202 struct cmsghdr cmsghdr;
203 char msgbuf[CMSG_SPACE (sizeof (struct timespec))];
204 } control;
206 do_sendto (&srv_addr, 42);
207 do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42);
209 bool found_timestamp = false;
210 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr);
211 cmsg != NULL;
212 cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg))
214 if (cmsg->cmsg_level != SOL_SOCKET)
215 continue;
217 if (sizeof (time_t) > 4 && cmsg->cmsg_type == COMPAT_SO_TIMESTAMPNS_NEW)
218 found_timestamp = true;
219 else
220 TEST_VERIFY (cmsg->cmsg_type != COMPAT_SO_TIMESTAMPNS_NEW);
223 if (sizeof (time_t) > 4)
225 TEST_VERIFY ((mmhdr.msg_hdr.msg_flags & MSG_CTRUNC));
226 TEST_COMPARE (found_timestamp, 0);
228 else
230 TEST_VERIFY ((mmhdr.msg_hdr.msg_flags & MSG_CTRUNC) == 0);
231 TEST_COMPARE (found_timestamp, 0);
236 static int
237 do_test (void)
239 /* This test only make sense for ABIs that support 32 bit time_t socket
240 timestampss. */
241 if (sizeof (time_t) > 4 && __TIMESIZE == 64)
242 return 0;
244 srv = xsocket (AF_INET, SOCK_DGRAM, 0);
245 srv_addr = (struct sockaddr_in) {
246 .sin_family = AF_INET,
247 .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK) },
249 xbind (srv, (struct sockaddr *) &srv_addr, sizeof (srv_addr));
251 socklen_t sa_len = sizeof (srv_addr);
252 xgetsockname (srv, (struct sockaddr *) &srv_addr, &sa_len);
253 TEST_VERIFY (sa_len == sizeof (srv_addr));
256 /* Check recvmsg; */
257 do_test_large_buffer (false);
258 do_test_small_buffer (false);
259 /* Check recvmmsg. */
260 do_test_large_buffer (true);
261 do_test_small_buffer (true);
263 return 0;
266 #include <support/test-driver.c>