Until now, "ipctest" seems only to have been able to test the "pair" parts
of "ipcsocket.c", not the parts that handle connections amongst unrelated
processes.
Attached is a patch to "ipctest.c" to exercise those parts. By invoking
it with the additional argument "-c <n>", it sets up a server and <n>
clients and runs the existing tests through the client/server access
points. (The "-c" means "clients".)
(Actually, the only valid value of "<n>" at present is "1": single client.
But that's still far more functionality than was there before, and you are
welcome to add multi-<n> capability for yet extra flexibility...)
I propose applying this later this week; please feel free to peer-review
it first.
Someone had made a comment about "/tmp/foobar" being a poor name. If I
recall correctly (and it is very vague!) this problem should minor in this
testing context. But if it needs fixing, even if this context, then give
me a little detail and point me in the right direction.
--
: David Lee I.T. Service :
: Senior Systems Programmer Computer Centre :
: Durham University :
: http://www.dur.ac.uk/t.d.lee/ South Road :
: Durham DH1 3LE :
: Phone: +44 191 334 2752 U.K. :
--- lib/clplumbing/ipctest.c.orig Mon Jan 9 12:38:14 2006
+++ lib/clplumbing/ipctest.c Thu Jan 19 14:09:21 2006
@@ -36,6 +36,7 @@
#include <clplumbing/cl_malloc.h>
#define MAXERRORS 1000
+#define MAXERRORS_RECV 10
typedef int (*TestFunc_t)(IPC_Channel*chan, int count);
@@ -58,9 +59,22 @@
= (int (*)(struct pollfd * fds, unsigned int, int)) poll;
static gboolean checkmsg(IPC_Message* rmsg, const char * who, int rcount);
+const char *procname;
+
int iter_def = 10000; /* number of iterations */
int verbosity = 0; /* verbosity level */
-const char *procname;
+
+/*
+ * The ipc interface can be invoked as either:
+ * 1. pair (pipe/socketpair);
+ * 2. separate connect/accept (like server with multiple independent clients).
+ *
+ * If number of clients is given as 0, the "pair" mechanism is used,
+ * otherwise the client/server mechanism.
+ */
+/* *** CLIENTS_MAX currently 1 while coding *** */
+#define CLIENTS_MAX 1 /* max. number of independent clients */
+int clients_def = 0; /* number of independent clients */
static int
channelpair(TestFunc_t clientfunc, TestFunc_t serverfunc, int count)
@@ -153,32 +167,174 @@
return(rc);
}
-#if 0
-/*
- * FIX commpath to non/tmp before enabling this code.
- *
- */
-static void
-clientserverpair(IPC_Channel* channels[2])
+/* server with many clients */
+static int
+clientserver(TestFunc_t clientfunc, TestFunc_t serverfunc, int count, int
clients)
{
- char path[] = IPC_PATH_ATTR;
- char commpath[] = "/tmp/foobar"
- GHashTable * wattrs;
- IPC_WAIT_CONNECTION* wconn;
+ IPC_Channel* channel;
+ int rc = 0;
+ int waitstat = 0;
+ struct IPC_WAIT_CONNECTION *wconn;
+ char path[] = IPC_PATH_ATTR;
+ char commpath[] = "/tmp/foobar"; /* *** CHECK/FIX: Is this OK? */
+ GHashTable * wattrs;
+ int i;
+ pid_t pid;
- wattrs = g_hash_table_new(g_str_hash, g_str_equal);
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: main process",
+ procname, (int)getpid(), __LINE__);
+ }
+
+ switch (fork()) {
+ case -1:
+ cl_perror("can't fork");
+ exit(1);
+ break;
+ default: /* Parent */
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: main waiting...",
+ procname, (int)getpid(), __LINE__);
+ }
+ while ((pid = wait(&waitstat)) > 0) {
+ if (WIFEXITED(waitstat)) {
+ rc += WEXITSTATUS(waitstat);
+ }else{
+ rc += 1;
+ }
+ }
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: main ended rc: %d",
+ procname, (int)getpid(), __LINE__, rc);
+ }
+ if (rc > 127) {
+ rc = 127;
+ }
+ exit(rc);
+ break;
+ case 0: /* Child */
+ break;
+ }
+
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d:",
+ procname, (int)getpid(), __LINE__);
+ }
+ /* set up a server */
+ wattrs = g_hash_table_new(g_str_hash, g_str_equal);
+ if (! wattrs) {
+ cl_perror("g_hash_table_new() failed");
+ exit(1);
+ }
g_hash_table_insert(wattrs, path, commpath);
- wconn = ipc_wait_conn_constructor(IPC_ANYTYPE, wconnattrs);
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d:",
+ procname, (int)getpid(), __LINE__);
+ }
- if (wconn == NULL) {
- cl_perror("Can't create wait connection");
+ wconn = ipc_wait_conn_constructor(IPC_ANYTYPE, wattrs);
+ if (! wconn) {
+ cl_perror("could not establish server");
exit(1);
}
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d:",
+ procname, (int)getpid(), __LINE__);
+ }
+
+ /* spawn the clients */
+ for (i = 1; i <= clients; i++) {
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: fork client %d of %d",
+ procname, (int)getpid(), __LINE__, i, clients);
+ }
+ switch (fork()) {
+ case -1:
+ cl_perror("can't fork");
+ exit(1);
+ break;
+
+ case 0: /* echo "client" Child */
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: client %d
starting...",
+ procname, (int)getpid(), __LINE__, i);
+ }
+ channel = ipc_channel_constructor(IPC_ANYTYPE,
wattrs);
+ if (channel == NULL) {
+ cl_perror("client: channel creation
failed");
+ }
+
+ rc = channel->ops->initiate_connection(channel);
+ if (rc != IPC_OK) {
+ cl_perror("channel[1] failed to
connect");
+ }
+ checksock(channel);
+ rc = clientfunc(channel, count);
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: client %d
ended rc:%d",
+ procname, (int)getpid(), __LINE__,
rc, i);
+ }
+ exit (rc > 127 ? 127 : rc);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: server starting...",
+ procname, (int)getpid(), __LINE__);
+ }
+ /* accept on server */
+ /* ***
+ * Two problems (or more) here:
+ * 1. What to do if no incoming call pending?
+ * At present, fudge by sleeping a little so client gets started.
+ * 2. How to handle multiple clients?
+ * Would need to be able to await both new connections and
+ * data on existing connections.
+ * At present, fudge CLIENTS_MAX as 1.
+ * ***
+ */
+ sleep(1); /* *** */
+ channel = wconn->ops->accept_connection(wconn, NULL);
+ if (channel == NULL) {
+ cl_perror("server: acceptance failed");
+ }
+
+ checksock(channel);
+
+ rc = serverfunc(channel, count);
+
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: server ended rc:%d",
+ procname, (int)getpid(), __LINE__, rc);
+ }
+
+ /* reap the clients */
+ for (i = 1; i <= clients; i++) {
+ pid_t pid;
+
+ pid = wait(&waitstat);
+ if (verbosity >= 1) {
+ cl_log(LOG_DEBUG, "%s[%d]%d: client %d reaped:%d",
+ procname, (int)getpid(), __LINE__,
+ (int) pid, WIFEXITED(waitstat));
+ }
+ if (WIFEXITED(waitstat)) {
+ rc += WEXITSTATUS(waitstat);
+ }else{
+ rc += 1;
+ }
+ }
+
+ return(rc);
}
-#endif
+
static void
checkifblocked(IPC_Channel* chan)
{
@@ -193,24 +349,30 @@
#endif
static int
-transport_tests(int iterations)
+transport_tests(int iterations, int clients)
{
int rc = 0;
#ifdef CHEAT_CHECKS
memset(SeqNums, 0, sizeof(SeqNums));
#endif
- rc += channelpair(echoclient, echoserver, iterations);
+ rc += (clients <= 0)
+ ? channelpair(echoclient, echoserver, iterations)
+ : clientserver(echoclient, echoserver, iterations, clients);
#ifdef CHEAT_CHECKS
memset(SeqNums, 0, sizeof(SeqNums));
#endif
- rc += channelpair(asyn_echoclient, asyn_echoserver, iterations);
+ rc += (clients <= 0)
+ ? channelpair(asyn_echoclient, asyn_echoserver, iterations)
+ : clientserver(asyn_echoclient, asyn_echoserver, iterations, clients);
#ifdef CHEAT_CHECKS
memset(SeqNums, 0, sizeof(SeqNums));
#endif
- rc += channelpair(mainloop_client, mainloop_server, iterations);
+ rc += (clients <= 0)
+ ? channelpair(mainloop_client, mainloop_server, iterations)
+ : clientserver(mainloop_client, mainloop_server, iterations, clients);
return rc;
}
@@ -220,18 +382,21 @@
{
int argflag, argerrs;
int iterations;
+ int clients;
int rc = 0;
/*
* Check and process arguments.
* -v: verbose
* -i: number of iterations
+ * -c: number of clients (invokes client/server mechanism)
*/
procname = basename(argv[0]);
argerrs = 0;
iterations = iter_def;
- while ((argflag = getopt(argc, argv, "i:v")) != EOF) {
+ clients = clients_def;
+ while ((argflag = getopt(argc, argv, "i:vuc:")) != EOF) {
switch (argflag) {
case 'i': /* iterations */
iterations = atoi(optarg);
@@ -239,16 +404,25 @@
case 'v': /* verbosity */
verbosity++;
break;
+ case 'c': /* number of clients */
+ clients = atoi(optarg);
+ if (clients < 1 || clients > CLIENTS_MAX) {
+ fprintf(stderr, "number of clients out of range"
+ "(1 to %d)\n", CLIENTS_MAX);
+ argerrs++;
+ }
+ break;
default:
argerrs++;
break;
}
}
if (argerrs) {
- fprintf(stderr, "Usage: %s [-v] [-i iterations]\n"
+ fprintf(stderr, "Usage: %s [-v] [-i iterations] [-c clients]\n"
"\t-v : verbose\n"
- "\t-i : iterations (default %d)\n",
- procname, iter_def);
+ "\t-i : iterations (default %d)\n"
+ "\t-c : number of clients (default %d; nonzero invokes
client/server)\n",
+ procname, iter_def, clients_def);
exit(1);
}
@@ -259,7 +433,7 @@
- rc += transport_tests(iterations);
+ rc += transport_tests(iterations, clients);
#if 0
/* Broken for the moment - need to fix it long term */
@@ -268,7 +442,7 @@
g_main_set_poll_func(cl_glibpoll);
ipc_set_pollfunc(cl_poll);
- rc += transport_tests(5 * iterations);
+ rc += transport_tests(5 * iterations, clients);
#endif
cl_log(LOG_INFO, "TOTAL errors: %d", rc);
@@ -280,6 +454,10 @@
checksock(IPC_Channel* channel)
{
+ if (!channel) {
+ cl_log(LOG_ERR, "Channel null");
+ return 1;
+ }
if (!IPC_ISRCONN(channel)) {
cl_log(LOG_ERR, "Channel status is %d"
", not IPC_CONNECT", channel->ch_status);
@@ -470,6 +648,12 @@
, rc, j, errno);
cl_perror("recv");
++errcount;
+ if (errcount > MAXERRORS_RECV) {
+ cl_log(LOG_ERR,
+ "echoclient: errcount excessive: %d:
abandoning",
+ errcount);
+ exit(1);
+ }
--j;
rmsg=NULL;
continue;
_______________________________________________________
Linux-HA-Dev: [email protected]
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/