svn commit: r250076 - stable/9/tools/regression/sockets/unix_cmsg
Sergey Kandaurov
pluknet at FreeBSD.org
Mon Apr 29 21:30:05 UTC 2013
Author: pluknet
Date: Mon Apr 29 21:30:04 2013
New Revision: 250076
URL: http://svnweb.freebsd.org/changeset/base/250076
Log:
MFC r243314:
Zero the whole struct not just the size of a pointer.
MFC r246670:
Major update for unix_cmsg.
PR: bin/131567
Submitted by: Andrey Simonenko <simon at comsys.ntu-kpi.kiev.ua>
Modified:
stable/9/tools/regression/sockets/unix_cmsg/README
stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c
stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.t
Directory Properties:
stable/9/tools/regression/sockets/ (props changed)
Modified: stable/9/tools/regression/sockets/unix_cmsg/README
==============================================================================
--- stable/9/tools/regression/sockets/unix_cmsg/README Mon Apr 29 21:12:25 2013 (r250075)
+++ stable/9/tools/regression/sockets/unix_cmsg/README Mon Apr 29 21:30:04 2013 (r250076)
@@ -1,127 +1,160 @@
$FreeBSD$
About unix_cmsg
-================
+===============
-This program is a collection of regression tests for ancillary (control)
-data for PF_LOCAL sockets (local domain or Unix domain sockets). There
-are tests for stream and datagram sockets.
-
-Usually each test does following steps: create Server, fork Client,
-Client sends something to Server, Server verifies if everything
-is correct in received message. Sometimes Client sends several
-messages to Server.
+This program is a collection of regression tests for ancillary data
+(control information) for PF_LOCAL sockets (local domain or Unix domain
+sockets). There are tests for stream and datagram sockets.
+
+Usually each test does following steps: creates Server, forks Client,
+Client sends something to Server, Server verifies whether everything is
+correct in received message(s).
It is better to change the owner of unix_cmsg to some safe user
-(eg. nobody:nogroup) and set SUID and SGID bits, else some tests
-can give correct results for wrong implementation.
+(eg. nobody:nogroup) and set SUID and SGID bits, else some tests that
+check credentials can give correct results for wrong implementation.
+
+It is better to run this program by a user that belongs to more
+than 16 groups.
Available options
=================
--d Output debugging information, values of different fields of
- received messages, etc. Will produce many lines of information.
-
--h Output help message and exit.
-
--t <socktype>
- Run tests only for the given socket type: "stream" or "dgram".
- With this option it is possible to run only particular test,
- not all of them.
-
--z Do not send real control data if possible. Struct cmsghdr{}
- should be followed by real control data. It is not clear if
- a sender should give control data in all cases (this is not
- documented and an arbitrary application can choose anything).
-
- At least for PF_LOCAL sockets' control messages with types
- SCM_CREDS and SCM_TIMESTAMP the kernel does not need any
- control data. This option allow to not send real control data
- for SCM_CREDS and SCM_TIMESTAMP control messages.
+usage: unix_cmsg [-dh] [-n num] [-s size] [-t type] [-z value] [testno]
-Description of tests
-====================
+ Options are:
+ -d Output debugging information
+ -h Output the help message and exit
+ -n num Number of messages to send
+ -s size Specify size of data for IPC
+ -t type Specify socket type (stream, dgram) for tests
+ -z value Do not send data in a message (bit 0x1), do not send
+ data array associated with a cmsghdr structure (bit 0x2)
+ testno Run one test by its number (require the -t option)
+
+Description
+===========
+
+If Client sends something to Server, then it sends 5 messages by default.
+Number of messages can be changed in the -n command line option. Number
+of messages will be given as N in the following descriptions.
+
+If Client sends something to Server, then it sends some data (few bytes)
+in each message by default. The size of this data can be changed by the -s
+command line option. The "-s 0" command line option means, that Client will
+send zero bytes represented by { NULL, 0 } value of struct iovec{}, referenced
+by the msg_iov field from struct msghdr{}. The "-z 1" or "-z 3" command line
+option means, that Client will send zero bytes represented by the NULL value
+in the msg_iov field from struct msghdr{}.
+
+If Client sends some ancillary data object, then this ancillary data object
+always has associated data array by default. The "-z 2" or "-z 3" option
+means, that Client will not send associated data array if possible.
For SOCK_STREAM sockets:
-----------------------
1: Sending, receiving cmsgcred
- Client connects to Server and sends two messages with data and
- control message with SCM_CREDS type to Server. Server should
- receive two messages, in both messages there should be data and
- control message with SCM_CREDS type followed by struct cmsgcred{}
- and this structure should contain correct information.
-
- 2: Receiving sockcred (listening socket has LOCAL_CREDS)
-
- Server creates listen socket and set socket option LOCAL_CREDS
- for it. Client connects to Server and sends two messages with data
- to Server. Server should receive two messages, in first message
- there should be data and control message with SCM_CREDS type followed
- by struct sockcred{} and this structure should contain correct
- information, in second message there should be data and no control
- message.
-
- 3: Receiving sockcred (accepted socket has LOCAL_CREDS)
-
- Client connects to Server and sends two messages with data. Server
- accepts connection and set socket option LOCAL_CREDS for just accepted
- socket (here synchronization is used, to allow Client to see just set
- flag on Server's socket before sending messages to Server). Server
- should receive two messages, in first message there should be data and
- control message with SOCK_CRED type followed by struct sockcred{} and
- this structure should contain correct information, in second message
- there should be data and no control message.
+ Client connects to Server and sends N messages with SCM_CREDS ancillary
+ data object. Server should receive N messages, each message should
+ have SCM_CREDS ancillary data object followed by struct cmsgcred{}.
+
+ 2: Receiving sockcred (listening socket)
+
+ Server creates a listening stream socket and sets the LOCAL_CREDS
+ socket option for it. Client connects to Server two times, each time
+ it sends N messages. Server accepts two connections and receives N
+ messages from each connection. The first message from each connection
+ should have SCM_CREDS ancillary data object followed by struct sockcred{},
+ next messages from the same connection should not have ancillary data.
+
+ 3: Receiving sockcred (accepted socket)
+
+ Client connects to Server. Server accepts connection and sets the
+ LOCAL_CREDS socket option for just accepted socket. Client sends N
+ messages to Server. Server should receive N messages, the first
+ message should have SCM_CREDS ancillary data object followed by
+ struct sockcred{}, next messages should not have ancillary data.
4: Sending cmsgcred, receiving sockcred
- Server creates listen socket and set socket option LOCAL_CREDS
- for it. Client connects to Server and sends one message with data
- and control message with SCM_CREDS type to Server. Server should
- receive one message with data and control message with SCM_CREDS type
- followed by struct sockcred{} and this structure should contain
- correct information.
-
- 5: Sending, receiving timestamp
-
- Client connects to Server and sends message with data and control
- message with SCM_TIMESTAMP type to Server. Server should receive
- message with data and control message with SCM_TIMESTAMP type
- followed by struct timeval{}.
+ Server creates a listening stream socket and sets the LOCAL_CREDS
+ socket option for it. Client connects to Server and sends N messages
+ with SCM_CREDS ancillary data object. Server should receive N messages,
+ the first message should have SCM_CREDS ancillary data object followed
+ by struct sockcred{}, each of next messages should have SCM_CREDS
+ ancillary data object followed by struct cmsgcred{}.
+
+ 5: Sending, receiving timeval
+
+ Client connects to Server and sends message with SCM_TIMESTAMP ancillary
+ data object. Server should receive one message with SCM_TIMESTAMP
+ ancillary data object followed by struct timeval{}.
+
+ 6: Sending, receiving bintime
+
+ Client connects to Server and sends message with SCM_BINTIME ancillary
+ data object. Server should receive one message with SCM_BINTIME
+ ancillary data object followed by struct bintime{}.
+
+ 7: Checking cmsghdr.cmsg_len
+
+ Client connects to Server and tries to send several messages with
+ SCM_CREDS ancillary data object that has wrong cmsg_len field in its
+ struct cmsghdr{}. All these attempts should fail, since cmsg_len
+ in all requests is less than CMSG_LEN(0).
+
+ 8: Check LOCAL_PEERCRED socket option
+
+ This test does not use ancillary data, but can be implemented here.
+ Client connects to Server. Both Client and Server verify that
+ credentials of the peer are correct using LOCAL_PEERCRED socket option.
For SOCK_DGRAM sockets:
----------------------
1: Sending, receiving cmsgcred
- Client sends to Server two messages with data and control message
- with SCM_CREDS type to Server. Server should receive two messages,
- in both messages there should be data and control message with
- SCM_CREDS type followed by struct cmsgcred{} and this structure
- should contain correct information.
+ Client connects to Server and sends N messages with SCM_CREDS ancillary
+ data object. Server should receive N messages, each message should
+ have SCM_CREDS ancillary data object followed by struct cmsgcred{}.
2: Receiving sockcred
- Server creates datagram socket and set socket option LOCAL_CREDS
- for it. Client sends two messages with data to Server. Server should
- receive two messages, in both messages there should be data and control
- message with SCM_CREDS type followed by struct sockcred{} and this
- structure should contain correct information.
+ Server creates datagram socket and sets the LOCAL_CREDS socket option
+ for it. Client sends N messages to Server. Server should receive N
+ messages, each message should have SCM_CREDS ancillary data object
+ followed by struct sockcred{}.
3: Sending cmsgcred, receiving sockcred
-
- Server creates datagram socket and set socket option LOCAL_CREDS
- for it. Client sends one message with data and control message with
- SOCK_CREDS type to Server. Server should receive one message with
- data and control message with SCM_CREDS type followed by struct
- sockcred{} and this structure should contain correct information.
-
- 4: Sending, receiving timestamp
-
- Client sends message with data and control message with SCM_TIMESTAMP
- type to Server. Server should receive message with data and control
- message with SCM_TIMESTAMP type followed by struct timeval{}.
+
+ Server creates datagram socket and sets the LOCAL_CREDS socket option
+ for it. Client sends N messages with SCM_CREDS ancillary data object
+ to Server. Server should receive N messages, the first message should
+ have SCM_CREDS ancillary data object followed by struct sockcred{},
+ each of next messages should have SCM_CREDS ancillary data object
+ followed by struct cmsgcred{}.
+
+ 4: Sending, receiving timeval
+
+ Client sends one message with SCM_TIMESTAMP ancillary data object
+ to Server. Server should receive one message with SCM_TIMESTAMP
+ ancillary data object followed by struct timeval{}.
+
+ 5: Sending, receiving bintime
+
+ Client sends one message with SCM_BINTIME ancillary data object
+ to Server. Server should receive one message with SCM_BINTIME
+ ancillary data object followed by struct bintime{}.
+
+ 6: Checking cmsghdr.cmsg_len
+
+ Client tries to send Server several messages with SCM_CREDS ancillary
+ data object that has wrong cmsg_len field in its struct cmsghdr{}.
+ All these attempts should fail, since cmsg_len in all requests is less
+ than CMSG_LEN(0).
- Andrey Simonenko
-simon at comsys.ntu-kpi.kiev.ua
+andreysimonenko at users.sourceforge.net
Modified: stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c
==============================================================================
--- stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c Mon Apr 29 21:12:25 2013 (r250075)
+++ stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c Mon Apr 29 21:30:04 2013 (r250076)
@@ -27,48 +27,46 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/resource.h>
#include <sys/time.h>
+#include <sys/select.h>
#include <sys/socket.h>
+#include <sys/ucred.h>
#include <sys/un.h>
#include <sys/wait.h>
-#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
-#include <setjmp.h>
+#include <paths.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <unistd.h>
/*
* There are tables with tests descriptions and pointers to test
* functions. Each t_*() function returns 0 if its test passed,
- * -1 if its test failed (something wrong was found in local domain
- * control messages), -2 if some system error occurred. If test
- * function returns -2, then a program exits.
+ * -1 if its test failed, -2 if some system error occurred.
+ * If a test function returns -2, then a program exits.
*
- * Each test function completely control what to do (eg. fork or
- * do not fork a client process). If a test function forks a client
- * process, then it waits for its termination. If a return code of a
- * client process is not equal to zero, or if a client process was
- * terminated by a signal, then test function returns -2.
+ * If a test function forks a client process, then it waits for its
+ * termination. If a return code of a client process is not equal
+ * to zero, or if a client process was terminated by a signal, then
+ * a test function returns -1 or -2 depending on exit status of
+ * a client process.
*
- * Each test function and complete program are not optimized
- * a lot to allow easy to modify tests.
- *
- * Each function which can block, is run under TIMEOUT, if timeout
- * occurs, then test function returns -2 or a client process exits
- * with nonzero return code.
+ * Each function which can block, is run under TIMEOUT. If timeout
+ * occurs, then a test function returns -2 or a client process exits
+ * with a non-zero return code.
*/
#ifndef LISTENQ
@@ -76,207 +74,290 @@ __FBSDID("$FreeBSD$");
#endif
#ifndef TIMEOUT
-# define TIMEOUT 60
+# define TIMEOUT 2
#endif
-#define EXTRA_CMSG_SPACE 512 /* Memory for not expected control data. */
-
-static int t_cmsgcred(void), t_sockcred_stream1(void);
-static int t_sockcred_stream2(void), t_cmsgcred_sockcred(void);
-static int t_sockcred_dgram(void), t_timestamp(void);
+static int t_cmsgcred(void);
+static int t_sockcred_1(void);
+static int t_sockcred_2(void);
+static int t_cmsgcred_sockcred(void);
+static int t_timeval(void);
+static int t_bintime(void);
+static int t_cmsg_len(void);
+static int t_peercred(void);
struct test_func {
- int (*func)(void); /* Pointer to function. */
- const char *desc; /* Test description. */
-};
-
-static struct test_func test_stream_tbl[] = {
- { NULL, " 0: All tests" },
- { t_cmsgcred, " 1: Sending, receiving cmsgcred" },
- { t_sockcred_stream1, " 2: Receiving sockcred (listening socket has LOCAL_CREDS)" },
- { t_sockcred_stream2, " 3: Receiving sockcred (accepted socket has LOCAL_CREDS)" },
- { t_cmsgcred_sockcred, " 4: Sending cmsgcred, receiving sockcred" },
- { t_timestamp, " 5: Sending, receiving timestamp" },
- { NULL, NULL }
+ int (*func)(void);
+ const char *desc;
};
-static struct test_func test_dgram_tbl[] = {
- { NULL, " 0: All tests" },
- { t_cmsgcred, " 1: Sending, receiving cmsgcred" },
- { t_sockcred_dgram, " 2: Receiving sockcred" },
- { t_cmsgcred_sockcred, " 3: Sending cmsgcred, receiving sockcred" },
- { t_timestamp, " 4: Sending, receiving timestamp" },
- { NULL, NULL }
+static const struct test_func test_stream_tbl[] = {
+ {
+ .func = NULL,
+ .desc = "All tests"
+ },
+ {
+ .func = t_cmsgcred,
+ .desc = "Sending, receiving cmsgcred"
+ },
+ {
+ .func = t_sockcred_1,
+ .desc = "Receiving sockcred (listening socket)"
+ },
+ {
+ .func = t_sockcred_2,
+ .desc = "Receiving sockcred (accepted socket)"
+ },
+ {
+ .func = t_cmsgcred_sockcred,
+ .desc = "Sending cmsgcred, receiving sockcred"
+ },
+ {
+ .func = t_timeval,
+ .desc = "Sending, receiving timeval"
+ },
+ {
+ .func = t_bintime,
+ .desc = "Sending, receiving bintime"
+ },
+ {
+ .func = t_cmsg_len,
+ .desc = "Check cmsghdr.cmsg_len"
+ },
+ {
+ .func = t_peercred,
+ .desc = "Check LOCAL_PEERCRED socket option"
+ }
};
-#define TEST_STREAM_NO_MAX (sizeof(test_stream_tbl) / sizeof(struct test_func) - 2)
-#define TEST_DGRAM_NO_MAX (sizeof(test_dgram_tbl) / sizeof(struct test_func) - 2)
-
-static const char *myname = "SERVER"; /* "SERVER" or "CLIENT" */
-
-static int debug = 0; /* 1, if -d. */
-static int no_control_data = 0; /* 1, if -z. */
-
-static u_int nfailed = 0; /* Number of failed tests. */
+#define TEST_STREAM_TBL_SIZE \
+ (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
-static int sock_type; /* SOCK_STREAM or SOCK_DGRAM */
-static const char *sock_type_str; /* "SOCK_STREAM" or "SOCK_DGRAN" */
-
-static char tempdir[] = "/tmp/unix_cmsg.XXXXXXX";
-static char serv_sock_path[PATH_MAX];
-
-static char ipc_message[] = "hello";
-
-#define IPC_MESSAGE_SIZE (sizeof(ipc_message))
-
-static struct sockaddr_un servaddr; /* Server address. */
-
-static sigjmp_buf env_alrm;
+static const struct test_func test_dgram_tbl[] = {
+ {
+ .func = NULL,
+ .desc = "All tests"
+ },
+ {
+ .func = t_cmsgcred,
+ .desc = "Sending, receiving cmsgcred"
+ },
+ {
+ .func = t_sockcred_2,
+ .desc = "Receiving sockcred"
+ },
+ {
+ .func = t_cmsgcred_sockcred,
+ .desc = "Sending cmsgcred, receiving sockcred"
+ },
+ {
+ .func = t_timeval,
+ .desc = "Sending, receiving timeval"
+ },
+ {
+ .func = t_bintime,
+ .desc = "Sending, receiving bintime"
+ },
+ {
+ .func = t_cmsg_len,
+ .desc = "Check cmsghdr.cmsg_len"
+ }
+};
-static uid_t my_uid;
-static uid_t my_euid;
-static gid_t my_gid;
-static gid_t my_egid;
+#define TEST_DGRAM_TBL_SIZE \
+ (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
-/*
- * my_gids[0] is EGID, next items are supplementary GIDs,
- * my_ngids determines valid items in my_gids array.
- */
-static gid_t my_gids[NGROUPS_MAX];
-static int my_ngids;
+static bool debug = false;
+static bool server_flag = true;
+static bool send_data_flag = true;
+static bool send_array_flag = true;
+static bool failed_flag = false;
+
+static int sock_type;
+static const char *sock_type_str;
+
+static const char *proc_name;
+
+static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
+static int serv_sock_fd;
+static struct sockaddr_un serv_addr_sun;
+
+static struct {
+ char *buf_send;
+ char *buf_recv;
+ size_t buf_size;
+ u_int msg_num;
+} ipc_msg;
+
+#define IPC_MSG_NUM_DEF 5
+#define IPC_MSG_NUM_MAX 10
+#define IPC_MSG_SIZE_DEF 7
+#define IPC_MSG_SIZE_MAX 128
+
+static struct {
+ uid_t uid;
+ uid_t euid;
+ gid_t gid;
+ gid_t egid;
+ gid_t *gid_arr;
+ int gid_num;
+} proc_cred;
+
+static pid_t client_pid;
+
+#define SYNC_SERVER 0
+#define SYNC_CLIENT 1
+#define SYNC_RECV 0
+#define SYNC_SEND 1
-static pid_t client_pid; /* PID of forked client. */
+static int sync_fd[2][2];
-#define dbgmsg(x) do { \
- if (debug) \
- logmsgx x ; \
-} while (/* CONSTCOND */0)
+#define LOGMSG_SIZE 128
static void logmsg(const char *, ...) __printflike(1, 2);
static void logmsgx(const char *, ...) __printflike(1, 2);
+static void dbgmsg(const char *, ...) __printflike(1, 2);
static void output(const char *, ...) __printflike(1, 2);
-extern char *__progname; /* The name of program. */
-
-/*
- * Output the help message (-h switch).
- */
static void
-usage(int quick)
+usage(bool verbose)
{
- const struct test_func *test_func;
+ u_int i;
- fprintf(stderr, "Usage: %s [-dhz] [-t <socktype>] [testno]\n",
- __progname);
- if (quick)
+ printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
+ "[-z value] [testno]\n", getprogname());
+ if (!verbose)
return;
- fprintf(stderr, "\n Options are:\n\
- -d\t\t\tOutput debugging information\n\
- -h\t\t\tOutput this help message and exit\n\
- -t <socktype>\t\tRun test only for the given socket type:\n\
-\t\t\tstream or dgram\n\
- -z\t\t\tDo not send real control data if possible\n\n");
- fprintf(stderr, " Available tests for stream sockets:\n");
- for (test_func = test_stream_tbl; test_func->desc != NULL; ++test_func)
- fprintf(stderr, " %s\n", test_func->desc);
- fprintf(stderr, "\n Available tests for datagram sockets:\n");
- for (test_func = test_dgram_tbl; test_func->desc != NULL; ++test_func)
- fprintf(stderr, " %s\n", test_func->desc);
+ printf("\n Options are:\n\
+ -d Output debugging information\n\
+ -h Output the help message and exit\n\
+ -n num Number of messages to send\n\
+ -s size Specify size of data for IPC\n\
+ -t type Specify socket type (stream, dgram) for tests\n\
+ -z value Do not send data in a message (bit 0x1), do not send\n\
+ data array associated with a cmsghdr structure (bit 0x2)\n\
+ testno Run one test by its number (require the -t option)\n\n");
+ printf(" Available tests for stream sockets:\n");
+ for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
+ printf(" %u: %s\n", i, test_stream_tbl[i].desc);
+ printf("\n Available tests for datagram sockets:\n");
+ for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
+ printf(" %u: %s\n", i, test_dgram_tbl[i].desc);
}
-/*
- * printf-like function for outputting to STDOUT_FILENO.
- */
static void
output(const char *format, ...)
{
- char buf[128];
+ char buf[LOGMSG_SIZE];
va_list ap;
va_start(ap, format);
if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
- err(EX_SOFTWARE, "output: vsnprintf failed");
+ err(EXIT_FAILURE, "output: vsnprintf failed");
write(STDOUT_FILENO, buf, strlen(buf));
va_end(ap);
}
-/*
- * printf-like function for logging, also outputs message for errno.
- */
static void
logmsg(const char *format, ...)
{
- char buf[128];
+ char buf[LOGMSG_SIZE];
va_list ap;
int errno_save;
- errno_save = errno; /* Save errno. */
-
+ errno_save = errno;
va_start(ap, format);
if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
- err(EX_SOFTWARE, "logmsg: vsnprintf failed");
+ err(EXIT_FAILURE, "logmsg: vsnprintf failed");
if (errno_save == 0)
- output("%s: %s\n", myname, buf);
+ output("%s: %s\n", proc_name, buf);
else
- output("%s: %s: %s\n", myname, buf, strerror(errno_save));
+ output("%s: %s: %s\n", proc_name, buf, strerror(errno_save));
va_end(ap);
+ errno = errno_save;
+}
+
+static void
+vlogmsgx(const char *format, va_list ap)
+{
+ char buf[LOGMSG_SIZE];
+
+ if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
+ err(EXIT_FAILURE, "logmsgx: vsnprintf failed");
+ output("%s: %s\n", proc_name, buf);
- errno = errno_save; /* Restore errno. */
}
-/*
- * printf-like function for logging, do not output message for errno.
- */
static void
logmsgx(const char *format, ...)
{
- char buf[128];
va_list ap;
va_start(ap, format);
- if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
- err(EX_SOFTWARE, "logmsgx: vsnprintf failed");
- output("%s: %s\n", myname, buf);
+ vlogmsgx(format, ap);
va_end(ap);
}
-/*
- * Run tests from testno1 to testno2.
- */
+static void
+dbgmsg(const char *format, ...)
+{
+ va_list ap;
+
+ if (debug) {
+ va_start(ap, format);
+ vlogmsgx(format, ap);
+ va_end(ap);
+ }
+}
+
static int
-run_tests(u_int testno1, u_int testno2)
+run_tests(int type, u_int testno1)
{
- const struct test_func *test_func;
- u_int i, nfailed1;
+ const struct test_func *tf;
+ u_int i, testno2, failed_num;
- output("Running tests for %s sockets:\n", sock_type_str);
- test_func = (sock_type == SOCK_STREAM ?
- test_stream_tbl : test_dgram_tbl) + testno1;
+ sock_type = type;
+ if (type == SOCK_STREAM) {
+ sock_type_str = "SOCK_STREAM";
+ tf = test_stream_tbl;
+ i = TEST_STREAM_TBL_SIZE - 1;
+ } else {
+ sock_type_str = "SOCK_DGRAM";
+ tf = test_dgram_tbl;
+ i = TEST_DGRAM_TBL_SIZE - 1;
+ }
+ if (testno1 == 0) {
+ testno1 = 1;
+ testno2 = i;
+ } else
+ testno2 = testno1;
- nfailed1 = 0;
- for (i = testno1; i <= testno2; ++test_func, ++i) {
- output(" %s\n", test_func->desc);
- switch (test_func->func()) {
+ output("Running tests for %s sockets:\n", sock_type_str);
+ failed_num = 0;
+ for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
+ output(" %u: %s\n", i, tf->desc);
+ switch (tf->func()) {
case -1:
- ++nfailed1;
+ ++failed_num;
break;
case -2:
- logmsgx("some system error occurred, exiting");
+ logmsgx("some system error or timeout occurred");
return (-1);
}
}
- nfailed += nfailed1;
+ if (failed_num != 0)
+ failed_flag = true;
if (testno1 != testno2) {
- if (nfailed1 == 0)
- output("-- all tests were passed!\n");
+ if (failed_num == 0)
+ output("-- all tests passed!\n");
else
- output("-- %u test%s failed!\n", nfailed1,
- nfailed1 == 1 ? "" : "s");
+ output("-- %u test%s failed!\n",
+ failed_num, failed_num == 1 ? "" : "s");
} else {
- if (nfailed == 0)
- output("-- test was passed!\n");
+ if (failed_num == 0)
+ output("-- test passed!\n");
else
output("-- test failed!\n");
}
@@ -284,183 +365,322 @@ run_tests(u_int testno1, u_int testno2)
return (0);
}
-/* ARGSUSED */
-static void
-sig_alrm(int signo __unused)
+static int
+init(void)
+{
+ struct sigaction sigact;
+ size_t idx;
+ int rv;
+
+ proc_name = "SERVER";
+
+ sigact.sa_handler = SIG_IGN;
+ sigact.sa_flags = 0;
+ sigemptyset(&sigact.sa_mask);
+ if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
+ logmsg("init: sigaction");
+ return (-1);
+ }
+
+ if (ipc_msg.buf_size == 0)
+ ipc_msg.buf_send = ipc_msg.buf_recv = NULL;
+ else {
+ ipc_msg.buf_send = malloc(ipc_msg.buf_size);
+ ipc_msg.buf_recv = malloc(ipc_msg.buf_size);
+ if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) {
+ logmsg("init: malloc");
+ return (-1);
+ }
+ for (idx = 0; idx < ipc_msg.buf_size; ++idx)
+ ipc_msg.buf_send[idx] = (char)idx;
+ }
+
+ proc_cred.uid = getuid();
+ proc_cred.euid = geteuid();
+ proc_cred.gid = getgid();
+ proc_cred.egid = getegid();
+ proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
+ if (proc_cred.gid_num < 0) {
+ logmsg("init: getgroups");
+ return (-1);
+ }
+ proc_cred.gid_arr = malloc(proc_cred.gid_num *
+ sizeof(*proc_cred.gid_arr));
+ if (proc_cred.gid_arr == NULL) {
+ logmsg("init: malloc");
+ return (-1);
+ }
+ if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) {
+ logmsg("init: getgroups");
+ return (-1);
+ }
+
+ memset(&serv_addr_sun, 0, sizeof(serv_addr_sun));
+ rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path),
+ "%s/%s", work_dir, proc_name);
+ if (rv < 0) {
+ logmsg("init: snprintf");
+ return (-1);
+ }
+ if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) {
+ logmsgx("init: not enough space for socket pathname");
+ return (-1);
+ }
+ serv_addr_sun.sun_family = PF_LOCAL;
+ serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun);
+
+ return (0);
+}
+
+static int
+client_fork(void)
{
- siglongjmp(env_alrm, 1);
+ int fd1, fd2;
+
+ if (pipe(sync_fd[SYNC_SERVER]) < 0 ||
+ pipe(sync_fd[SYNC_CLIENT]) < 0) {
+ logmsg("client_fork: pipe");
+ return (-1);
+ }
+ client_pid = fork();
+ if (client_pid == (pid_t)-1) {
+ logmsg("client_fork: fork");
+ return (-1);
+ }
+ if (client_pid == 0) {
+ proc_name = "CLIENT";
+ server_flag = false;
+ fd1 = sync_fd[SYNC_SERVER][SYNC_RECV];
+ fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND];
+ } else {
+ fd1 = sync_fd[SYNC_SERVER][SYNC_SEND];
+ fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV];
+ }
+ if (close(fd1) < 0 || close(fd2) < 0) {
+ logmsg("client_fork: close");
+ return (-1);
+ }
+ return (client_pid != 0);
}
-/*
- * Initialize signals handlers.
- */
static void
-sig_init(void)
+client_exit(int rv)
+{
+ if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
+ close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
+ logmsg("client_exit: close");
+ rv = -1;
+ }
+ rv = rv == 0 ? EXIT_SUCCESS : -rv;
+ dbgmsg("exit: code %d", rv);
+ _exit(rv);
+}
+
+static int
+client_wait(void)
{
- struct sigaction sa;
+ int status;
+ pid_t pid;
- sa.sa_handler = SIG_IGN;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0)
- err(EX_OSERR, "sigaction(SIGPIPE)");
-
- sa.sa_handler = sig_alrm;
- if (sigaction(SIGALRM, &sa, (struct sigaction *)NULL) < 0)
- err(EX_OSERR, "sigaction(SIGALRM)");
+ dbgmsg("waiting for client");
+
+ if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
+ close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
+ logmsg("client_wait: close");
+ return (-1);
+ }
+
+ pid = waitpid(client_pid, &status, 0);
+ if (pid == (pid_t)-1) {
+ logmsg("client_wait: waitpid");
+ return (-1);
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != EXIT_SUCCESS) {
+ logmsgx("client exit status is %d",
+ WEXITSTATUS(status));
+ return (-WEXITSTATUS(status));
+ }
+ } else {
+ if (WIFSIGNALED(status))
+ logmsgx("abnormal termination of client, signal %d%s",
+ WTERMSIG(status), WCOREDUMP(status) ?
+ " (core file generated)" : "");
+ else
+ logmsgx("termination of client, unknown status");
+ return (-1);
+ }
+
+ return (0);
}
int
main(int argc, char *argv[])
{
const char *errstr;
- int opt, dgramflag, streamflag;
- u_int testno1, testno2;
-
- dgramflag = streamflag = 0;
- while ((opt = getopt(argc, argv, "dht:z")) != -1)
+ u_int testno, zvalue;
+ int opt, rv;
+ bool dgram_flag, stream_flag;
+
+ ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
+ ipc_msg.msg_num = IPC_MSG_NUM_DEF;
+ dgram_flag = stream_flag = false;
+ while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
switch (opt) {
case 'd':
- debug = 1;
+ debug = true;
break;
case 'h':
- usage(0);
- return (EX_OK);
+ usage(true);
+ return (EXIT_SUCCESS);
+ case 'n':
+ ipc_msg.msg_num = strtonum(optarg, 1,
+ IPC_MSG_NUM_MAX, &errstr);
+ if (errstr != NULL)
+ errx(EXIT_FAILURE, "option -n: number is %s",
+ errstr);
+ break;
+ case 's':
+ ipc_msg.buf_size = strtonum(optarg, 0,
+ IPC_MSG_SIZE_MAX, &errstr);
+ if (errstr != NULL)
+ errx(EXIT_FAILURE, "option -s: number is %s",
+ errstr);
+ break;
case 't':
if (strcmp(optarg, "stream") == 0)
- streamflag = 1;
+ stream_flag = true;
else if (strcmp(optarg, "dgram") == 0)
- dgramflag = 1;
+ dgram_flag = true;
else
- errx(EX_USAGE, "wrong socket type in -t option");
+ errx(EXIT_FAILURE, "option -t: "
+ "wrong socket type");
break;
case 'z':
- no_control_data = 1;
+ zvalue = strtonum(optarg, 0, 3, &errstr);
+ if (errstr != NULL)
+ errx(EXIT_FAILURE, "option -z: number is %s",
+ errstr);
+ if (zvalue & 0x1)
+ send_data_flag = false;
+ if (zvalue & 0x2)
+ send_array_flag = false;
break;
- case '?':
default:
- usage(1);
- return (EX_USAGE);
+ usage(false);
+ return (EXIT_FAILURE);
}
if (optind < argc) {
if (optind + 1 != argc)
- errx(EX_USAGE, "too many arguments");
- testno1 = strtonum(argv[optind], 0, UINT_MAX, &errstr);
+ errx(EXIT_FAILURE, "too many arguments");
+ testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
if (errstr != NULL)
- errx(EX_USAGE, "wrong test number: %s", errstr);
+ errx(EXIT_FAILURE, "test number is %s", errstr);
+ if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
+ errx(EXIT_FAILURE, "given test %u for stream "
+ "sockets does not exist", testno);
+ if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-9
mailing list