From: Andrew Deason Date: Tue, 24 Mar 2020 16:59:48 +0000 (-0500) Subject: tests: Wait for server start in auth/superuser-t X-Git-Tag: openafs-devel-1_9_0~122 X-Git-Url: http://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=66d0f91791695ac585f0511d0dadafd4e570b1bf tests: Wait for server start in auth/superuser-t The auth/superuser-t test runs an Rx server and client in two child processes. If the client process tries to contact the server before the server has started listening on its port, some tests involving RPCs can fail (notably test 39, "Can run a simple RPC"). Normally if we try to contact a server that's not there, Rx will try resending its packets a few times, but on Linux with AFS_RXERRQ_ENV, if the port isn't open at all, we can get an ICMP_PORT_UNREACH error, which causes the relevant Rx call to die immediately with RX_CALL_DEAD. This means that if the auth/superuser-t client is only just a bit faster than the server starting up, tests can fail, since the server's port is not open yet. To avoid this, we can wait until the server's port is open before starting the client process. To do this, have the server process send a SIGUSR1 to the parent after rx_Init() is called, and have the parent process wait for the SIGUSR1 (waiting for a max of 5 seconds before failing). This should guarantee that the server's port will be open by the time the client starts running. Note that before commit 086d1858 (LINUX: Include linux/time.h for linux/errqueue.h), AFS_RXERRQ_ENV was mistakenly disabled on Linux 3.17+, so this issue was probably not possible on recent Linux before that commit. Change-Id: I0032a640b83c24f72c03e7bea100df5bc3d9ed4c Reviewed-on: https://gerrit.openafs.org/14109 Tested-by: BuildBot Reviewed-by: Benjamin Kaduk Reviewed-by: Cheyenne Wills --- diff --git a/tests/auth/superuser-t.c b/tests/auth/superuser-t.c index 63be96a..92c48c7 100644 --- a/tests/auth/superuser-t.c +++ b/tests/auth/superuser-t.c @@ -29,6 +29,8 @@ #ifdef HAVE_SYS_WAIT_H #include #endif +#include +#include #ifdef IGNORE_SOME_GCC_WARNINGS # pragma GCC diagnostic warning "-Wdeprecated-declarations" @@ -365,6 +367,34 @@ STEST_NewWhoAmI(struct rx_call *call, char **result) return 0; } +/* + * Primitive replacement for using sigtimedwait(). Just see if 'signo' is + * pending, and if it's not, wait 100ms and try again. Try this for + * approximately as many times as it takes to wait for 'nsecs' seconds. + */ +static int +waitforsig(int signo, int nsecs) +{ + int nsleeps; + + for (nsleeps = 0; nsleeps < nsecs * 10; nsleeps++) { + sigset_t set; + struct timespec timeo; + + opr_Verify(sigpending(&set) == 0); + if (sigismember(&set, signo)) { + return 0; + } + + /* Sleep for 100ms */ + timeo.tv_sec = 0; + timeo.tv_nsec = 100 * 1000 * 1000; + opr_Verify(nanosleep(&timeo, NULL) == 0); + } + + return -1; +} + int main(int argc, char **argv) { struct afsconf_dir *dir; @@ -372,6 +402,7 @@ int main(int argc, char **argv) int serverPid, clientPid, waited, stat; int code; int ret = 0; + sigset_t set; char *argv0 = afstest_GetProgname(argv); afstest_SkipTestsIfBadHostname(); @@ -381,8 +412,8 @@ int main(int argc, char **argv) if (argc == 3 ) { if (strcmp(argv[1], "-server") == 0) { globalDir = afsconf_Open(argv[2]); - afstest_StartTestRPCService(argv[2], TEST_PORT, TEST_SERVICE_ID, - TEST_ExecuteRequest); + afstest_StartTestRPCService(argv[2], getppid(), TEST_PORT, + TEST_SERVICE_ID, TEST_ExecuteRequest); exit(0); } else if (strcmp(argv[1], "-client") == 0) { startClient(argv[2]); @@ -396,6 +427,10 @@ int main(int argc, char **argv) /* Otherwise, do the basic configuration, then start the client and * server */ + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + opr_Verify(sigprocmask(SIG_BLOCK, &set, NULL) == 0); + dirname = afstest_BuildTestConfig(); dir = afsconf_Open(dirname); @@ -421,6 +456,17 @@ int main(int argc, char **argv) ret = 1; goto out; } + + /* Our server child pid will send us a SIGUSR1 when it's started listening + * on its port. Wait for up to 5 seconds to get the USR1. */ + if (waitforsig(SIGUSR1, 5) != 0) { + fprintf(stderr, "%s: Timed out waiting for SIGUSR1 from server child\n", + argv0); + kill(serverPid, SIGTERM); + ret = 1; + goto out; + } + clientPid = fork(); if (clientPid == -1) { kill(serverPid, SIGTERM); diff --git a/tests/common/common.h b/tests/common/common.h index 061f707..e1a407c 100644 --- a/tests/common/common.h +++ b/tests/common/common.h @@ -40,7 +40,7 @@ extern struct rx_securityClass struct rx_call; extern int afstest_StartVLServer(char *dirname, pid_t *serverPid); extern int afstest_StopServer(pid_t serverPid); -extern int afstest_StartTestRPCService(const char *, u_short, u_short, +extern int afstest_StartTestRPCService(const char *, pid_t, u_short, u_short, afs_int32 (*proc)(struct rx_call *)); /* ubik.c */ diff --git a/tests/common/servers.c b/tests/common/servers.c index 24b2bee..70dd366 100644 --- a/tests/common/servers.c +++ b/tests/common/servers.c @@ -90,6 +90,7 @@ afstest_StopServer(pid_t serverPid) int afstest_StartTestRPCService(const char *configPath, + pid_t signal_pid, u_short port, u_short serviceId, afs_int32 (*proc) (struct rx_call *)) @@ -112,6 +113,10 @@ afstest_StartTestRPCService(const char *configPath, return -1; } + if (signal_pid != 0) { + kill(signal_pid, SIGUSR1); + } + afsconf_BuildServerSecurityObjects(dir, &classes, &numClasses); service = rx_NewService(0, serviceId, "test", classes, numClasses, proc);