support: Add envp argument to support_capture_subprogram
[glibc.git] / sunrpc / tst-svc_register.c
blobe5ebfeb66d82d863f11655d4c03d014c07a4eaed
1 /* Test svc_register/svc_unregister rpcbind interaction (bug 5010).
2 Copyright (C) 2017-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 /* This test uses a stub rpcbind server (implemented in a child
20 process using rpcbind_dispatch/run_rpcbind) to check how RPC
21 services are registered and unregistered using the rpcbind
22 protocol. For each subtest, a separate rpcbind test server is
23 spawned and terminated. */
25 #include <errno.h>
26 #include <netinet/in.h>
27 #include <rpc/clnt.h>
28 #include <rpc/pmap_prot.h>
29 #include <rpc/svc.h>
30 #include <signal.h>
31 #include <support/check.h>
32 #include <support/namespace.h>
33 #include <support/test-driver.h>
34 #include <support/xsocket.h>
35 #include <support/xthread.h>
36 #include <support/xunistd.h>
37 #include <sys/socket.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
41 #include <libc-symbols.h>
42 #include <shlib-compat.h>
44 /* These functions are only available as compat symbols. */
45 compat_symbol_reference (libc, xdr_pmap, xdr_pmap, GLIBC_2_0);
46 compat_symbol_reference (libc, svc_unregister, svc_unregister, GLIBC_2_0);
48 /* Server callback for the unused RPC service which is registered and
49 unregistered. */
50 static void
51 server_dispatch (struct svc_req *request, SVCXPRT *transport)
53 FAIL_EXIT1 ("server_dispatch called");
56 /* The port on which rpcbind listens for incoming requests. */
57 static inline struct sockaddr_in
58 rpcbind_address (void)
60 return (struct sockaddr_in)
62 .sin_family = AF_INET,
63 .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
64 .sin_port = htons (PMAPPORT)
68 /* Data provided by the test server after running the test, to see
69 that the expected calls (and only those) happened. */
70 struct test_state
72 bool_t set_called;
73 bool_t unset_called;
76 static bool_t
77 xdr_test_state (XDR *xdrs, void *data, ...)
79 struct test_state *p = data;
80 return xdr_bool (xdrs, &p->set_called)
81 && xdr_bool (xdrs, &p->unset_called);
84 enum
86 /* Coordinates of our test service. These numbers are
87 arbitrary. */
88 PROGNUM = 123,
89 VERSNUM = 456,
91 /* Extension for this test. */
92 PROC_GET_STATE_AND_EXIT = 10760
95 /* Dummy implementation of the rpcbind service, with the
96 PROC_GET_STATE_AND_EXIT extension. */
97 static void
98 rpcbind_dispatch (struct svc_req *request, SVCXPRT *transport)
100 static struct test_state state = { 0, };
102 if (test_verbose)
103 printf ("info: rpcbind request %lu\n", request->rq_proc);
105 switch (request->rq_proc)
107 case PMAPPROC_SET:
108 case PMAPPROC_UNSET:
109 TEST_VERIFY (state.set_called == (request->rq_proc == PMAPPROC_UNSET));
110 TEST_VERIFY (!state.unset_called);
112 struct pmap query = { 0, };
113 TEST_VERIFY
114 (svc_getargs (transport, (xdrproc_t) xdr_pmap, (void *) &query));
115 if (test_verbose)
116 printf (" pm_prog=%lu pm_vers=%lu pm_prot=%lu pm_port=%lu\n",
117 query.pm_prog, query.pm_vers, query.pm_prot, query.pm_port);
118 TEST_VERIFY (query.pm_prog == PROGNUM);
119 TEST_VERIFY (query.pm_vers == VERSNUM);
121 if (request->rq_proc == PMAPPROC_SET)
122 state.set_called = TRUE;
123 else
124 state.unset_called = TRUE;
126 bool_t result = TRUE;
127 TEST_VERIFY (svc_sendreply (transport,
128 (xdrproc_t) xdr_bool, (void *) &result));
129 break;
131 case PROC_GET_STATE_AND_EXIT:
132 TEST_VERIFY (svc_sendreply (transport,
133 xdr_test_state, (void *) &state));
134 _exit (0);
135 break;
137 default:
138 FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
142 /* Run the rpcbind test server. */
143 static void
144 run_rpcbind (int rpcbind_sock)
146 SVCXPRT *rpcbind_transport = svcudp_create (rpcbind_sock);
147 TEST_VERIFY (svc_register (rpcbind_transport, PMAPPROG, PMAPVERS,
148 rpcbind_dispatch,
149 /* Do not register with rpcbind. */
150 0));
151 svc_run ();
154 /* Call out to the rpcbind test server to retrieve the test status
155 information. */
156 static struct test_state
157 get_test_state (void)
159 int socket = RPC_ANYSOCK;
160 struct sockaddr_in address = rpcbind_address ();
161 CLIENT *client = clntudp_create
162 (&address, PMAPPROG, PMAPVERS, (struct timeval) { 1, 0}, &socket);
163 struct test_state result = { 0 };
164 TEST_VERIFY (clnt_call (client, PROC_GET_STATE_AND_EXIT,
165 (xdrproc_t) xdr_void, NULL,
166 xdr_test_state, (void *) &result,
167 ((struct timeval) { 3, 0}))
168 == RPC_SUCCESS);
169 clnt_destroy (client);
170 return result;
173 /* Used by test_server_thread to receive test parameters. */
174 struct test_server_args
176 bool use_rpcbind;
177 bool use_unregister;
180 /* RPC test server. Used to verify the svc_unregister behavior during
181 thread cleanup. */
182 static void *
183 test_server_thread (void *closure)
185 struct test_server_args *args = closure;
186 SVCXPRT *transport = svcudp_create (RPC_ANYSOCK);
187 int protocol;
188 if (args->use_rpcbind)
189 protocol = IPPROTO_UDP;
190 else
191 /* Do not register with rpcbind. */
192 protocol = 0;
193 TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM,
194 server_dispatch, protocol));
195 if (args->use_unregister)
196 svc_unregister (PROGNUM, VERSNUM);
197 SVC_DESTROY (transport);
198 return NULL;
201 static int
202 do_test (void)
204 support_become_root ();
205 support_enter_network_namespace ();
207 /* Try to bind to the rpcbind port. */
208 int rpcbind_sock = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
210 struct sockaddr_in sin = rpcbind_address ();
211 if (bind (rpcbind_sock, (struct sockaddr *) &sin, sizeof (sin)) != 0)
213 /* If the port is not available, we cannot run this test. */
214 printf ("warning: could not bind to rpcbind port %d: %m\n",
215 (int) PMAPPORT);
216 return EXIT_UNSUPPORTED;
220 for (int use_thread = 0; use_thread < 2; ++use_thread)
221 for (int use_rpcbind = 0; use_rpcbind < 2; ++use_rpcbind)
222 for (int use_unregister = 0; use_unregister < 2; ++use_unregister)
224 if (test_verbose)
225 printf ("info: * use_thread=%d use_rpcbind=%d use_unregister=%d\n",
226 use_thread, use_rpcbind, use_unregister);
228 /* Create the subprocess which runs the actual test. The
229 kernel will queue the UDP packets to the rpcbind
230 process. */
231 pid_t svc_pid = xfork ();
232 if (svc_pid == 0)
234 struct test_server_args args =
236 .use_rpcbind = use_rpcbind,
237 .use_unregister = use_unregister,
239 if (use_thread)
240 xpthread_join (xpthread_create
241 (NULL, test_server_thread, &args));
242 else
243 test_server_thread (&args);
244 /* We cannot use _exit here because we want to test the
245 process cleanup. */
246 exit (0);
249 /* Create the subprocess for the rpcbind test server. */
250 pid_t rpcbind_pid = xfork ();
251 if (rpcbind_pid == 0)
252 run_rpcbind (rpcbind_sock);
254 int status;
255 xwaitpid (svc_pid, &status, 0);
256 TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == 0);
258 if (!use_rpcbind)
259 /* Wait a bit, to see if the packet arrives on the rpcbind
260 port. The choice is of the timeout is arbitrary, but
261 should be long enough even for slow/busy systems. For
262 the use_rpcbind case, waiting on svc_pid above makes
263 sure that the test server has responded because
264 svc_register/svc_unregister are supposed to wait for a
265 reply. */
266 usleep (300 * 1000);
268 struct test_state state = get_test_state ();
269 if (use_rpcbind)
271 TEST_VERIFY (state.set_called);
272 if (use_thread || use_unregister)
273 /* Thread cleanup or explicit svc_unregister will
274 result in a rpcbind unset RPC call. */
275 TEST_VERIFY (state.unset_called);
276 else
277 /* This is arguably a bug: Regular process termination
278 does not unregister the service with rpcbind. The
279 unset rpcbind call happens from a __libc_freeres,
280 and this only happens when running under memory debuggers
281 such as valgrind. */
282 TEST_VERIFY (!state.unset_called);
284 else
286 /* If rpcbind registration is not requested, we do not
287 expect any rpcbind calls. */
288 TEST_VERIFY (!state.set_called);
289 TEST_VERIFY (!state.unset_called);
292 xwaitpid (rpcbind_pid, &status, 0);
293 TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == 0);
296 return 0;
299 #include <support/test-driver.c>