diff options
Diffstat (limited to 'sunrpc/tst-udp-nonblocking.c')
-rw-r--r-- | sunrpc/tst-udp-nonblocking.c | 333 |
1 files changed, 0 insertions, 333 deletions
diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c deleted file mode 100644 index 1d6a7f4b56..0000000000 --- a/sunrpc/tst-udp-nonblocking.c +++ /dev/null @@ -1,333 +0,0 @@ -/* Test non-blocking use of the UDP client. - Copyright (C) 2017 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <http://www.gnu.org/licenses/>. */ - -#include <netinet/in.h> -#include <rpc/clnt.h> -#include <rpc/svc.h> -#include <stdbool.h> -#include <string.h> -#include <support/check.h> -#include <support/namespace.h> -#include <support/test-driver.h> -#include <support/xsocket.h> -#include <support/xunistd.h> -#include <sys/socket.h> -#include <time.h> -#include <unistd.h> - -/* Test data serialization and deserialization. */ - -struct test_query -{ - uint32_t a; - uint32_t b; - uint32_t timeout_ms; -}; - -static bool_t -xdr_test_query (XDR *xdrs, void *data, ...) -{ - struct test_query *p = data; - return xdr_uint32_t (xdrs, &p->a) - && xdr_uint32_t (xdrs, &p->b) - && xdr_uint32_t (xdrs, &p->timeout_ms); -} - -struct test_response -{ - uint32_t server_id; - uint32_t seq; - uint32_t sum; -}; - -static bool_t -xdr_test_response (XDR *xdrs, void *data, ...) -{ - struct test_response *p = data; - return xdr_uint32_t (xdrs, &p->server_id) - && xdr_uint32_t (xdrs, &p->seq) - && xdr_uint32_t (xdrs, &p->sum); -} - -/* Implementation of the test server. */ - -enum - { - /* Number of test servers to run. */ - SERVER_COUNT = 3, - - /* RPC parameters, chosen at random. */ - PROGNUM = 8242, - VERSNUM = 19654, - - /* Main RPC operation. */ - PROC_ADD = 1, - - /* Request process termination. */ - PROC_EXIT, - - /* Special exit status to mark successful processing. */ - EXIT_MARKER = 55, - }; - -/* Set by the parent process to tell test servers apart. */ -static int server_id; - -/* Implementation of the test server. */ -static void -server_dispatch (struct svc_req *request, SVCXPRT *transport) -{ - /* Query sequence number. */ - static uint32_t seq = 0; - ++seq; - static bool proc_add_seen; - - if (test_verbose) - printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n", - server_id, seq, request->rq_proc); - - switch (request->rq_proc) - { - case PROC_ADD: - { - struct test_query query; - memset (&query, 0xc0, sizeof (query)); - TEST_VERIFY_EXIT - (svc_getargs (transport, xdr_test_query, - (void *) &query)); - - if (test_verbose) - printf (" a=%u b=%u timeout_ms=%u\n", - query.a, query.b, query.timeout_ms); - - usleep (query.timeout_ms * 1000); - - struct test_response response = - { - .server_id = server_id, - .seq = seq, - .sum = query.a + query.b, - }; - TEST_VERIFY (svc_sendreply (transport, xdr_test_response, - (void *) &response)); - if (test_verbose) - printf (" server id %d response seq=%u sent\n", server_id, seq); - proc_add_seen = true; - } - break; - - case PROC_EXIT: - TEST_VERIFY (proc_add_seen); - TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); - _exit (EXIT_MARKER); - break; - - default: - FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); - break; - } -} - -/* Return the number seconds since an arbitrary point in time. */ -static double -get_ticks (void) -{ - { - struct timespec ts; - if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) - return ts.tv_sec + ts.tv_nsec * 1e-9; - } - { - struct timeval tv; - TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); - return tv.tv_sec + tv.tv_usec * 1e-6; - } -} - -static int -do_test (void) -{ - support_become_root (); - support_enter_network_namespace (); - - /* Information about the test servers. */ - struct - { - SVCXPRT *transport; - struct sockaddr_in address; - pid_t pid; - uint32_t xid; - } servers[SERVER_COUNT]; - - /* Spawn the test servers. */ - for (int i = 0; i < SERVER_COUNT; ++i) - { - servers[i].transport = svcudp_create (RPC_ANYSOCK); - TEST_VERIFY_EXIT (servers[i].transport != NULL); - servers[i].address = (struct sockaddr_in) - { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl (INADDR_LOOPBACK), - .sin_port = htons (servers[i].transport->xp_port), - }; - servers[i].xid = 0xabcd0101 + i; - if (test_verbose) - printf ("info: setting up server %d xid=%x on port %d\n", - i, servers[i].xid, servers[i].transport->xp_port); - - server_id = i; - servers[i].pid = xfork (); - if (servers[i].pid == 0) - { - TEST_VERIFY (svc_register (servers[i].transport, - PROGNUM, VERSNUM, server_dispatch, 0)); - svc_run (); - FAIL_EXIT1 ("supposed to be unreachable"); - } - /* We need to close the socket so that we do not accidentally - consume the request. */ - TEST_VERIFY (close (servers[i].transport->xp_sock) == 0); - } - - - /* The following code mirrors what ypbind does. */ - - /* Copied from clnt_udp.c (like ypbind). */ - struct cu_data - { - int cu_sock; - bool_t cu_closeit; - struct sockaddr_in cu_raddr; - int cu_rlen; - struct timeval cu_wait; - struct timeval cu_total; - struct rpc_err cu_error; - XDR cu_outxdrs; - u_int cu_xdrpos; - u_int cu_sendsz; - char *cu_outbuf; - u_int cu_recvsz; - char cu_inbuf[1]; - }; - - int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); - CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM, - /* 5 seconds per-response timeout. */ - ((struct timeval) { 5, 0 }), - &client_socket); - TEST_VERIFY (clnt != NULL); - clnt->cl_auth = authunix_create_default (); - { - struct timeval zero = { 0, 0 }; - TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero)); - } - - /* Poke at internal data structures (like ypbind). */ - struct cu_data *cu = (struct cu_data *) clnt->cl_private; - - /* Send a ping to each server. */ - double before_pings = get_ticks (); - for (int i = 0; i < SERVER_COUNT; ++i) - { - if (test_verbose) - printf ("info: sending server %d ping\n", i); - /* Reset the xid because it is changed by each invocation of - clnt_call. Subtract one to compensate for the xid update - during the call. */ - *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1; - cu->cu_raddr = servers[i].address; - - struct test_query query = { .a = 100, .b = i + 1 }; - if (i == 1) - /* Shorter timeout to prefer this server. These timeouts must - be much shorter than the 5-second per-response timeout - configured with clntudp_create. */ - query.timeout_ms = 700; - else - query.timeout_ms = 1400; - struct test_response response = { 0 }; - /* NB: Do not check the return value. The server reply will - prove that the call worked. */ - double before_one_ping = get_ticks (); - clnt_call (clnt, PROC_ADD, - xdr_test_query, (void *) &query, - xdr_test_response, (void *) &response, - ((struct timeval) { 0, 0 })); - double after_one_ping = get_ticks (); - if (test_verbose) - printf ("info: non-blocking send took %f seconds\n", - after_one_ping - before_one_ping); - /* clnt_call should return immediately. Accept some delay in - case the process is descheduled. */ - TEST_VERIFY (after_one_ping - before_one_ping < 0.3); - } - - /* Collect the non-blocking response. */ - if (test_verbose) - printf ("info: collecting response\n"); - struct test_response response = { 0 }; - TEST_VERIFY - (clnt_call (clnt, PROC_ADD, NULL, NULL, - xdr_test_response, (void *) &response, - ((struct timeval) { 0, 0 })) == RPC_SUCCESS); - double after_pings = get_ticks (); - if (test_verbose) - printf ("info: send/receive took %f seconds\n", - after_pings - before_pings); - /* Expected timeout is 0.7 seconds. */ - TEST_VERIFY (0.7 <= after_pings - before_pings); - TEST_VERIFY (after_pings - before_pings < 1.2); - - uint32_t xid; - memcpy (&xid, &cu->cu_inbuf, sizeof (xid)); - if (test_verbose) - printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n", - xid, response.server_id, response.seq, response.sum); - /* Check that the reply from the preferred server was used. */ - TEST_VERIFY (servers[1].xid == xid); - TEST_VERIFY (response.server_id == 1); - TEST_VERIFY (response.seq == 1); - TEST_VERIFY (response.sum == 102); - - auth_destroy (clnt->cl_auth); - clnt_destroy (clnt); - - for (int i = 0; i < SERVER_COUNT; ++i) - { - if (test_verbose) - printf ("info: requesting server %d termination\n", i); - client_socket = RPC_ANYSOCK; - clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM, - ((struct timeval) { 5, 0 }), - &client_socket); - TEST_VERIFY_EXIT (clnt != NULL); - TEST_VERIFY (clnt_call (clnt, PROC_EXIT, - (xdrproc_t) xdr_void, NULL, - (xdrproc_t) xdr_void, NULL, - ((struct timeval) { 3, 0 })) == RPC_SUCCESS); - clnt_destroy (clnt); - - int status; - xwaitpid (servers[i].pid, &status, 0); - TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); - } - - return 0; -} - -#include <support/test-driver.c> |