tests: add a test for decoding and dumping of recvmmsg/sendmmsg

* configure (AC_CHECK_FUNCS): Add sendmmsg.
* tests/mmsg.c: New file.
* tests/mmsg.expected: New file.
* tests/mmsg.test: New test.
* tests/.gitignore: Add mmsg.
* tests/Makefile.am (CHECK_PROGRAMS): Add mmsg.
(TESTS): Add mmsg.test.
(EXTRA_DIST): Add mmsg.expected.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
Signed-off-by: Dmitry V. Levin <ldv@altlinux.org>
diff --git a/tests/mmsg.c b/tests/mmsg.c
new file mode 100644
index 0000000..496111b
--- /dev/null
+++ b/tests/mmsg.c
@@ -0,0 +1,74 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+int
+main(void)
+{
+#if defined(HAVE_SENDMMSG) && defined(HAVE_STRUCT_MMSGHDR)
+	const int R = 0, W = 1;
+	int fd;
+	int sv[2];
+	char one[] = "one";
+	char two[] = "two";
+	char three[] = "three";
+
+	struct iovec iov[] = {
+		{
+			.iov_base = one,
+			.iov_len = sizeof(one) - 1
+		}, {
+			.iov_base = two,
+			.iov_len = sizeof(two) - 1
+		}, {
+			.iov_base = three,
+			.iov_len = sizeof(three) - 1
+		}
+	};
+
+	struct mmsghdr mmh[] = {
+		{
+			.msg_hdr = {
+				.msg_iov = iov + 0,
+				.msg_iovlen = 2,
+			}
+		}, {
+			.msg_hdr = {
+				.msg_iov = iov + 2,
+				.msg_iovlen = 1,
+			}
+		}
+	};
+#define n_mmh (sizeof(mmh)/sizeof(mmh[0]))
+
+	/*
+	 * Following open/dup2/close calls make the output of strace
+	 * more predictable, so we can just compare the output and
+	 * expected output (mmsg.expected) for testing purposes.
+	 */
+	while ((fd = open("/dev/null", O_RDWR)) < 3)
+		assert(fd >= 0);
+	(void) close(3);
+
+	assert(socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) == 0);
+
+	assert(dup2(sv[W], W) == W);
+	assert(close(sv[W]) == 0);
+	assert(dup2(sv[R], R) == R);
+	assert(close(sv[R]) == 0);
+
+	assert(sendmmsg(W, mmh, n_mmh, 0) == n_mmh);
+	assert(close(W) == 0);
+
+	assert(recvmmsg(R, mmh, n_mmh, 0, NULL) == n_mmh);
+	assert(close(R) == 0);
+
+	return 0;
+#else
+	return 77;
+#endif
+}