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>
21 #include <support/check.h>
22 #include <support/xsocket.h>
23 #include <support/xunistd.h>
25 #include <socket-constants-time64.h>
27 /* AF_INET socket and address used to receive data. */
29 static struct sockaddr_in srv_addr
;
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
,
46 do_recvmsg_ancillary (bool use_multi_call
, struct mmsghdr
*mmhdr
,
47 void *msgbuf
, size_t msgbuflen
, int exp_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
;
64 r
= recvmmsg (srv
, mmhdr
, 1, 0, NULL
);
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. */
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. */
85 struct cmsghdr cmsghdr
;
89 /* Enable 32 bit timeval precision and check if no 64 bit timeval stamp
92 int r
= setsockopt (srv
, SOL_SOCKET
, COMPAT_SO_TIMESTAMP_OLD
, &(int){1},
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
);
102 cmsg
= CMSG_NXTHDR (&mmhdr
.msg_hdr
, cmsg
))
104 if (cmsg
->cmsg_level
!= SOL_SOCKET
)
107 if (sizeof (time_t) > 4 && cmsg
->cmsg_type
== COMPAT_SO_TIMESTAMP_NEW
)
108 found_timestamp
= true;
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},
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
);
128 cmsg
= CMSG_NXTHDR (&mmhdr
.msg_hdr
, cmsg
))
130 if (cmsg
->cmsg_level
!= SOL_SOCKET
)
133 if (sizeof (time_t) > 4 && cmsg
->cmsg_type
== COMPAT_SO_TIMESTAMPNS_NEW
)
134 found_timestamp
= true;
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
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
155 int r
= setsockopt (srv
, SOL_SOCKET
, COMPAT_SO_TIMESTAMP_OLD
, &(int){1},
157 TEST_VERIFY_EXIT (r
!= -1);
161 struct cmsghdr cmsghdr
;
162 char msgbuf
[CMSG_SPACE (sizeof (struct timeval
))];
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
);
171 cmsg
= CMSG_NXTHDR (&mmhdr
.msg_hdr
, cmsg
))
173 if (cmsg
->cmsg_level
!= SOL_SOCKET
)
176 if (sizeof (time_t) > 4 && cmsg
->cmsg_type
== COMPAT_SO_TIMESTAMP_NEW
)
177 found_timestamp
= true;
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);
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},
198 TEST_VERIFY_EXIT (r
!= -1);
202 struct cmsghdr cmsghdr
;
203 char msgbuf
[CMSG_SPACE (sizeof (struct timespec
))];
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
);
212 cmsg
= CMSG_NXTHDR (&mmhdr
.msg_hdr
, cmsg
))
214 if (cmsg
->cmsg_level
!= SOL_SOCKET
)
217 if (sizeof (time_t) > 4 && cmsg
->cmsg_type
== COMPAT_SO_TIMESTAMPNS_NEW
)
218 found_timestamp
= true;
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);
230 TEST_VERIFY ((mmhdr
.msg_hdr
.msg_flags
& MSG_CTRUNC
) == 0);
231 TEST_COMPARE (found_timestamp
, 0);
239 /* This test only make sense for ABIs that support 32 bit time_t socket
241 if (sizeof (time_t) > 4 && __TIMESIZE
== 64)
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
));
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);
266 #include <support/test-driver.c>