openafs/tests/common/servers.c
Andrew Deason 66d0f91791 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 <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
2020-03-31 17:34:51 -04:00

132 lines
2.8 KiB
C

#include <afsconfig.h>
#include <afs/param.h>
#include <roken.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <rx/rx.h>
#include <afs/cellconfig.h>
#include <tests/tap/basic.h>
#include "common.h"
/* Start up the VLserver, using the configuration in dirname, and putting our
* logs there too.
*/
int
afstest_StartVLServer(char *dirname, pid_t *serverPid)
{
pid_t pid;
int status;
pid = fork();
if (pid == -1) {
exit(1);
/* Argggggghhhhh */
} else if (pid == 0) {
char *binPath, *logPath, *dbPath, *build;
/* Child */
build = getenv("BUILD");
if (build == NULL)
build = "..";
if (asprintf(&binPath, "%s/../src/tvlserver/vlserver", build) < 0 ||
asprintf(&logPath, "%s/VLLog", dirname) < 0 ||
asprintf(&dbPath, "%s/vldb", dirname) < 0) {
fprintf(stderr, "Out of memory building vlserver arguments\n");
exit(1);
}
execl(binPath, "vlserver",
"-logfile", logPath, "-database", dbPath, "-config", dirname, NULL);
fprintf(stderr, "Running %s failed\n", binPath);
exit(1);
}
if (waitpid(pid, &status, WNOHANG) != 0) {
fprintf(stderr, "Error starting vlserver\n");
return -1;
}
diag("Sleeping for a few seconds to let the vlserver startup");
sleep(5);
if (waitpid(pid, &status, WNOHANG) != 0) {
fprintf(stderr, "vlserver died during startup\n");
return -1;
}
*serverPid = pid;
return 0;
}
int
afstest_StopServer(pid_t serverPid)
{
int status;
kill(serverPid, SIGTERM);
waitpid(serverPid, &status, 0);
if (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM) {
fprintf(stderr, "Server died exited on signal %d\n", WTERMSIG(status));
return -1;
}
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
fprintf(stderr, "Server exited with code %d\n", WEXITSTATUS(status));
return -1;
}
return 0;
}
int
afstest_StartTestRPCService(const char *configPath,
pid_t signal_pid,
u_short port,
u_short serviceId,
afs_int32 (*proc) (struct rx_call *))
{
struct afsconf_dir *dir;
struct rx_securityClass **classes;
afs_int32 numClasses;
int code;
struct rx_service *service;
dir = afsconf_Open(configPath);
if (dir == NULL) {
fprintf(stderr, "Server: Unable to open config directory\n");
return -1;
}
code = rx_Init(htons(port));
if (code != 0) {
fprintf(stderr, "Server: Unable to initialise RX\n");
return -1;
}
if (signal_pid != 0) {
kill(signal_pid, SIGUSR1);
}
afsconf_BuildServerSecurityObjects(dir, &classes, &numClasses);
service = rx_NewService(0, serviceId, "test", classes, numClasses,
proc);
if (service == NULL) {
fprintf(stderr, "Server: Unable to start to test service\n");
return -1;
}
rx_StartServer(1);
return 0; /* Not reached, we donated ourselves to StartServer */
}