./usr/tests/minix-posix/test78 minix-sys
./usr/tests/minix-posix/test79 minix-sys
./usr/tests/minix-posix/test8 minix-sys
+./usr/tests/minix-posix/test80 minix-sys
+./usr/tests/minix-posix/test81 minix-sys
./usr/tests/minix-posix/test9 minix-sys
./usr/tests/minix-posix/testinterp minix-sys
./usr/tests/minix-posix/testisofs minix-sys
# Some have an extra file
OBJS.test57= test57loop.o
+OBJS.test56+= common-socket.o
+OBJS.test80+= common-socket.o
+OBJS.test81+= common-socket.o
# Cache testing programs
OBJS.test71+= testcache.o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
-61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
+61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
+81
.if ${MACHINE_ARCH} == "i386"
MINIX_TESTS+= \
--- /dev/null
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "common-socket.h"
+
+#define ISO8601_FORMAT "%Y-%m-%dT%H:%M:%S"
+
+/* timestamps for debug and error logs */
+static char *get_timestamp(void)
+{
+ struct tm *tm;
+ time_t t;
+ size_t len;
+ char *s;
+
+ len = sizeof(char) * 32;
+
+ t = time(NULL);
+ if (t == -1) {
+ return NULL;
+ }
+ tm = gmtime(&t);
+ if (tm == NULL) {
+ return NULL;
+ }
+
+ s = (char *) malloc(len);
+ if (!s) {
+ perror("malloc");
+ return NULL;
+ }
+ memset(s, '\0', len);
+
+ strftime(s, len - 1, ISO8601_FORMAT, tm);
+ return s;
+}
+
+void test_fail_fl(char *msg, char *file, int line)
+{
+ char *timestamp;
+ timestamp = get_timestamp();
+ if (errct == 0) fprintf(stderr, "\n");
+ fprintf(stderr, "[ERROR][%s] (%s Line %d) %s [pid=%d:errno=%d:%s]\n",
+ timestamp, file, line, msg, getpid(),
+ errno, strerror(errno));
+ fflush(stderr);
+ if (timestamp != NULL) {
+ free(timestamp);
+ timestamp = NULL;
+ }
+ e(7);
+}
+
+#if DEBUG == 1
+void debug_fl(char *msg, char *file, int line)
+{
+ char *timestamp;
+ timestamp = get_timestamp();
+ fprintf(stdout,"[DEBUG][%s] (%s:%d) %s [pid=%d]\n",
+ timestamp, __FILE__, __LINE__, msg, getpid());
+ fflush(stdout);
+ if (timestamp != NULL) {
+ free(timestamp);
+ timestamp = NULL;
+ }
+}
+#endif
+
+void test_socket(const struct socket_test_info *info)
+{
+ struct stat statbuf, statbuf2;
+ int sd, sd2;
+ int rc;
+ int i;
+
+ debug("entering test_socket()");
+
+ debug("Test socket() with an unsupported address family");
+
+ errno = 0;
+ sd = socket(-1, info->type, 0);
+ if (!(sd == -1 && errno == EAFNOSUPPORT)) {
+ test_fail("socket");
+ if (sd != -1) {
+ CLOSE(sd);
+ }
+ }
+
+ debug("Test socket() with all available FDs open by this process");
+
+ for (i = 3; i < getdtablesize(); i++) {
+ rc = open("/dev/null", O_RDONLY);
+ if (rc == -1) {
+ test_fail("we couldn't open /dev/null for read");
+ }
+ }
+
+ errno = 0;
+ sd = socket(info->domain, info->type, 0);
+ if (!(sd == -1 && errno == EMFILE)) {
+ test_fail("socket() call with all fds open should fail");
+ if (sd != -1) {
+ CLOSE(sd);
+ }
+ }
+
+ for (i = 3; i < getdtablesize(); i++) {
+ CLOSE(i);
+ }
+
+ debug("Test socket() with an mismatched protocol");
+
+ errno = 0;
+ sd = socket(info->domain, info->type, 4);
+ if (!(sd == -1 && errno == EPROTONOSUPPORT)) {
+ test_fail("socket() should fail with errno = EPROTONOSUPPORT");
+ if (sd != -1) {
+ CLOSE(sd);
+ }
+ }
+
+ debug("Test socket() success");
+
+ /*
+ * open 2 sockets at once and *then* close them.
+ * This will test that /dev/uds is cloning properly.
+ */
+
+ SOCKET(sd, info->domain, info->type, 0);
+ SOCKET(sd2, info->domain, info->type, 0);
+
+ rc = fstat(sd, &statbuf);
+ if (rc == -1) {
+ test_fail("fstat failed on sd");
+ }
+
+ rc = fstat(sd2, &statbuf2);
+ if (rc == -1) {
+ test_fail("fstat failed on sd2");
+ }
+
+
+ if (statbuf.st_dev == statbuf2.st_dev) {
+ test_fail("/dev/uds isn't being cloned");
+ }
+
+ CLOSE(sd2);
+ CLOSE(sd);
+
+ debug("leaving test_socket()");
+}
+
+void test_getsockname(const struct socket_test_info *info)
+{
+ int sd;
+ int rc;
+ struct sockaddr_storage sock_addr;
+ socklen_t sock_addr_len;
+
+ SOCKET(sd, info->domain, info->type, 0);
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc == -1) {
+ test_fail("bind() should have worked");
+ }
+
+ debug("Test getsockname() success");
+
+ memset(&sock_addr, '\0', sizeof(sock_addr));
+ sock_addr_len = sizeof(sock_addr);
+
+ rc = getsockname(sd, (struct sockaddr *) &sock_addr, &sock_addr_len);
+ if (rc == -1) {
+ test_fail("getsockname() should have worked");
+ }
+
+ info->callback_check_sockaddr((struct sockaddr *) &sock_addr,
+ sock_addr_len, "getsockname", 1);
+
+ CLOSE(sd);
+}
+
+void test_bind(const struct socket_test_info *info)
+{
+ struct sockaddr_storage sock_addr;
+ socklen_t sock_addr_len;
+ int sd;
+ int sd2;
+ int rc;
+
+ debug("entering test_bind()");
+ info->callback_cleanup();
+
+ debug("Test bind() success");
+
+ SOCKET(sd, info->domain, info->type, 0);
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc == -1) {
+ test_fail("bind() should have worked");
+ }
+
+ debug("Test getsockname() success");
+
+ memset(&sock_addr, '\0', sizeof(sock_addr));
+ sock_addr_len = sizeof(sock_addr);
+
+ rc = getsockname(sd, (struct sockaddr *) &sock_addr, &sock_addr_len);
+ if (rc == -1) {
+ test_fail("getsockname() should have worked");
+ }
+
+ info->callback_check_sockaddr((struct sockaddr *) &sock_addr,
+ sock_addr_len, "getsockname", 1);
+
+ debug("Test bind() with a address that has already been bind()'d");
+
+ SOCKET(sd2, info->domain, info->type, 0);
+ errno = 0;
+ rc = bind(sd2, info->serveraddr, info->serveraddrlen);
+ if (!((rc == -1) && (errno == EADDRINUSE)) &&
+ !info->bug_bind_in_use) {
+ test_fail("bind() should have failed with EADDRINUSE");
+ }
+ CLOSE(sd2);
+ CLOSE(sd);
+ info->callback_cleanup();
+
+ if (!info->bug_bind_null) {
+ debug("Test bind() with a NULL address");
+
+ SOCKET(sd, info->domain, info->type, 0);
+ errno = 0;
+ rc = bind(sd, (struct sockaddr *) NULL,
+ sizeof(struct sockaddr_storage));
+ if (!((rc == -1) && (errno == EFAULT))) {
+ test_fail("bind() should have failed with EFAULT");
+ }
+ CLOSE(sd);
+ }
+
+ debug("leaving test_bind()");
+}
+
+void test_listen(const struct socket_test_info *info)
+{
+ int rc;
+
+ debug("entering test_listen()");
+
+ debug("Test listen() with a bad file descriptor");
+
+ errno = 0;
+ rc = listen(-1, 0);
+ if (!(rc == -1 && errno == EBADF)) {
+ test_fail("listen(-1, 0) should have failed");
+ }
+
+ debug("Test listen() with a non-socket file descriptor");
+
+ errno = 0;
+ rc = listen(0, 0);
+ /* Test on errno disabled here: there's currently no telling what this
+ * will return. POSIX says it should be ENOTSOCK, MINIX3 libc returns
+ * ENOSYS, and we used to test for ENOTTY here..
+ */
+ if (!(rc == -1)) {
+ test_fail("listen(0, 0) should have failed");
+ }
+
+ debug("leaving test_listen()");
+}
+
+void test_shutdown(const struct socket_test_info *info)
+{
+ int how[3] = { SHUT_RD, SHUT_WR, SHUT_RDWR };
+ int sd;
+ int rc;
+ int i;
+
+ debug("entering test_shutdown()");
+
+ /* test for each direction (read, write, read-write) */
+ for (i = 0; i < 3; i++) {
+
+ if (info->bug_shutdown_read && how[i] == SHUT_RD) continue;
+
+ debug("test shutdown() with an invalid descriptor");
+
+ errno = 0;
+ rc = shutdown(-1, how[i]);
+ if (!(rc == -1 && errno == EBADF) && !info->bug_shutdown) {
+ test_fail("shutdown(-1, how[i]) should have failed");
+ }
+
+ debug("test shutdown() with a non-socket descriptor");
+
+ errno = 0;
+ rc = shutdown(0, how[i]);
+ if (!(rc == -1 && errno == ENOSYS) && !info->bug_shutdown) {
+ test_fail("shutdown() should have failed with ENOSYS");
+ }
+
+ debug("test shutdown() with a socket that is not connected");
+
+ SOCKET(sd, info->domain, info->type, 0);
+ errno = 0;
+ rc = shutdown(sd, how[i]);
+ if (!(rc == -1 && errno == ENOTCONN) &&
+ !info->bug_shutdown_not_conn &&
+ !info->bug_shutdown) {
+ test_fail("shutdown() should have failed");
+ }
+ CLOSE(sd);
+ }
+
+ SOCKET(sd, info->domain, info->type, 0);
+ errno = 0;
+ rc = shutdown(sd, -1);
+ if (!(rc == -1 && errno == ENOTCONN) &&
+ !info->bug_shutdown_not_conn &&
+ !info->bug_shutdown) {
+ test_fail("shutdown(sd, -1) should have failed with ENOTCONN");
+ }
+ CLOSE(sd);
+
+ debug("leaving test_shutdown()");
+}
+
+void test_close(const struct socket_test_info *info)
+{
+ int sd, sd2;
+ int rc, i;
+
+ debug("entering test_close()");
+
+ info->callback_cleanup();
+
+ debug("Test close() success");
+
+ SOCKET(sd, info->domain, info->type, 0);
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc != 0) {
+ test_fail("bind() should have worked");
+ }
+
+ CLOSE(sd);
+
+ debug("Close an already closed file descriptor");
+
+ errno = 0;
+ rc = close(sd);
+ if (!(rc == -1 && errno == EBADF)) {
+ test_fail("close(sd) should have failed with EBADF");
+ }
+
+ info->callback_cleanup();
+
+ debug("dup()'ing a file descriptor and closing both should work");
+
+ SOCKET(sd, info->domain, info->type, 0);
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc != 0) {
+ test_fail("bind() should have worked");
+ }
+
+ errno = 0;
+ sd2 = dup(sd);
+ if (sd2 == -1) {
+ test_fail("dup(sd) should have worked");
+ } else {
+ CLOSE(sd2);
+ CLOSE(sd);
+ }
+
+ info->callback_cleanup();
+
+ /* Create and close a socket a bunch of times.
+ * If the implementation doesn't properly free the
+ * socket during close(), eventually socket() will
+ * fail when the internal descriptor table is full.
+ */
+ for (i = 0; i < 1024; i++) {
+ SOCKET(sd, info->domain, info->type, 0);
+ CLOSE(sd);
+ }
+
+ debug("leaving test_close()");
+}
+
+void test_sockopts(const struct socket_test_info *info)
+{
+ int i;
+ int rc;
+ int sd;
+ int option_value;
+ socklen_t option_len;
+
+ debug("entering test_sockopts()");
+
+ for (i = 0; i < info->typecount; i++) {
+
+ SOCKET(sd, info->domain, info->types[i], 0);
+
+ debug("Test setsockopt() works");
+
+ option_value = 0;
+ option_len = sizeof(option_value);
+ errno = 0;
+ rc = getsockopt(sd, SOL_SOCKET, SO_TYPE, &option_value,
+ &option_len);
+ if (rc != 0) {
+ test_fail("setsockopt() should have worked");
+ }
+
+ if (option_value != info->types[i]) {
+ test_fail("SO_TYPE didn't seem to work.");
+ }
+
+ CLOSE(sd);
+ }
+
+
+
+ SOCKET(sd, info->domain, info->type, 0);
+
+ debug("Test setsockopt() works");
+
+ option_value = 0;
+ option_len = sizeof(option_value);
+ errno = 0;
+ rc = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &option_value, &option_len);
+ if (rc != 0 && !info->bug_sockopt_sndbuf) {
+ test_fail("getsockopt() should have worked");
+ }
+
+ if (info->expected_sndbuf >= 0 &&
+ option_value != info->expected_sndbuf &&
+ !info->bug_sockopt_sndbuf) {
+ test_fail("SO_SNDBUF didn't seem to work.");
+ }
+
+ CLOSE(sd);
+
+
+ SOCKET(sd, info->domain, info->type, 0);
+
+ debug("Test setsockopt() works");
+
+ option_value = 0;
+ option_len = sizeof(option_value);
+ errno = 0;
+ rc = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &option_value, &option_len);
+ if (rc != 0 && !info->bug_sockopt_rcvbuf) {
+ test_fail("getsockopt() should have worked");
+ }
+
+ if (info->expected_rcvbuf >= 0 &&
+ option_value != info->expected_rcvbuf &&
+ !info->bug_sockopt_rcvbuf) {
+ test_fail("SO_RCVBUF didn't seem to work.");
+ }
+
+ CLOSE(sd);
+
+
+ debug("leaving test_sockopts()");
+}
+
+void test_read(const struct socket_test_info *info)
+{
+ int rc;
+ int fd;
+ char buf[BUFSIZE];
+
+ debug("entering test_read()");
+
+ errno = 0;
+ rc = read(-1, buf, sizeof(buf));
+ if (!(rc == -1 && errno == EBADF)) {
+ test_fail("read() should have failed with EBADF");
+ }
+
+ fd = open("/tmp", O_RDONLY);
+ if (fd == -1) {
+ test_fail("open(\"/tmp\", O_RDONLY) should have worked");
+ }
+
+ CLOSE(fd);
+
+ debug("leaving test_read()");
+}
+
+void test_write(const struct socket_test_info *info)
+{
+ int rc;
+ char buf[BUFSIZE];
+
+ debug("entering test_write()");
+
+ errno = 0;
+ rc = write(-1, buf, sizeof(buf));
+ if (!(rc == -1 && errno == EBADF)) {
+ test_fail("write() should have failed with EBADF");
+ }
+
+ debug("leaving test_write()");
+}
+
+void test_dup(const struct socket_test_info *info)
+{
+ struct stat info1;
+ struct stat info2;
+ int sd, sd2;
+ int rc;
+ int i;
+
+ debug("entering test_dup()");
+
+ info->callback_cleanup();
+
+ debug("Test dup()");
+
+ SOCKET(sd, info->domain, info->type, 0);
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc != 0) {
+ test_fail("bind() should have worked");
+ }
+
+ errno = 0;
+ sd2 = dup(sd);
+ if (sd2 == -1) {
+ test_fail("dup(sd) should have worked");
+ }
+
+ rc = fstat(sd, &info1);
+ if (rc == -1) {
+ test_fail("fstat(fd, &info1) failed");
+ }
+
+ rc = fstat(sd2, &info2);
+ if (rc == -1) {
+ test_fail("fstat(sd, &info2) failed");
+ }
+
+ if (info1.st_ino != info2.st_ino) {
+ test_fail("dup() failed info1.st_ino != info2.st_ino");
+ }
+
+ CLOSE(sd);
+ CLOSE(sd2);
+
+ debug("Test dup() with a closed socket");
+
+ errno = 0;
+ rc = dup(sd);
+ if (!(rc == -1 && errno == EBADF)) {
+ test_fail("dup(sd) on a closed socket shouldn't have worked");
+ }
+
+ debug("Test dup() with socket descriptor of -1");
+
+ errno = 0;
+ rc = dup(-1);
+ if (!(rc == -1 && errno == EBADF)) {
+ test_fail("dup(-1) shouldn't have worked");
+ }
+
+ debug("Test dup() when all of the file descriptors are taken");
+
+ SOCKET(sd, info->domain, info->type, 0);
+
+ for (i = 4; i < getdtablesize(); i++) {
+ rc = open("/dev/null", O_RDONLY);
+ if (rc == -1) {
+ test_fail("we couldn't open /dev/null for read");
+ }
+ }
+
+ errno = 0;
+ sd2 = dup(sd);
+ if (!(sd2 == -1 && errno == EMFILE)) {
+ test_fail("dup(sd) should have failed with errno = EMFILE");
+ }
+
+ for (i = 3; i < getdtablesize(); i++) {
+ CLOSE(i);
+ }
+
+ info->callback_cleanup();
+
+ debug("leaving test_dup()");
+}
+
+void test_dup2(const struct socket_test_info *info)
+{
+ struct stat info1;
+ struct stat info2;
+ int sd;
+ int fd;
+ int rc;
+
+ debug("entering test_dup2()");
+ info->callback_cleanup();
+
+ SOCKET(sd, info->domain, info->type, 0);
+
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc != 0) {
+ test_fail("bind() should have worked");
+ }
+
+ fd = open("/dev/null", O_RDONLY);
+ if (fd == -1) {
+ test_fail("open(\"/dev/null\", O_RDONLY) failed");
+ }
+
+ fd = dup2(sd, fd);
+ if (fd == -1) {
+ test_fail("dup2(sd, fd) failed.");
+ }
+
+ memset(&info1, '\0', sizeof(struct stat));
+ memset(&info2, '\0', sizeof(struct stat));
+
+ rc = fstat(fd, &info1);
+ if (rc == -1) {
+ test_fail("fstat(fd, &info1) failed");
+ }
+
+ rc = fstat(sd, &info2);
+ if (rc == -1) {
+ test_fail("fstat(sd, &info2) failed");
+ }
+
+ if (!(info1.st_ino == info2.st_ino &&
+ major(info1.st_dev) == major(info2.st_dev) &&
+ minor(info1.st_dev) == minor(info2.st_dev))) {
+
+ test_fail("dup2() failed");
+ }
+
+ CLOSE(fd);
+ CLOSE(sd);
+
+ info->callback_cleanup();
+ debug("leaving test_dup2()");
+
+}
+
+/*
+ * A toupper() server. This toy server converts a string to upper case.
+ */
+static void test_xfer_server(const struct socket_test_info *info, pid_t pid)
+{
+ int i;
+ struct timeval tv;
+ fd_set readfds;
+ int status;
+ int rc;
+ int sd;
+ unsigned char buf[BUFSIZE];
+ socklen_t client_addr_size;
+ int client_sd;
+ struct sockaddr_storage client_addr;
+
+ status = 0;
+ rc = 0;
+ sd = 0;
+ client_sd = 0;
+ client_addr_size = sizeof(struct sockaddr_storage);
+
+ memset(&buf, '\0', sizeof(buf));
+ memset(&client_addr, '\0', sizeof(client_addr));
+
+ SOCKET(sd, info->domain, info->type, 0);
+
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc == -1) {
+ test_fail("bind() should have worked");
+ }
+
+ rc = listen(sd, 8);
+ if (rc == -1) {
+ test_fail("listen(sd, 8) should have worked");
+ }
+
+ /* we're ready for connections, time to tell the client to start
+ * the test
+ */
+ kill(pid, SIGUSR1);
+
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readfds);
+ FD_SET(sd, &readfds);
+
+ /* use select() in case the client is really broken and never
+ * attempts to connect (we don't want to block on accept()
+ * forever).
+ */
+ rc = select(sd + 1, &readfds, NULL, NULL, &tv);
+ if (rc == -1) {
+ test_fail("[server] select() should not have failed");
+ }
+
+ if (rc != 1) {
+ test_fail("[server] select() should have returned 1");
+ printf("[server] select returned %d\n", rc);
+ }
+
+ if (!(FD_ISSET(sd, &readfds))) {
+ test_fail("[server] client didn't connect within 10 seconds");
+ kill(pid, SIGKILL);
+ return;
+ }
+
+ client_sd = accept(sd, (struct sockaddr *) &client_addr,
+ &client_addr_size);
+
+ if (client_sd == -1) {
+ test_fail("accept() should have worked");
+ kill(pid, SIGKILL);
+ return;
+ } else {
+ debug("[server] client accept()'d");
+ }
+
+ debug("[server] Reading message");
+ rc = read(client_sd, buf, sizeof(buf));
+ if (rc == -1) {
+ test_fail("read() failed unexpectedly");
+ kill(pid, SIGKILL);
+ return;
+ }
+ debug("[server] we got the following message:");
+ debug(buf);
+
+ for (i = 0; i < rc && i < 127; i++) {
+ buf[i] = toupper(buf[i]);
+ }
+
+ debug("[server] Writing message...");
+ rc = write(client_sd, buf, sizeof(buf));
+ if (rc == -1) {
+ test_fail("write(client_sd, buf, sizeof(buf)) failed");
+ kill(pid, SIGKILL);
+ return;
+ }
+
+ if (rc < strlen(buf)) {
+ test_fail("[server] write didn't write all the bytes");
+ }
+
+ memset(&buf, '\0', sizeof(buf));
+
+ debug("[server] Recv message");
+ rc = recv(client_sd, buf, sizeof(buf), 0);
+ if (rc == -1) {
+ test_fail("recv() failed unexpectedly");
+ kill(pid, SIGKILL);
+ return;
+ }
+ debug("[server] we got the following message:");
+ debug(buf);
+
+ for (i = 0; i < rc && i < 127; i++) {
+ buf[i] = toupper(buf[i]);
+ }
+
+ debug("[server] Sending message...");
+ rc = send(client_sd, buf, sizeof(buf), 0);
+ if (rc == -1) {
+ test_fail("send(client_sd, buf, sizeof(buf), 0) failed");
+ kill(pid, SIGKILL);
+ return;
+ }
+
+ if (rc < strlen(buf)) {
+ test_fail("[server] write didn't write all the bytes");
+ }
+
+ memset(&buf, '\0', sizeof(buf));
+
+ debug("[server] Recvfrom message");
+ rc = recvfrom(client_sd, buf, sizeof(buf), 0, NULL, 0);
+ if (rc == -1) {
+ test_fail("recvfrom() failed unexpectedly");
+ kill(pid, SIGKILL);
+ return;
+ }
+ debug("[server] we got the following message:");
+ debug(buf);
+
+ for (i = 0; i < rc && i < 127; i++) {
+ buf[i] = toupper(buf[i]);
+ }
+
+ debug("[server] Sendto message...");
+ rc = sendto(client_sd, buf, sizeof(buf), 0, NULL, 0);
+ if (rc == -1) {
+ test_fail("sendto() failed");
+ kill(pid, SIGKILL);
+ return;
+ }
+
+ if (rc < strlen(buf)) {
+ test_fail("[server] write didn't write all the bytes");
+ }
+
+ shutdown(client_sd, SHUT_RDWR);
+ CLOSE(client_sd);
+
+ shutdown(sd, SHUT_RDWR);
+ CLOSE(sd);
+
+ /* wait for client to exit */
+ do {
+ errno = 0;
+ rc = waitpid(pid, &status, 0);
+ } while (rc == -1 && errno == EINTR);
+
+ /* we use the exit status to get its error count */
+ errct += WEXITSTATUS(status);
+}
+
+int server_ready = 0;
+
+/* signal handler for the client */
+void test_xfer_sighdlr(int sig)
+{
+ debug("entering signal handler");
+ switch (sig) {
+ /* the server will send SIGUSR1 when it is time for us
+ * to start the tests
+ */
+ case SIGUSR1:
+ server_ready = 1;
+ debug("got SIGUSR1, the server is ready for the client");
+ break;
+ default:
+ debug("didn't get SIGUSR1");
+ }
+ debug("leaving signal handler");
+}
+
+/*
+ * A toupper() client.
+ */
+static void test_xfer_client(const struct socket_test_info *info)
+{
+ struct timeval tv;
+ fd_set readfds;
+ struct sockaddr_storage peer_addr;
+ socklen_t peer_addr_len;
+ int sd;
+ int rc;
+ char buf[BUFSIZE];
+
+ debug("[client] entering test_xfer_client()");
+ errct = 0; /* reset error count */
+ memset(&buf, '\0', sizeof(buf));
+
+ while (server_ready == 0) {
+ debug("[client] waiting for the server to signal");
+ sleep(1);
+ }
+
+ peer_addr_len = sizeof(peer_addr);
+
+
+ if (info->callback_xfer_prepclient) info->callback_xfer_prepclient();
+
+ debug("[client] creating client socket");
+ SOCKET(sd, info->domain, info->type, 0);
+
+ debug("[client] connecting to server through the symlink");
+ rc = connect(sd, info->clientaddrsym, info->clientaddrsymlen);
+ if (rc == -1) {
+ test_fail("[client] connect() should have worked");
+ } else {
+ debug("[client] connected");
+ }
+
+ debug("[client] testing getpeername()");
+ memset(&peer_addr, '\0', sizeof(peer_addr));
+ rc = getpeername(sd, (struct sockaddr *) &peer_addr, &peer_addr_len);
+ if (rc == -1) {
+ test_fail("[client] getpeername() should have worked");
+ }
+
+ /* we need to use the full path "/usr/src/test/DIR_56/test.sock"
+ * because that is what is returned by getpeername().
+ */
+
+ info->callback_check_sockaddr((struct sockaddr *) &peer_addr,
+ peer_addr_len, "getpeername", 1);
+
+ strncpy(buf, "Hello, World!", sizeof(buf) - 1);
+ debug("[client] send to server");
+ rc = write(sd, buf, sizeof(buf));
+ if (rc == -1) {
+ test_fail("[client] write() failed unexpectedly");
+ }
+
+ memset(buf, '\0', sizeof(buf));
+ debug("[client] read from server");
+ rc = read(sd, buf, sizeof(buf));
+ if (rc == -1) {
+ test_fail("[client] read() failed unexpectedly");
+ } else {
+ debug("[client] we got the following message:");
+ debug(buf);
+ }
+
+ if (strncmp(buf, "HELLO, WORLD!", sizeof(buf)) != 0) {
+ test_fail("[client] We didn't get the correct response");
+ }
+
+ memset(&buf, '\0', sizeof(buf));
+ strncpy(buf, "Bonjour!", sizeof(buf) - 1);
+
+ debug("[client] send to server");
+ rc = send(sd, buf, sizeof(buf), 0);
+ if (rc == -1) {
+ test_fail("[client] send() failed unexpectedly");
+ }
+
+ if (info->callback_xfer_peercred) info->callback_xfer_peercred(sd);
+
+ debug("Testing select()");
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 500000;
+
+ FD_ZERO(&readfds);
+ FD_SET(sd, &readfds);
+
+ rc = select(sd + 1, &readfds, NULL, NULL, &tv);
+ if (rc == -1) {
+ test_fail("[client] select() should not have failed");
+ }
+
+ if (rc != 1) {
+ test_fail("[client] select() should have returned 1");
+ }
+
+ if (!(FD_ISSET(sd, &readfds))) {
+ test_fail("The server didn't respond within 2.5 seconds");
+ }
+
+ memset(buf, '\0', sizeof(buf));
+ debug("[client] recv from server");
+ rc = recv(sd, buf, sizeof(buf), 0);
+ if (rc == -1) {
+ test_fail("[client] recv() failed unexpectedly");
+ } else {
+ debug("[client] we got the following message:");
+ debug(buf);
+ }
+
+ if (strncmp(buf, "BONJOUR!", sizeof(buf)) != 0) {
+ test_fail("[client] We didn't get the right response.");
+ }
+
+ memset(&buf, '\0', sizeof(buf));
+ strncpy(buf, "Hola!", sizeof(buf) - 1);
+
+ debug("[client] sendto to server");
+ rc = sendto(sd, buf, sizeof(buf), 0, NULL, 0);
+ if (rc == -1) {
+ test_fail("[client] sendto() failed");
+ }
+
+ debug("Testing select()");
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 500000;
+
+ FD_ZERO(&readfds);
+ FD_SET(sd, &readfds);
+
+ rc = select(sd + 1, &readfds, NULL, NULL, &tv);
+ if (rc == -1) {
+ test_fail("[client] select() should not have failed");
+ }
+
+ if (rc != 1) {
+ test_fail("[client] select() should have returned 1");
+ }
+
+ if (!(FD_ISSET(sd, &readfds))) {
+ test_fail("[client] The server didn't respond in 2.5 seconds");
+ }
+
+ memset(buf, '\0', sizeof(buf));
+ debug("[client] recvfrom from server");
+ rc = recvfrom(sd, buf, sizeof(buf), 0, NULL, 0);
+ if (rc == -1) {
+ test_fail("[cleint] recvfrom() failed unexpectedly");
+ } else {
+ debug("[client] we got the following message:");
+ debug(buf);
+ }
+
+ if (strncmp(buf, "HOLA!", sizeof(buf)) != 0) {
+ test_fail("[client] We didn't get the right response.");
+ }
+
+ debug("[client] closing socket");
+ CLOSE(sd);
+
+ debug("[client] leaving test_xfer_client()");
+ exit(errct);
+}
+
+void test_xfer(const struct socket_test_info *info)
+{
+ pid_t pid;
+
+ debug("entering test_xfer()");
+ info->callback_cleanup();
+
+ /* the signal handler is only used by the client, but we have to
+ * install it now. if we don't the server may signal the client
+ * before the handler is installed.
+ */
+ debug("installing signal handler");
+ if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
+ test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
+ }
+
+ debug("signal handler installed");
+
+ server_ready = 0;
+
+ pid = fork();
+ if (pid == -1) {
+ test_fail("fork() failed");
+ return;
+ } else if (pid == 0) {
+ debug("child");
+ errct = 0;
+ test_xfer_client(info);
+ test_fail("we should never get here");
+ exit(1);
+ } else {
+ debug("parent");
+ test_xfer_server(info, pid);
+ debug("parent done");
+ }
+
+ info->callback_cleanup();
+ debug("leaving test_xfer()");
+}
+
+static void test_simple_client(const struct socket_test_info *info, int type)
+{
+ char buf[BUFSIZE];
+ int sd, rc;
+
+ sd = socket(info->domain, type, 0);
+ if (sd == -1) {
+ test_fail("socket");
+ exit(errct);
+ }
+
+ while (server_ready == 0) {
+ debug("[client] waiting for the server");
+ sleep(1);
+ }
+
+ bzero(buf, BUFSIZE);
+ snprintf(buf, BUFSIZE-1, "Hello, My Name is Client.");
+
+ if (type == SOCK_DGRAM) {
+
+ rc = sendto(sd, buf, strlen(buf) + 1, 0,
+ info->clientaddr, info->clientaddrlen);
+ if (rc == -1) {
+ test_fail("sendto");
+ exit(errct);
+ }
+
+ } else {
+
+ rc = connect(sd, info->clientaddr, info->clientaddrlen);
+ if (rc == -1) {
+ test_fail("connect");
+ exit(errct);
+ }
+
+ rc = write(sd, buf, strlen(buf) + 1);
+
+ if (rc == -1) {
+ test_fail("write");
+ }
+
+ memset(buf, '\0', BUFSIZE);
+ rc = read(sd, buf, BUFSIZE);
+ if (rc == -1) {
+ test_fail("read");
+ }
+
+ if (strcmp("Hello, My Name is Server.", buf) != 0) {
+ test_fail("didn't read the correct string");
+ }
+ }
+
+ rc = close(sd);
+ if (rc == -1) {
+ test_fail("close");
+ }
+
+ exit(errct);
+}
+
+static void test_simple_server(const struct socket_test_info *info, int type,
+ pid_t pid)
+{
+ char buf[BUFSIZE];
+ int sd, rc, client_sd, status;
+ struct sockaddr_storage addr;
+ socklen_t addr_len;
+
+ addr_len = info->clientaddrlen;
+
+ sd = socket(info->domain, type, 0);
+ if (sd == -1) {
+ test_fail("socket");
+ }
+
+ assert(info->clientaddrlen <= sizeof(addr));
+ memcpy(&addr, info->clientaddr, info->clientaddrlen);
+
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc == -1) {
+ test_fail("bind");
+ }
+
+ if (type == SOCK_DGRAM) {
+
+ /* ready for client */
+ kill(pid, SIGUSR1);
+
+ rc = recvfrom(sd, buf, BUFSIZE, 0,
+ (struct sockaddr *) &addr, &addr_len);
+ if (rc == -1) {
+ test_fail("recvfrom");
+ }
+
+ } else {
+
+ rc = listen(sd, 5);
+ if (rc == -1) {
+ test_fail("listen");
+ }
+
+ /* we're ready for connections, time to tell the client
+ * to start the test
+ */
+ kill(pid, SIGUSR1);
+
+ client_sd = accept(sd, (struct sockaddr *) &addr, &addr_len);
+ if (client_sd == -1) {
+ test_fail("accept");
+ }
+
+ memset(buf, '\0', BUFSIZE);
+ rc = read(client_sd, buf, BUFSIZE);
+ if (rc == -1) {
+ test_fail("read");
+ }
+
+ if (strcmp("Hello, My Name is Client.", buf) != 0) {
+ test_fail("didn't read the correct string");
+ }
+
+ /* added for extra fun to make the client block on read() */
+ sleep(1);
+
+ bzero(buf, BUFSIZE);
+ snprintf(buf, BUFSIZE-1, "Hello, My Name is Server.");
+
+ rc = write(client_sd, buf, strlen(buf) + 1);
+ if (rc == -1) {
+ test_fail("write");
+ }
+ rc = close(client_sd);
+ if (rc == -1) {
+ test_fail("close");
+ }
+ }
+
+ rc = close(sd);
+ if (rc == -1) {
+ test_fail("close");
+ }
+
+ /* wait for client to exit */
+ do {
+ errno = 0;
+ rc = waitpid(pid, &status, 0);
+ } while (rc == -1 && errno == EINTR);
+
+ /* we use the exit status to get its error count */
+ errct += WEXITSTATUS(status);
+}
+
+static void test_abort_client(const struct socket_test_info *info,
+ int abort_type);
+static void test_abort_server(const struct socket_test_info *info,
+ pid_t pid, int abort_type);
+
+void test_abort_client_server(const struct socket_test_info *info,
+ int abort_type)
+{
+ pid_t pid;
+
+ debug("test_simple_client_server()");
+
+ info->callback_cleanup();
+
+ /* the signal handler is only used by the client, but we have to
+ * install it now. if we don't the server may signal the client
+ * before the handler is installed.
+ */
+ debug("installing signal handler");
+ if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
+ test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
+ }
+
+ debug("signal handler installed");
+
+ server_ready = 0;
+
+ pid = fork();
+ if (pid == -1) {
+ test_fail("fork() failed");
+ return;
+ } else if (pid == 0) {
+ debug("child");
+ errct = 0;
+ test_abort_client(info, abort_type);
+ test_fail("we should never get here");
+ exit(1);
+ } else {
+ debug("parent");
+ test_abort_server(info, pid, abort_type);
+ debug("parent done");
+ }
+
+ info->callback_cleanup();
+}
+
+static void test_abort_client(const struct socket_test_info *info,
+ int abort_type)
+{
+ char buf[BUFSIZE];
+ int sd, rc;
+
+ sd = socket(info->domain, info->type, 0);
+ if (sd == -1) {
+ test_fail("socket");
+ exit(errct);
+ }
+
+ while (server_ready == 0) {
+ debug("[client] waiting for the server");
+ sleep(1);
+ }
+
+ bzero(buf, BUFSIZE);
+ snprintf(buf, BUFSIZE-1, "Hello, My Name is Client.");
+
+ rc = connect(sd, info->clientaddr, info->clientaddrlen);
+ if (rc == -1) {
+ test_fail("connect");
+ exit(errct);
+ }
+
+ if (abort_type == 2) {
+ /* Give server a chance to close connection */
+ sleep(2);
+ rc = write(sd, buf, strlen(buf) + 1);
+ if (rc != -1) {
+ if (!info->ignore_write_conn_reset) {
+ test_fail("write should have failed\n");
+ }
+ } else if (errno != ECONNRESET) {
+ test_fail("errno should've been ECONNRESET\n");
+ }
+ }
+
+ rc = close(sd);
+ if (rc == -1) {
+ test_fail("close");
+ }
+
+ exit(errct);
+}
+
+static void test_abort_server(const struct socket_test_info *info,
+ pid_t pid, int abort_type)
+{
+ char buf[BUFSIZE];
+ int sd, rc, client_sd, status;
+ struct sockaddr_storage addr;
+ socklen_t addr_len;
+
+ addr_len = info->clientaddrlen;
+
+ sd = socket(info->domain, info->type, 0);
+ if (sd == -1) {
+ test_fail("socket");
+ }
+
+ assert(sizeof(addr) >= info->clientaddrlen);
+ memcpy(&addr, info->clientaddr, info->clientaddrlen);
+
+ rc = bind(sd, info->serveraddr, info->serveraddrlen);
+ if (rc == -1) {
+ test_fail("bind");
+ }
+
+ rc = listen(sd, 5);
+ if (rc == -1) {
+ test_fail("listen");
+ }
+
+ /* we're ready for connections, time to tell the client
+ * to start the test
+ */
+ kill(pid, SIGUSR1);
+
+ client_sd = accept(sd, (struct sockaddr *) &addr, &addr_len);
+ if (client_sd == -1) {
+ test_fail("accept");
+ }
+
+ if (abort_type == 1) {
+ memset(buf, '\0', BUFSIZE);
+ rc = read(client_sd, buf, BUFSIZE);
+ if (rc != -1 && (rc != 0 || !info->ignore_read_conn_reset)) {
+ test_fail("read should've failed or returned zero\n");
+ }
+ if (rc != 0 && errno != ECONNRESET) {
+ test_fail("errno should've been ECONNRESET\n");
+ }
+ } /* else if (abort_type == 2) { */
+ rc = close(client_sd);
+ if (rc == -1) {
+ test_fail("close");
+ }
+ /* } */
+
+ rc = close(sd);
+ if (rc == -1) {
+ test_fail("close");
+ }
+
+ /* wait for client to exit */
+ do {
+ errno = 0;
+ rc = waitpid(pid, &status, 0);
+ } while (rc == -1 && errno == EINTR);
+
+ /* we use the exit status to get its error count */
+ errct += WEXITSTATUS(status);
+}
+
+void test_simple_client_server(const struct socket_test_info *info, int type)
+{
+ pid_t pid;
+
+ debug("entering test_simple_client_server()");
+
+ info->callback_cleanup();
+
+ /* the signal handler is only used by the client, but we have to
+ * install it now. if we don't the server may signal the client
+ * before the handler is installed.
+ */
+ debug("installing signal handler");
+ if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
+ test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
+ }
+
+ debug("signal handler installed");
+
+ server_ready = 0;
+
+ pid = fork();
+ if (pid == -1) {
+ test_fail("fork() failed");
+ return;
+ } else if (pid == 0) {
+ debug("child");
+ errct = 0;
+ test_simple_client(info, type);
+ test_fail("we should never get here");
+ exit(1);
+ } else {
+ debug("parent");
+ test_simple_server(info, type, pid);
+ debug("parent done");
+ }
+
+ info->callback_cleanup();
+ debug("leaving test_simple_client_server()");
+}
+
+void test_msg_dgram(const struct socket_test_info *info)
+{
+ int rc;
+ int src;
+ int dst;
+ struct sockaddr_storage addr;
+ struct iovec iov[3];
+ struct msghdr msg1;
+ struct msghdr msg2;
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+
+ debug("entering test_msg_dgram");
+
+ info->callback_cleanup();
+
+ src = socket(info->domain, SOCK_DGRAM, 0);
+ if (src == -1) {
+ test_fail("socket");
+ }
+
+ dst = socket(info->domain, SOCK_DGRAM, 0);
+ if (dst == -1) {
+ test_fail("socket");
+ }
+
+ rc = bind(src, info->serveraddr2, info->serveraddr2len);
+ if (rc == -1) {
+ test_fail("bind");
+ }
+
+ assert(info->clientaddrlen <= sizeof(addr));
+ memcpy(&addr, info->clientaddr, info->clientaddrlen);
+
+ rc = bind(dst, info->serveraddr, info->serveraddrlen);
+ if (rc == -1) {
+ test_fail("bind");
+ }
+
+ memset(&buf1, '\0', BUFSIZE);
+ memset(&buf2, '\0', BUFSIZE);
+ memset(&buf3, '\0', BUFSIZE);
+
+ strncpy(buf1, "Minix ", BUFSIZE-1);
+ strncpy(buf2, "is ", BUFSIZE-1);
+ strncpy(buf3, "great!", BUFSIZE-1);
+
+ iov[0].iov_base = buf1;
+ iov[0].iov_len = 6;
+ iov[1].iov_base = buf2;
+ iov[1].iov_len = 3;
+ iov[2].iov_base = buf3;
+ iov[2].iov_len = 32;
+
+ memset(&msg1, '\0', sizeof(struct msghdr));
+ msg1.msg_name = &addr;
+ msg1.msg_namelen = info->clientaddrlen;
+ msg1.msg_iov = iov;
+ msg1.msg_iovlen = 3;
+ msg1.msg_control = NULL;
+ msg1.msg_controllen = 0;
+ msg1.msg_flags = 0;
+
+ rc = sendmsg(src, &msg1, 0);
+ if (rc == -1) {
+ test_fail("sendmsg");
+ }
+
+ memset(&buf1, '\0', BUFSIZE);
+ memset(&buf2, '\0', BUFSIZE);
+
+ iov[0].iov_base = buf1;
+ iov[0].iov_len = 9;
+ iov[1].iov_base = buf2;
+ iov[1].iov_len = 32;
+
+ memset(&addr, '\0', sizeof(addr));
+ memset(&msg2, '\0', sizeof(struct msghdr));
+ msg2.msg_name = &addr;
+ msg2.msg_namelen = sizeof(addr);
+ msg2.msg_iov = iov;
+ msg2.msg_iovlen = 2;
+ msg2.msg_control = NULL;
+ msg2.msg_controllen = 0;
+ msg2.msg_flags = 0;
+
+ rc = recvmsg(dst, &msg2, 0);
+ if (rc == -1) {
+ test_fail("recvmsg");
+ }
+
+ if (strncmp(buf1, "Minix is ", 9) || strncmp(buf2, "great!", 6)) {
+ test_fail("recvmsg");
+ }
+
+ /* we need to use the full path "/usr/src/test/DIR_56/testb.sock"
+ * because that is what is returned by recvmsg().
+ */
+ info->callback_check_sockaddr((struct sockaddr *) &addr,
+ msg2.msg_namelen, "recvmsg", 2);
+
+ rc = close(dst);
+ if (rc == -1) {
+ test_fail("close");
+ }
+
+ rc = close(src);
+ if (rc == -1) {
+ test_fail("close");
+ }
+
+ info->callback_cleanup();
+ debug("leaving test_msg_dgram");
+}
+
+#define check_select(sd, rd, wr, block) \
+ check_select_internal(sd, rd, wr, block, 1, __LINE__)
+#define check_select_cond(sd, rd, wr, block, allchecks) \
+ check_select_internal(sd, rd, wr, block, allchecks, __LINE__)
+
+static void
+check_select_internal(int sd, int rd, int wr, int block, int allchecks, int line)
+{
+ fd_set read_set, write_set;
+ struct timeval tv;
+
+ FD_ZERO(&read_set);
+ if (rd != -1)
+ FD_SET(sd, &read_set);
+
+ FD_ZERO(&write_set);
+ if (wr != -1)
+ FD_SET(sd, &write_set);
+
+ tv.tv_sec = block ? 2 : 0;
+ tv.tv_usec = 0;
+
+ errno = 0;
+ if (select(sd + 1, &read_set, &write_set, NULL, &tv) < 0)
+ test_fail_fl("select() failed unexpectedly", __FILE__, line);
+
+ if (rd != -1 && !!FD_ISSET(sd, &read_set) != rd && allchecks)
+ test_fail_fl("select() mismatch on read operation",
+ __FILE__, line);
+
+ if (wr != -1 && !!FD_ISSET(sd, &write_set) != wr && allchecks)
+ test_fail_fl("select() mismatch on write operation",
+ __FILE__, line);
+}
+
+/*
+ * Verify that:
+ * - a nonblocking connecting socket for which there is no accepter, will
+ * return EINPROGRESS and complete in the background later;
+ * - a nonblocking listening socket will return EAGAIN on accept;
+ * - connecting a connecting socket yields EALREADY;
+ * - connecting a connected socket yields EISCONN;
+ * - selecting for read and write on a connecting socket will only satisfy the
+ * write only once it is connected;
+ * - doing a nonblocking write on a connecting socket yields EAGAIN;
+ * - doing a nonblocking read on a connected socket with no pending data yields
+ * EAGAIN.
+ */
+void
+test_nonblock(const struct socket_test_info *info)
+{
+ char buf[BUFSIZE];
+ socklen_t len;
+ int server_sd, client_sd;
+ struct sockaddr_storage addr;
+ int status;
+
+ debug("entering test_nonblock()");
+ memset(buf, 0, sizeof(buf));
+
+ SOCKET(server_sd, info->domain, info->type, 0);
+
+ if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
+ test_fail("bind() should have worked");
+
+ if (listen(server_sd, 8) == -1)
+ test_fail("listen() should have worked");
+
+ fcntl(server_sd, F_SETFL, fcntl(server_sd, F_GETFL) | O_NONBLOCK);
+
+ check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ len = sizeof(addr);
+ if (accept(server_sd, (struct sockaddr *) &addr, &len) != -1 ||
+ errno != EAGAIN)
+ test_fail("accept() should have yielded EAGAIN");
+
+ SOCKET(client_sd, info->domain, info->type, 0);
+
+ fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
+ test_fail("connect() should have failed");
+ } else if (errno != EINPROGRESS) {
+ test_fail("connect() should have yielded EINPROGRESS");
+ }
+
+ check_select_cond(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/,
+ !info->ignore_select_delay);
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
+ test_fail("connect() should have failed");
+ } else if (errno != EALREADY && errno != EISCONN) {
+ test_fail("connect() should have yielded EALREADY");
+ }
+
+ if (recv(client_sd, buf, sizeof(buf), 0) != -1 || errno != EAGAIN)
+ test_fail("recv() should have yielded EAGAIN");
+
+ /* This may be an implementation aspect, or even plain wrong (?). */
+ if (send(client_sd, buf, sizeof(buf), 0) != -1) {
+ if (!info->ignore_send_waiting) {
+ test_fail("send() should have failed");
+ }
+ } else if (errno != EAGAIN) {
+ test_fail("send() should have yielded EAGAIN");
+ }
+
+ switch (fork()) {
+ case 0:
+ errct = 0;
+ close(client_sd);
+
+ check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ len = sizeof(addr);
+ client_sd = accept(server_sd, (struct sockaddr *) &addr, &len);
+ if (client_sd == -1)
+ test_fail("accept() should have succeeded");
+
+ check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ close(server_sd);
+
+ /* Let the socket become writable in the parent process. */
+ sleep(1);
+
+ if (write(client_sd, buf, 1) != 1)
+ test_fail("write() should have succeeded");
+
+ /* Wait for the client side to close. */
+ check_select_cond(client_sd, 0 /*read*/, 1 /*write*/,
+ 0 /*block*/, !info->ignore_select_delay /*allchecks*/);
+ check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
+ check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ exit(errct);
+ case -1:
+ test_fail("can't fork");
+ default:
+ break;
+ }
+
+ close(server_sd);
+
+ check_select(client_sd, 0 /*read*/, 1 /*write*/, 1 /*block*/);
+ check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1 ||
+ errno != EISCONN)
+ test_fail("connect() should have yielded EISCONN");
+
+ check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
+ check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ if (read(client_sd, buf, 1) != 1)
+ test_fail("read() should have succeeded");
+
+ check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ if (read(client_sd, buf, 1) != -1 || errno != EAGAIN)
+ test_fail("read() should have yielded EAGAIN");
+
+ /* Let the child process block on the select waiting for the close. */
+ sleep(1);
+
+ close(client_sd);
+
+ errno = 0;
+ if (wait(&status) <= 0)
+ test_fail("wait() should have succeeded");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ test_fail("child process failed the test");
+
+ info->callback_cleanup();
+ debug("leaving test_nonblock()");
+}
+
+/*
+ * Verify that a nonblocking connect for which there is an accepter, succeeds
+ * immediately. A pretty lame test, only here for completeness.
+ */
+void
+test_connect_nb(const struct socket_test_info *info)
+{
+ socklen_t len;
+ int server_sd, client_sd;
+ struct sockaddr_storage addr;
+ int status;
+
+ debug("entering test_connect_nb()");
+ SOCKET(server_sd, info->domain, info->type, 0);
+
+ if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
+ test_fail("bind() should have worked");
+
+ if (listen(server_sd, 8) == -1)
+ test_fail("listen() should have worked");
+
+ switch (fork()) {
+ case 0:
+ errct = 0;
+ len = sizeof(addr);
+ if (accept(server_sd, (struct sockaddr *) &addr, &len) == -1)
+ test_fail("accept() should have succeeded");
+
+ exit(errct);
+ case -1:
+ test_fail("can't fork");
+ default:
+ break;
+ }
+
+ close(server_sd);
+
+ sleep(1);
+
+ SOCKET(client_sd, info->domain, info->type, 0);
+
+ fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != 0) {
+ if (!info->ignore_connect_delay) {
+ test_fail("connect() should have succeeded");
+ } else if (errno != EINPROGRESS) {
+ test_fail("connect() should have succeeded or "
+ "failed with EINPROGRESS");
+ }
+ }
+
+ close(client_sd);
+
+ if (wait(&status) <= 0)
+ test_fail("wait() should have succeeded");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ test_fail("child process failed the test");
+
+ info->callback_cleanup();
+ debug("leaving test_connect_nb()");
+}
+
+static void
+dummy_handler(int sig)
+{
+ /* Nothing. */
+}
+
+/*
+ * Verify that:
+ * - interrupting a blocking connect will return EINTR but complete in the
+ * background later;
+ * - doing a blocking write on an asynchronously connecting socket succeeds
+ * once the socket is connected.
+ * - doing a nonblocking write on a connected socket with lots of pending data
+ * yields EAGAIN.
+ */
+void
+test_intr(const struct socket_test_info *info)
+{
+ struct sigaction act, oact;
+ char buf[BUFSIZE];
+ int isconn;
+ socklen_t len;
+ int server_sd, client_sd;
+ struct sockaddr_storage addr;
+ int r, status;
+
+ debug("entering test_intr()");
+ memset(buf, 0, sizeof(buf));
+
+ SOCKET(server_sd, info->domain, info->type, 0);
+
+ if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
+ test_fail("bind() should have worked");
+
+ if (listen(server_sd, 8) == -1)
+ test_fail("listen() should have worked");
+
+ SOCKET(client_sd, info->domain, info->type, 0);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = dummy_handler;
+ if (sigaction(SIGALRM, &act, &oact) == -1)
+ test_fail("sigaction() should have succeeded");
+
+ if (info->domain != PF_INET) alarm(1);
+
+ isconn = 0;
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
+ if (!info->ignore_connect_unaccepted) {
+ test_fail("connect() should have failed");
+ }
+ isconn = 1;
+ } else if (errno != EINTR) {
+ test_fail("connect() should have yielded EINTR");
+ }
+
+ alarm(0);
+
+ check_select(client_sd, 0 /*read*/, isconn /*write*/, 0 /*block*/);
+
+ switch (fork()) {
+ case 0:
+ errct = 0;
+ close(client_sd);
+
+ check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ len = sizeof(addr);
+ client_sd = accept(server_sd, (struct sockaddr *) &addr, &len);
+ if (client_sd == -1)
+ test_fail("accept() should have succeeded");
+
+ check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ close(server_sd);
+
+ check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
+ check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ if (recv(client_sd, buf, sizeof(buf), 0) != sizeof(buf))
+ test_fail("recv() should have yielded bytes");
+
+ /* No partial transfers should be happening. */
+ check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ sleep(1);
+
+ fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) |
+ O_NONBLOCK);
+
+ /* We can only test nonblocking writes by filling the pipe. */
+ while ((r = write(client_sd, buf, sizeof(buf))) > 0);
+
+ if (r != -1) {
+ test_fail("write() should have failed");
+ } else if (errno != EAGAIN) {
+ test_fail("write() should have yielded EAGAIN");
+ }
+
+ check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
+
+ if (write(client_sd, buf, 1) != -1) {
+ test_fail("write() should have failed");
+ } else if (errno != EAGAIN) {
+ test_fail("write() should have yielded EAGAIN");
+ }
+
+ exit(errct);
+ case -1:
+ test_fail("can't fork");
+ default:
+ break;
+ }
+
+ close(server_sd);
+
+ if (send(client_sd, buf, sizeof(buf), 0) != sizeof(buf))
+ test_fail("send() should have succeded");
+
+ check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ if (wait(&status) <= 0)
+ test_fail("wait() should have succeeded");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ test_fail("child process failed the test");
+
+ check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ close(client_sd);
+
+ sigaction(SIGALRM, &oact, NULL);
+
+ info->callback_cleanup();
+ debug("leaving test_intr()");
+}
+
+/*
+ * Verify that closing a connecting socket before it is accepted will result in
+ * no activity on the accepting side later.
+ */
+void
+test_connect_close(const struct socket_test_info *info)
+{
+ int server_sd, client_sd;
+ struct sockaddr_storage addr;
+ socklen_t len;
+
+ debug("entering test_connect_close()");
+ SOCKET(server_sd, info->domain, info->type, 0);
+
+ if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
+ test_fail("bind() should have worked");
+
+ if (listen(server_sd, 8) == -1)
+ test_fail("listen() should have worked");
+
+ fcntl(server_sd, F_SETFL, fcntl(server_sd, F_GETFL) | O_NONBLOCK);
+
+ check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
+
+ SOCKET(client_sd, info->domain, info->type, 0);
+
+ fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1 ||
+ errno != EINPROGRESS)
+ test_fail("connect() should have yielded EINPROGRESS");
+
+ check_select_cond(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/,
+ !info->ignore_select_delay);
+ check_select_cond(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/,
+ !info->ignore_select_delay);
+
+ close(client_sd);
+
+ check_select_cond(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/,
+ !info->ignore_select_delay);
+
+ len = sizeof(addr);
+ errno = 0;
+ if (accept(server_sd, (struct sockaddr *) &addr, &len) != -1) {
+ if (!info->ignore_accept_delay) {
+ test_fail("accept() should have failed");
+ }
+ } else if (errno != EAGAIN) {
+ test_fail("accept() should have yielded EAGAIN");
+ }
+ close(server_sd);
+
+ info->callback_cleanup();
+ debug("leaving test_connect_close()");
+}
+
+/*
+ * Verify that closing a listening socket will cause a blocking connect to fail
+ * with ECONNRESET, and that a subsequent write will yield EPIPE.
+ */
+void
+test_listen_close(const struct socket_test_info *info)
+{
+ int server_sd, client_sd;
+ int status;
+ char byte;
+
+ debug("entering test_listen_close()");
+ SOCKET(server_sd, info->domain, info->type, 0);
+
+ if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
+ test_fail("bind() should have worked");
+
+ if (listen(server_sd, 8) == -1)
+ test_fail("listen() should have worked");
+
+ switch (fork()) {
+ case 0:
+ sleep(1);
+
+ exit(0);
+ case -1:
+ test_fail("can't fork");
+ default:
+ break;
+ }
+
+ close(server_sd);
+
+ SOCKET(client_sd, info->domain, info->type, 0);
+
+ byte = 0;
+ if (write(client_sd, &byte, 1) != -1 || errno != ENOTCONN)
+ /* Yes, you fucked up the fix for the FIXME below. */
+ test_fail("write() should have yielded ENOTCONN");
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
+ if (!info->bug_connect_after_close) {
+ test_fail("connect() should have failed");
+ }
+ } else if (errno != ECONNRESET) {
+ test_fail("connect() should have yielded ECONNRESET");
+ }
+
+ /*
+ * FIXME: currently UDS cannot distinguish between sockets that have
+ * not yet been connected, and sockets that have been disconnected.
+ * Thus, we get the same error for both: ENOTCONN instead of EPIPE.
+ */
+#if 0
+ if (write(client_sd, &byte, 1) != -1 || errno != EPIPE)
+ test_fail("write() should have yielded EPIPE");
+#endif
+
+ close(client_sd);
+
+ if (wait(&status) <= 0)
+ test_fail("wait() should have succeeded");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ test_fail("child process failed the test");
+
+ info->callback_cleanup();
+ debug("leaving test_listen_close()");
+}
+
+/*
+ * Verify that closing a listening socket will cause a nonblocking connect to
+ * result in the socket becoming readable and writable, and yielding ECONNRESET
+ * and EPIPE on the next two writes, respectively.
+ */
+void
+test_listen_close_nb(const struct socket_test_info *info)
+{
+ int server_sd, client_sd;
+ int status;
+ char byte;
+
+ debug("entering test_listen_close_nb()");
+ SOCKET(server_sd, info->domain, info->type, 0);
+
+ if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
+ test_fail("bind() should have worked");
+
+ if (listen(server_sd, 8) == -1)
+ test_fail("listen() should have worked");
+
+ switch (fork()) {
+ case 0:
+ sleep(1);
+
+ exit(0);
+ case -1:
+ test_fail("can't fork");
+ default:
+ break;
+ }
+
+ close(server_sd);
+
+ SOCKET(client_sd, info->domain, info->type, 0);
+
+ fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
+
+ if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1 ||
+ errno != EINPROGRESS)
+ test_fail("connect() should have yielded EINPROGRESS");
+
+ check_select_cond(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/,
+ !info->ignore_select_delay);
+ check_select_cond(client_sd, 1 /*read*/, 1 /*write*/, 1 /*block*/,
+ !info->ignore_select_delay);
+
+ byte = 0;
+ if (write(client_sd, &byte, 1) != -1) {
+ if (!info->ignore_write_conn_reset) {
+ test_fail("write() should have failed");
+ }
+ } else if (errno != ECONNRESET) {
+ test_fail("write() should have yielded ECONNRESET");
+ }
+
+ /*
+ * FIXME: currently UDS cannot distinguish between sockets that have
+ * not yet been connected, and sockets that have been disconnected.
+ * Thus, we get the same error for both: ENOTCONN instead of EPIPE.
+ */
+#if 0
+ if (write(client_sd, &byte, 1) != -1 || errno != EPIPE)
+ test_fail("write() should have yielded EPIPE");
+#endif
+
+ check_select_cond(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/,
+ !info->ignore_select_delay);
+
+ close(client_sd);
+
+ if (wait(&status) <= 0)
+ test_fail("wait() should have succeeded");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ test_fail("child process failed the test");
+
+ info->callback_cleanup();
+ debug("leaving test_listen_close_nb()");
+}
--- /dev/null
+#define DEBUG 0
+
+/* buffer for send/recv */
+#define BUFSIZE (128)
+
+/* macro to display information about a failed test and increment the errct */
+void test_fail_fl(char *msg, char *file, int line);
+#define test_fail(msg) test_fail_fl(msg, __FILE__, __LINE__)
+
+#if DEBUG == 1
+/* macros to display debugging information */
+void debug_fl(char *msg, char *file, int line);
+#define debug(msg) debug_fl(msg, __FILE__, __LINE__)
+#else
+#define debug(msg)
+#endif
+
+#define SOCKET(sd,domain,type,protocol) \
+ do { \
+ errno = 0; \
+ sd = socket(domain, type, protocol); \
+ if (sd == -1) { \
+ test_fail("sd = socket(domain, type, protocol) failed");\
+ } \
+ } while (0)
+
+#define UNLINK(path) \
+ do { \
+ int rc; \
+ errno = 0; \
+ rc = unlink(path); \
+ if (rc == -1 && errno != ENOENT) { \
+ test_fail("unlink(path) failed"); \
+ } \
+ } while(0)
+
+#define SYMLINK(oldpath,newpath) \
+ do { \
+ int rc; \
+ errno = 0; \
+ rc = symlink(oldpath,newpath); \
+ if (rc == -1) { \
+ test_fail("symlink(oldpath,newpath) failed"); \
+ } \
+ } while(0)
+
+#define CLOSE(sd) \
+ do { \
+ int rc; \
+ errno = 0; \
+ rc = close(sd); \
+ if (rc == -1) { \
+ test_fail("close(sd) failed"); \
+ } \
+ } while (0)
+
+extern int server_ready;
+void test_xfer_sighdlr(int sig);
+
+struct socket_test_info {
+ const struct sockaddr *clientaddr;
+ socklen_t clientaddrlen;
+ const struct sockaddr *clientaddr2;
+ socklen_t clientaddr2len;
+ const struct sockaddr *clientaddrsym;
+ socklen_t clientaddrsymlen;
+ int domain;
+ int expected_rcvbuf;
+ int expected_sndbuf;
+ const struct sockaddr *serveraddr;
+ socklen_t serveraddrlen;
+ const struct sockaddr *serveraddr2;
+ socklen_t serveraddr2len;
+ int type;
+ const int *types;
+ size_t typecount;
+
+ int buf_accept_intr; /* accept can return success when interrupted */
+ int bug_bind_in_use; /* bind does not return EADDRINUSE */
+ int bug_bind_null; /* bind segfaults with NULL pointer */
+ int bug_connect_after_close; /* connect succeeds after server closed */
+ int bug_select_nonblock; /* select unexpected results for nb sockets */
+ int bug_shutdown; /* shutdown not supported */
+ int bug_shutdown_not_conn; /* shutdown does not return ENOTCONN */
+ int bug_shutdown_read; /* shutdown does not support SHUT_RD */
+ int bug_sockopt_rcvbuf; /* get/setsockopt does not support SO_RCVBUF */
+ int bug_sockopt_sndbuf; /* get/setsockopt does not support SO_SNDBUF */
+ int ignore_accept_delay; /* success from accept after aborted connect */
+ int ignore_connect_delay; /* nb connect not instant */
+ int ignore_connect_unaccepted; /* connect succeeds without accept */
+ int ignore_read_conn_reset; /* read does not guarantee ECONNRESET */
+ int ignore_select_delay; /* select delay reflecting other side nb op */
+ int ignore_send_waiting; /* can send while waiting for nb recv */
+ int ignore_write_conn_reset; /* write does not guarantee ECONNRESET */
+
+ void (* callback_check_sockaddr)(const struct sockaddr *sockaddr,
+ socklen_t sockaddrlen, const char *callname, int addridx);
+ void (* callback_cleanup)(void);
+ void (* callback_xfer_peercred)(int sd); /* can be NULL */
+ void (* callback_xfer_prepclient)(void); /* can be NULL */
+};
+
+void test_abort_client_server(const struct socket_test_info *info,
+ int abort_type);
+void test_bind(const struct socket_test_info *info);
+void test_close(const struct socket_test_info *info);
+void test_connect_close(const struct socket_test_info *info);
+void test_connect_nb(const struct socket_test_info *info);
+void test_dup(const struct socket_test_info *info);
+void test_dup2(const struct socket_test_info *info);
+void test_getsockname(const struct socket_test_info *info);
+void test_intr(const struct socket_test_info *info);
+void test_listen(const struct socket_test_info *info);
+void test_listen_close(const struct socket_test_info *info);
+void test_listen_close_nb(const struct socket_test_info *info);
+void test_msg_dgram(const struct socket_test_info *info);
+void test_nonblock(const struct socket_test_info *info);
+void test_read(const struct socket_test_info *info);
+void test_shutdown(const struct socket_test_info *info);
+void test_simple_client_server(const struct socket_test_info *info, int type);
+void test_sockopts(const struct socket_test_info *info);
+void test_socket(const struct socket_test_info *info);
+void test_write(const struct socket_test_info *info);
+void test_xfer(const struct socket_test_info *info);
alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
- 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 \
- sh1 sh2 interp mfs isofs vnd"
+ 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
+ 81 sh1 sh2 interp mfs isofs vnd"
tests_no=`expr 0`
# If root, make sure the setuid tests have the correct permissions
* socketpair(), write(), writev()
*/
-#define DEBUG 0
-
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
*/
int max_error = 4;
#include "common.h"
+#include "common-socket.h"
/* Use the common testing code instead of reinventing the wheel. */
#define TEST_TXT_FILE "test.txt"
#define MSG "This raccoon loves to eat bugs.\n"
-/* buffer for send/recv */
-#define BUFSIZE (128)
-
-#define ISO8601_FORMAT "%Y-%m-%dT%H:%M:%S"
-
/* socket types supported */
static int types[3] = {SOCK_STREAM, SOCK_SEQPACKET, SOCK_DGRAM};
static char sock_fullpath[PATH_MAX + 1];
-static void test_abort_client_server(int abort_type);
-static void test_abort_client(int abort_type);
-static void test_abort_server(pid_t pid, int abort_type);
-
-/* timestamps for debug and error logs */
-static char *get_timestamp(void)
-{
- struct tm *tm;
- time_t t;
- size_t len;
- char *s;
-
- len = sizeof(char) * 32;
-
- t = time(NULL);
- if (t == -1) {
- return NULL;
- }
- tm = gmtime(&t);
- if (tm == NULL) {
- return NULL;
- }
-
- s = (char *) malloc(len);
- if (!s) {
- perror("malloc");
- return NULL;
- }
- memset(s, '\0', len);
-
- strftime(s, len - 1, ISO8601_FORMAT, tm);
- return s;
-}
-
-/* macro to display information about a failed test and increment the errct */
-static void test_fail_fl(char *msg, char *file, int line)
-{
- char *timestamp;
- timestamp = get_timestamp();
- if (errct == 0) fprintf(stderr, "\n");
- fprintf(stderr, "[ERROR][%s] (%s Line %d) %s [pid=%d:errno=%d:%s]\n",
- timestamp, file, line, msg, getpid(),
- errno, strerror(errno));
- fflush(stderr);
- if (timestamp != NULL) {
- free(timestamp);
- timestamp = NULL;
- }
- e(7);
-}
-#define test_fail(msg) test_fail_fl(msg, __FILE__, __LINE__)
-
/* Convert name to the full path of the socket. Assumes name is in cwd. */
-static char *fullpath(char *name)
+static char *fullpath(const char *name)
{
char cwd[PATH_MAX + 1];
return(sock_fullpath);
}
-#if DEBUG == 1
-/* macros to display debugging information */
-static void debug_fl(char *msg, char *file, int line)
-{
- char *timestamp;
- timestamp = get_timestamp();
- fprintf(stdout,"[DEBUG][%s] (%s:%d) %s [pid=%d]\n",
- timestamp, __FILE__, __LINE__, msg, getpid());
- fflush(stdout);
- if (timestamp != NULL) {
- free(timestamp);
- timestamp = NULL;
- }
-}
-#define debug(msg) debug_fl(msg, __FILE__, __LINE__)
-#else
-#define debug(msg)
-#endif
-
-#define SOCKET(sd,domain,type,protocol) \
- do { \
- errno = 0; \
- sd = socket(domain, type, protocol); \
- if (sd == -1) { \
- test_fail("sd = socket(domain, type, protocol) failed");\
- } \
- } while (0)
-
-#define UNLINK(path) \
- do { \
- int rc; \
- errno = 0; \
- rc = unlink(path); \
- if (rc == -1 && errno != ENOENT) { \
- test_fail("unlink(path) failed"); \
- } \
- } while(0)
-
-#define SYMLINK(oldpath,newpath) \
- do { \
- int rc; \
- errno = 0; \
- rc = symlink(oldpath,newpath); \
- if (rc == -1) { \
- test_fail("symlink(oldpath,newpath) failed"); \
- } \
- } while(0)
-
-#define CLOSE(sd) \
- do { \
- int rc; \
- errno = 0; \
- rc = close(sd); \
- if (rc == -1) { \
- test_fail("close(sd) failed"); \
- } \
- } while (0)
-
-static void test_socket(void)
-{
- struct stat statbuf, statbuf2;
- int sd, sd2;
- int rc;
- int i;
-
- debug("entering test_socket()");
-
- debug("Test socket() with an unsupported address family");
-
- errno = 0;
- sd = socket(-1, SOCK_STREAM, 0);
- if (!(sd == -1 && errno == EAFNOSUPPORT)) {
- test_fail("socket");
- if (sd != -1) {
- CLOSE(sd);
- }
- }
-
- debug("Test socket() with all available FDs open by this process");
-
- for (i = 3; i < getdtablesize(); i++) {
- rc = open("/dev/null", O_RDONLY);
- if (rc == -1) {
- test_fail("we couldn't open /dev/null for read");
- }
- }
-
- errno = 0;
- sd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (!(sd == -1 && errno == EMFILE)) {
- test_fail("socket() call with all fds open should fail");
- if (sd != -1) {
- CLOSE(sd);
- }
- }
-
- for (i = 3; i < getdtablesize(); i++) {
- CLOSE(i);
- }
-
- debug("Test socket() with an mismatched protocol");
-
- errno = 0;
- sd = socket(PF_UNIX, SOCK_STREAM, 4);
- if (!(sd == -1 && errno == EPROTONOSUPPORT)) {
- test_fail("socket() should fail with errno = EPROTONOSUPPORT");
- if (sd != -1) {
- CLOSE(sd);
- }
- }
-
- debug("Test socket() success");
-
- /*
- * open 2 sockets at once and *then* close them.
- * This will test that /dev/uds is cloning properly.
- */
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- SOCKET(sd2, PF_UNIX, SOCK_STREAM, 0);
-
- rc = fstat(sd, &statbuf);
- if (rc == -1) {
- test_fail("fstat failed on sd");
- }
-
- rc = fstat(sd2, &statbuf2);
- if (rc == -1) {
- test_fail("fstat failed on sd2");
- }
-
-
- if (statbuf.st_dev == statbuf2.st_dev) {
- test_fail("/dev/uds isn't being cloned");
- }
-
- CLOSE(sd2);
- CLOSE(sd);
-
- debug("leaving test_socket()");
-}
-
static void test_header(void)
{
struct sockaddr_un sun;
CLOSE(sv[1]);
}
-static void test_getsockname(void)
-{
- int sd;
- int rc;
- struct sockaddr_un addr, sock_addr;
- socklen_t sock_addr_len;
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
+static void callback_check_sockaddr(const struct sockaddr *sockaddr,
+ socklen_t sockaddrlen, const char *callname, int addridx) {
+ char buf[256];
+ const char *path;
+ const struct sockaddr_un *sockaddr_un =
+ (const struct sockaddr_un *) sockaddr;
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("bind() should have worked");
+ switch (addridx) {
+ case 1: path = TEST_SUN_PATH; break;
+ case 2: path = TEST_SUN_PATHB; break;
+ default:
+ fprintf(stderr, "error: invalid addridx %d in "
+ "callback_check_sockaddr\n", addridx);
+ abort();
}
- debug("Test getsockname() success");
-
- memset(&sock_addr, '\0', sizeof(struct sockaddr_un));
- sock_addr_len = sizeof(struct sockaddr_un);
-
- rc = getsockname(sd, (struct sockaddr *) &sock_addr, &sock_addr_len);
- if (rc == -1) {
- test_fail("getsockname() should have worked");
- }
+ if (!(sockaddr_un->sun_family == AF_UNIX &&
+ strncmp(sockaddr_un->sun_path,
+ fullpath(path),
+ sizeof(sockaddr_un->sun_path) - 1) == 0)) {
- if (!(sock_addr.sun_family == AF_UNIX && strncmp(sock_addr.sun_path,
- fullpath(TEST_SUN_PATH),
- sizeof(sock_addr.sun_path) - 1) == 0)) {
- test_fail("getsockname() did return the right address");
- fprintf(stderr, "exp: '%s' | got: '%s'\n", addr.sun_path,
- sock_addr.sun_path);
+ snprintf(buf, sizeof(buf), "%s() didn't return the right addr",
+ callname);
+ test_fail(buf);
+ fprintf(stderr, "exp: '%s' | got: '%s'\n", path,
+ sockaddr_un->sun_path);
}
+}
- CLOSE(sd);
+static void callback_cleanup(void) {
+ UNLINK(TEST_SUN_PATH);
+ UNLINK(TEST_SUN_PATHB);
+ UNLINK(TEST_SYM_A);
+ UNLINK(TEST_SYM_B);
}
-static void test_bind(void)
+static void test_bind_unix(void)
{
struct sockaddr_un addr;
- struct sockaddr_un sock_addr;
- socklen_t sock_addr_len;
int sd;
- int sd2;
int rc;
- debug("entering test_bind()");
+ debug("entering test_bind_unix()");
UNLINK(TEST_SUN_PATH);
memset(&addr, '\0', sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- debug("Test bind() success");
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("bind() should have worked");
- }
-
- debug("Test getsockname() success");
-
- memset(&sock_addr, '\0', sizeof(struct sockaddr_un));
- sock_addr_len = sizeof(struct sockaddr_un);
-
- rc = getsockname(sd, (struct sockaddr *) &sock_addr, &sock_addr_len);
- if (rc == -1) {
- test_fail("getsockname() should have worked");
- }
-
- if (!(sock_addr.sun_family == AF_UNIX &&
- strncmp(sock_addr.sun_path,
- fullpath(TEST_SUN_PATH),
- sizeof(sock_addr.sun_path) - 1) == 0)) {
-
- test_fail("getsockname() didn't return the right addr");
- fprintf(stderr, "exp: '%s' | got: '%s'\n", addr.sun_path,
- sock_addr.sun_path);
- }
-
- debug("Test bind() with a address that has already been bind()'d");
-
- SOCKET(sd2, PF_UNIX, SOCK_STREAM, 0);
- errno = 0;
- rc = bind(sd2, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (!((rc == -1) && (errno == EADDRINUSE))) {
- test_fail("bind() should have failed with EADDRINUSE");
- }
- CLOSE(sd2);
- CLOSE(sd);
- UNLINK(TEST_SUN_PATH);
-
debug("Test bind() with an empty sun_path");
SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
}
CLOSE(sd);
- debug("Test bind() with a NULL address");
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- errno = 0;
- rc = bind(sd, (struct sockaddr *) NULL, sizeof(struct sockaddr_un));
- if (!((rc == -1) && (errno == EFAULT))) {
- test_fail("bind() should have failed with EFAULT");
- }
- CLOSE(sd);
-
debug("Test bind() using a symlink loop");
UNLINK(TEST_SUN_PATH);
CLOSE(sd);
UNLINK("foo");
- debug("leaving test_bind()");
+ debug("leaving test_bind_unix()");
}
-static void test_listen(void)
-{
- int rc;
+static void callback_xfer_prepclient(void) {
+ debug("Creating symlink to TEST_SUN_PATH");
- debug("entering test_listen()");
+ SYMLINK(TEST_SUN_PATH, TEST_SYM_A);
+}
- debug("Test listen() with a bad file descriptor");
+static void callback_xfer_peercred(int sd) {
+ struct uucred credentials;
+ int rc;
+ socklen_t ucred_length;
- errno = 0;
- rc = listen(-1, 0);
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("listen(-1, 0) should have failed");
- }
+ ucred_length = sizeof(struct uucred);
- debug("Test listen() with a non-socket file descriptor");
+ debug("Test passing the client credentials to the server");
- errno = 0;
- rc = listen(0, 0);
- /* Test on errno disabled here: there's currently no telling what this
- * will return. POSIX says it should be ENOTSOCK, MINIX3 libc returns
- * ENOSYS, and we used to test for ENOTTY here..
- */
- if (!(rc == -1)) {
- test_fail("listen(0, 0) should have failed");
- }
+ memset(&credentials, '\0', ucred_length);
+ rc = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &credentials,
+ &ucred_length);
- debug("leaving test_listen()");
+ if (rc == -1) {
+ test_fail("[client] getsockopt() failed");
+ } else if (credentials.cr_uid != geteuid() ||
+ credentials.cr_gid != getegid()) {
+ printf("%d=%d=%d %d=%d=%d\n", credentials.cr_uid, getuid(),
+ geteuid(), credentials.cr_gid, getgid(), getegid());
+ test_fail("[client] Credential passing gave us a bad UID/GID");
+ }
}
-static void test_shutdown(void)
+static void test_vectorio(int type)
{
- int how[3] = { SHUT_RD, SHUT_WR, SHUT_RDWR };
- int sd;
+ int sv[2];
int rc;
- int i;
-
- debug("entering test_shutdown()");
-
- /* test for each direction (read, write, read-write) */
- for (i = 0; i < 3; i++) {
-
- debug("test shutdown() with an invalid descriptor");
-
- errno = 0;
- rc = shutdown(-1, how[i]);
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("shutdown(-1, how[i]) should have failed");
- }
+ struct iovec iov[3];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+ char buf4[BUFSIZE*3];
+ const struct iovec *iovp = iov;
- debug("test shutdown() with a non-socket descriptor");
+ debug("begin vectorio tests");
- errno = 0;
- rc = shutdown(0, how[i]);
- if (!(rc == -1 && errno == ENOSYS)) {
- test_fail("shutdown() should have failed with ENOSYS");
- }
+ memset(buf1, '\0', BUFSIZE);
+ strncpy(buf1, "HELLO ", BUFSIZE - 1);
- debug("test shutdown() with a socket that is not connected");
+ memset(buf2, '\0', BUFSIZE);
+ strncpy(buf2, "WORLD", BUFSIZE - 1);
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- errno = 0;
- rc = shutdown(sd, how[i]);
- if (!(rc == -1 && errno == ENOTCONN)) {
- test_fail("shutdown() should have failed");
- }
- CLOSE(sd);
- }
+ memset(buf3, '\0', BUFSIZE);
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- errno = 0;
- rc = shutdown(sd, -1);
- if (!(rc == -1 && errno == ENOTCONN)) {
- test_fail("shutdown(sd, -1) should have failed with ENOTCONN");
+ rc = socketpair(PF_UNIX, type, 0, sv);
+ if (rc == -1) {
+ test_fail("socketpair");
}
- CLOSE(sd);
-
- debug("leaving test_shutdown()");
-}
-
-static void test_close(void)
-{
- struct sockaddr_un addr;
- int sd, sd2;
- int rc, i;
-
- debug("entering test_close()");
- UNLINK(TEST_SUN_PATH);
+ iov[0].iov_base = buf1;
+ iov[0].iov_len = strlen(buf1);
+ iov[1].iov_base = buf2;
+ iov[1].iov_len = strlen(buf2);
+ iov[2].iov_base = buf3;
+ iov[2].iov_len = 1;
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
+ rc = writev(sv[0], iovp, 3);
+ if (rc == -1) {
+ test_fail("writev");
+ }
- debug("Test close() success");
+ memset(buf4, '\0', BUFSIZE*3);
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc != 0) {
- test_fail("bind() should have worked");
+ rc = read(sv[1], buf4, BUFSIZE*3);
+ if (rc == -1) {
+ test_fail("read");
}
- CLOSE(sd);
+ if (strncmp(buf4, "HELLO WORLD", strlen("HELLO WORLD"))) {
+ test_fail("the string we read was not 'HELLO WORLD'");
+ }
- debug("Close an already closed file descriptor");
+ memset(buf1, '\0', BUFSIZE);
+ strncpy(buf1, "Unit Test Time", BUFSIZE - 1);
- errno = 0;
- rc = close(sd);
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("close(sd) should have failed with EBADF");
+ rc = write(sv[1], buf1, strlen(buf1) + 1);
+ if (rc == -1) {
+ test_fail("write");
}
- UNLINK(TEST_SUN_PATH);
+ memset(buf2, '\0', BUFSIZE);
+ memset(buf3, '\0', BUFSIZE);
+ memset(buf4, '\0', BUFSIZE*3);
- debug("dup()'ing a file descriptor and closing both should work");
+ iov[0].iov_base = buf2;
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf3;
+ iov[1].iov_len = 5;
+ iov[2].iov_base = buf4;
+ iov[2].iov_len = 32;
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc != 0) {
- test_fail("bind() should have worked");
+ rc = readv(sv[0], iovp, 3);
+ if (rc == -1) {
+ test_fail("readv");
}
- errno = 0;
- sd2 = dup(sd);
- if (sd2 == -1) {
- test_fail("dup(sd) should have worked");
- } else {
- CLOSE(sd2);
- CLOSE(sd);
+ if (strncmp(buf2, "Unit ", 5) || strncmp(buf3, "Test ", 5) ||
+ strncmp(buf4, "Time", 4)) {
+ test_fail("readv");
}
- UNLINK(TEST_SUN_PATH);
+ rc = close(sv[0]);
+ if (rc == -1) {
+ test_fail("close");
+ }
- /* Create and close a socket a bunch of times.
- * If the implementation doesn't properly free the
- * socket during close(), eventually socket() will
- * fail when the internal descriptor table is full.
- */
- for (i = 0; i < 1024; i++) {
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- CLOSE(sd);
+ rc = close(sv[1]);
+ if (rc == -1) {
+ test_fail("close");
}
- debug("leaving test_close()");
+ debug("done vector io tests");
}
-static void test_sockopts(void)
+static void test_msg(int type)
{
- int i;
- int rc;
- int sd;
- int option_value;
- socklen_t option_len;
-
- debug("entering test_sockopts()");
-
- for (i = 0; i < 3; i++) {
-
- SOCKET(sd, PF_UNIX, types[i], 0);
-
- debug("Test setsockopt() works");
-
- option_value = 0;
- option_len = sizeof(option_value);
- errno = 0;
- rc = getsockopt(sd, SOL_SOCKET, SO_TYPE, &option_value,
- &option_len);
- if (rc != 0) {
- test_fail("setsockopt() should have worked");
- }
-
- if (option_value != types[i]) {
- test_fail("SO_TYPE didn't seem to work.");
- }
-
- CLOSE(sd);
- }
-
-
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
-
- debug("Test setsockopt() works");
-
- option_value = 0;
- option_len = sizeof(option_value);
- errno = 0;
- rc = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &option_value, &option_len);
- if (rc != 0) {
- test_fail("getsockopt() should have worked");
- }
-
- if (option_value != PIPE_BUF) {
- test_fail("SO_SNDBUF didn't seem to work.");
- }
-
- CLOSE(sd);
-
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
-
- debug("Test setsockopt() works");
-
- option_value = 0;
- option_len = sizeof(option_value);
- errno = 0;
- rc = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &option_value, &option_len);
- if (rc != 0) {
- test_fail("getsockopt() should have worked");
- }
-
- if (option_value != PIPE_BUF) {
- test_fail("SO_RCVBUF didn't seem to work.");
- }
-
- CLOSE(sd);
-
-
- debug("leaving test_sockopts()");
-}
-
-static void test_read(void)
-{
- int rc;
- int fd;
- char buf[BUFSIZE];
-
- debug("entering test_read()");
-
- errno = 0;
- rc = read(-1, buf, sizeof(buf));
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("read() should have failed with EBADF");
- }
-
- fd = open("/tmp", O_RDONLY);
- if (fd == -1) {
- test_fail("open(\"/tmp\", O_RDONLY) should have worked");
- }
-
- CLOSE(fd);
-
- debug("leaving test_read()");
-}
-
-static void test_write(void)
-{
- int rc;
- char buf[BUFSIZE];
-
- debug("entering test_write()");
-
- errno = 0;
- rc = write(-1, buf, sizeof(buf));
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("write() should have failed with EBADF");
- }
-
- debug("leaving test_write()");
-}
-
-static void test_dup(void)
-{
- struct stat info1;
- struct stat info2;
- struct sockaddr_un addr;
- int sd, sd2;
- int rc;
- int i;
-
- debug("entering test_dup()");
-
- UNLINK(TEST_SUN_PATH);
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- debug("Test dup()");
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc != 0) {
- test_fail("bind() should have worked");
- }
-
- errno = 0;
- sd2 = dup(sd);
- if (sd2 == -1) {
- test_fail("dup(sd) should have worked");
- }
-
- rc = fstat(sd, &info1);
- if (rc == -1) {
- test_fail("fstat(fd, &info1) failed");
- }
-
- rc = fstat(sd2, &info2);
- if (rc == -1) {
- test_fail("fstat(sd, &info2) failed");
- }
-
- if (info1.st_ino != info2.st_ino) {
- test_fail("dup() failed info1.st_ino != info2.st_ino");
- }
-
- CLOSE(sd);
- CLOSE(sd2);
-
- debug("Test dup() with a closed socket");
-
- errno = 0;
- rc = dup(sd);
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("dup(sd) on a closed socket shouldn't have worked");
- }
-
- debug("Test dup() with socket descriptor of -1");
-
- errno = 0;
- rc = dup(-1);
- if (!(rc == -1 && errno == EBADF)) {
- test_fail("dup(-1) shouldn't have worked");
- }
-
- debug("Test dup() when all of the file descriptors are taken");
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
-
- for (i = 4; i < getdtablesize(); i++) {
- rc = open("/dev/null", O_RDONLY);
- if (rc == -1) {
- test_fail("we couldn't open /dev/null for read");
- }
- }
-
- errno = 0;
- sd2 = dup(sd);
- if (!(sd2 == -1 && errno == EMFILE)) {
- test_fail("dup(sd) should have failed with errno = EMFILE");
- }
-
- for (i = 3; i < getdtablesize(); i++) {
- CLOSE(i);
- }
-
- UNLINK(TEST_SUN_PATH);
-
- debug("leaving test_dup()");
-}
-
-static void test_dup2(void)
-{
- struct stat info1;
- struct stat info2;
- struct sockaddr_un addr;
- int sd;
- int fd;
- int rc;
-
- debug("entering test_dup2()");
- UNLINK(TEST_SUN_PATH);
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
-
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc != 0) {
- test_fail("bind() should have worked");
- }
-
- fd = open("/dev/null", O_RDONLY);
- if (fd == -1) {
- test_fail("open(\"/dev/null\", O_RDONLY) failed");
- }
-
- fd = dup2(sd, fd);
- if (fd == -1) {
- test_fail("dup2(sd, fd) failed.");
- }
-
- memset(&info1, '\0', sizeof(struct stat));
- memset(&info2, '\0', sizeof(struct stat));
-
- rc = fstat(fd, &info1);
- if (rc == -1) {
- test_fail("fstat(fd, &info1) failed");
- }
-
- rc = fstat(sd, &info2);
- if (rc == -1) {
- test_fail("fstat(sd, &info2) failed");
- }
-
- if (!(info1.st_ino == info2.st_ino &&
- major(info1.st_dev) == major(info2.st_dev) &&
- minor(info1.st_dev) == minor(info2.st_dev))) {
-
- test_fail("dup2() failed");
- }
-
- CLOSE(fd);
- CLOSE(sd);
-
- UNLINK(TEST_SUN_PATH);
- debug("leaving test_dup2()");
-
-}
-
-/*
- * A toupper() server. This toy server converts a string to upper case.
- */
-static void test_xfer_server(pid_t pid)
-{
- int i;
- struct timeval tv;
- fd_set readfds;
- int status;
- int rc;
- int sd;
- unsigned char buf[BUFSIZE];
- socklen_t client_addr_size;
- int client_sd;
- struct sockaddr_un addr;
- struct sockaddr_un client_addr;
-
- status = 0;
- rc = 0;
- sd = 0;
- client_sd = 0;
- client_addr_size = sizeof(struct sockaddr_un);
-
- memset(&buf, '\0', sizeof(buf));
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- memset(&client_addr, '\0', sizeof(struct sockaddr_un));
-
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
-
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("bind() should have worked");
- }
-
- rc = listen(sd, 8);
- if (rc == -1) {
- test_fail("listen(sd, 8) should have worked");
- }
-
- /* we're ready for connections, time to tell the client to start
- * the test
- */
- kill(pid, SIGUSR1);
-
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- FD_ZERO(&readfds);
- FD_SET(sd, &readfds);
-
- /* use select() in case the client is really broken and never
- * attempts to connect (we don't want to block on accept()
- * forever).
- */
- rc = select(sd + 1, &readfds, NULL, NULL, &tv);
- if (rc == -1) {
- test_fail("[server] select() should not have failed");
- }
-
- if (rc != 1) {
- test_fail("[server] select() should have returned 1");
- printf("[server] select returned %d\n", rc);
- }
-
- if (!(FD_ISSET(sd, &readfds))) {
- test_fail("[server] client didn't connect within 10 seconds");
- kill(pid, SIGKILL);
- return;
- }
-
- client_sd = accept(sd, (struct sockaddr *) &client_addr,
- &client_addr_size);
-
- if (client_sd == -1) {
- test_fail("accept() should have worked");
- kill(pid, SIGKILL);
- return;
- } else {
- debug("[server] client accept()'d");
- }
-
- debug("[server] Reading message");
- rc = read(client_sd, buf, sizeof(buf));
- if (rc == -1) {
- test_fail("read() failed unexpectedly");
- kill(pid, SIGKILL);
- return;
- }
- debug("[server] we got the following message:");
- debug(buf);
-
- for (i = 0; i < rc && i < 127; i++) {
- buf[i] = toupper(buf[i]);
- }
-
- debug("[server] Writing message...");
- rc = write(client_sd, buf, sizeof(buf));
- if (rc == -1) {
- test_fail("write(client_sd, buf, sizeof(buf)) failed");
- kill(pid, SIGKILL);
- return;
- }
-
- if (rc < strlen(buf)) {
- test_fail("[server] write didn't write all the bytes");
- }
-
- memset(&buf, '\0', sizeof(buf));
-
- debug("[server] Recv message");
- rc = recv(client_sd, buf, sizeof(buf), 0);
- if (rc == -1) {
- test_fail("recv() failed unexpectedly");
- kill(pid, SIGKILL);
- return;
- }
- debug("[server] we got the following message:");
- debug(buf);
-
- for (i = 0; i < rc && i < 127; i++) {
- buf[i] = toupper(buf[i]);
- }
-
- debug("[server] Sending message...");
- rc = send(client_sd, buf, sizeof(buf), 0);
- if (rc == -1) {
- test_fail("send(client_sd, buf, sizeof(buf), 0) failed");
- kill(pid, SIGKILL);
- return;
- }
-
- if (rc < strlen(buf)) {
- test_fail("[server] write didn't write all the bytes");
- }
-
- memset(&buf, '\0', sizeof(buf));
-
- debug("[server] Recvfrom message");
- rc = recvfrom(client_sd, buf, sizeof(buf), 0, NULL, 0);
- if (rc == -1) {
- test_fail("recvfrom() failed unexpectedly");
- kill(pid, SIGKILL);
- return;
- }
- debug("[server] we got the following message:");
- debug(buf);
-
- for (i = 0; i < rc && i < 127; i++) {
- buf[i] = toupper(buf[i]);
- }
-
- debug("[server] Sendto message...");
- rc = sendto(client_sd, buf, sizeof(buf), 0, NULL, 0);
- if (rc == -1) {
- test_fail("sendto() failed");
- kill(pid, SIGKILL);
- return;
- }
-
- if (rc < strlen(buf)) {
- test_fail("[server] write didn't write all the bytes");
- }
-
- shutdown(client_sd, SHUT_RDWR);
- CLOSE(client_sd);
-
- shutdown(sd, SHUT_RDWR);
- CLOSE(sd);
-
- /* wait for client to exit */
- do {
- errno = 0;
- rc = waitpid(pid, &status, 0);
- } while (rc == -1 && errno == EINTR);
-
- /* we use the exit status to get its error count */
- errct += WEXITSTATUS(status);
-}
-
-static int server_ready = 0;
-
-/* signal handler for the client */
-static void test_xfer_sighdlr(int sig)
-{
- debug("entering signal handler");
- switch (sig) {
- /* the server will send SIGUSR1 when it is time for us
- * to start the tests
- */
- case SIGUSR1:
- server_ready = 1;
- debug("got SIGUSR1, the server is ready for the client");
- break;
- default:
- debug("didn't get SIGUSR1");
- }
- debug("leaving signal handler");
-}
-
-/*
- * A toupper() client.
- */
-static void test_xfer_client(void)
-{
- struct uucred credentials;
- socklen_t ucred_length;
- struct timeval tv;
- fd_set readfds;
- struct sockaddr_un addr;
- struct sockaddr_un peer_addr;
- socklen_t peer_addr_len;
- int sd;
- int rc;
- char buf[BUFSIZE];
-
- debug("[client] entering test_xfer_client()");
- errct = 0; /* reset error count */
- ucred_length = sizeof(struct uucred);
- memset(&buf, '\0', sizeof(buf));
-
- while (server_ready == 0) {
- debug("[client] waiting for the server to signal");
- sleep(1);
- }
-
- peer_addr_len = sizeof(struct sockaddr_un);
-
-
- debug("Creating symlink to TEST_SUN_PATH");
-
- SYMLINK(TEST_SUN_PATH, TEST_SYM_A);
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- strncpy(addr.sun_path, TEST_SYM_A, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- debug("[client] creating client socket");
- SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
-
- debug("[client] connecting to server through the symlink");
- rc = connect(sd, (struct sockaddr *) &addr,
- sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("[client] connect() should have worked");
- } else {
- debug("[client] connected");
- }
-
- debug("[client] testing getpeername()");
- memset(&peer_addr, '\0', sizeof(struct sockaddr_un));
- rc = getpeername(sd, (struct sockaddr *) &peer_addr, &peer_addr_len);
- if (rc == -1) {
- test_fail("[client] getpeername() should have worked");
- }
-
- /* we need to use the full path "/usr/src/test/DIR_56/test.sock"
- * because that is what is returned by getpeername().
- */
-
- if (!(peer_addr.sun_family == AF_UNIX &&
- strncmp(peer_addr.sun_path,
- fullpath(TEST_SUN_PATH),
- sizeof(peer_addr.sun_path) - 1) == 0)) {
-
- test_fail("getpeername() didn't return the right address");
- }
-
- strncpy(buf, "Hello, World!", sizeof(buf) - 1);
- debug("[client] send to server");
- rc = write(sd, buf, sizeof(buf));
- if (rc == -1) {
- test_fail("[client] write() failed unexpectedly");
- }
-
- memset(buf, '\0', sizeof(buf));
- debug("[client] read from server");
- rc = read(sd, buf, sizeof(buf));
- if (rc == -1) {
- test_fail("[client] read() failed unexpectedly");
- } else {
- debug("[client] we got the following message:");
- debug(buf);
- }
-
- if (strncmp(buf, "HELLO, WORLD!", sizeof(buf)) != 0) {
- test_fail("[client] We didn't get the correct response");
- }
-
- memset(&buf, '\0', sizeof(buf));
- strncpy(buf, "Bonjour!", sizeof(buf) - 1);
-
- debug("[client] send to server");
- rc = send(sd, buf, sizeof(buf), 0);
- if (rc == -1) {
- test_fail("[client] send() failed unexpectedly");
- }
-
- debug("Test passing the client credentials to the server");
-
- memset(&credentials, '\0', ucred_length);
- rc = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &credentials,
- &ucred_length);
-
- if (rc == -1) {
- test_fail("[client] getsockopt() failed");
- } else if (credentials.cr_uid != geteuid() ||
- credentials.cr_gid != getegid()) {
- printf("%d=%d=%d %d=%d=%d\n", credentials.cr_uid, getuid(),
- geteuid(), credentials.cr_gid, getgid(), getegid());
- test_fail("[client] Credential passing gave us a bad UID/GID");
- }
-
- debug("Testing select()");
-
- tv.tv_sec = 2;
- tv.tv_usec = 500000;
-
- FD_ZERO(&readfds);
- FD_SET(sd, &readfds);
-
- rc = select(sd + 1, &readfds, NULL, NULL, &tv);
- if (rc == -1) {
- test_fail("[client] select() should not have failed");
- }
-
- if (rc != 1) {
- test_fail("[client] select() should have returned 1");
- }
-
- if (!(FD_ISSET(sd, &readfds))) {
- test_fail("The server didn't respond within 2.5 seconds");
- }
-
- memset(buf, '\0', sizeof(buf));
- debug("[client] recv from server");
- rc = recv(sd, buf, sizeof(buf), 0);
- if (rc == -1) {
- test_fail("[client] recv() failed unexpectedly");
- } else {
- debug("[client] we got the following message:");
- debug(buf);
- }
-
- if (strncmp(buf, "BONJOUR!", sizeof(buf)) != 0) {
- test_fail("[client] We didn't get the right response.");
- }
-
- memset(&buf, '\0', sizeof(buf));
- strncpy(buf, "Hola!", sizeof(buf) - 1);
-
- debug("[client] sendto to server");
- rc = sendto(sd, buf, sizeof(buf), 0, NULL, 0);
- if (rc == -1) {
- test_fail("[client] sendto() failed");
- }
-
- debug("Testing select()");
-
- tv.tv_sec = 2;
- tv.tv_usec = 500000;
-
- FD_ZERO(&readfds);
- FD_SET(sd, &readfds);
-
- rc = select(sd + 1, &readfds, NULL, NULL, &tv);
- if (rc == -1) {
- test_fail("[client] select() should not have failed");
- }
-
- if (rc != 1) {
- test_fail("[client] select() should have returned 1");
- }
-
- if (!(FD_ISSET(sd, &readfds))) {
- test_fail("[client] The server didn't respond in 2.5 seconds");
- }
-
- memset(buf, '\0', sizeof(buf));
- debug("[client] recvfrom from server");
- rc = recvfrom(sd, buf, sizeof(buf), 0, NULL, 0);
- if (rc == -1) {
- test_fail("[cleint] recvfrom() failed unexpectedly");
- } else {
- debug("[client] we got the following message:");
- debug(buf);
- }
-
- if (strncmp(buf, "HOLA!", sizeof(buf)) != 0) {
- test_fail("[client] We didn't get the right response.");
- }
-
- debug("[client] closing socket");
- CLOSE(sd);
-
- debug("[client] leaving test_xfer_client()");
- exit(errct);
-}
-
-static void test_xfer(void)
-{
- pid_t pid;
-
- UNLINK(TEST_SYM_A);
- UNLINK(TEST_SUN_PATH);
-
- /* the signal handler is only used by the client, but we have to
- * install it now. if we don't the server may signal the client
- * before the handler is installed.
- */
- debug("installing signal handler");
- if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
- test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
- }
-
- debug("signal handler installed");
-
- server_ready = 0;
-
- pid = fork();
- if (pid == -1) {
- test_fail("fork() failed");
- return;
- } else if (pid == 0) {
- debug("child");
- test_xfer_client();
- test_fail("we should never get here");
- exit(1);
- } else {
- debug("parent");
- test_xfer_server(pid);
- debug("parent done");
- }
-
- UNLINK(TEST_SYM_A);
- UNLINK(TEST_SUN_PATH);
-}
-
-static void test_simple_client(int type)
-{
- char buf[BUFSIZE];
- int sd, rc;
- struct sockaddr_un addr;
-
- sd = socket(PF_UNIX, type, 0);
- if (sd == -1) {
- test_fail("socket");
- exit(errct);
- }
-
- while (server_ready == 0) {
- debug("[client] waiting for the server");
- sleep(1);
- }
-
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- bzero(buf, BUFSIZE);
- snprintf(buf, BUFSIZE-1, "Hello, My Name is Client.");
-
- if (type == SOCK_DGRAM) {
-
- rc = sendto(sd, buf, strlen(buf) + 1, 0,
- (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("sendto");
- exit(errct);
- }
-
- } else {
-
- rc = connect(sd, (struct sockaddr *) &addr,
- sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("connect");
- exit(errct);
- }
-
- rc = write(sd, buf, strlen(buf) + 1);
-
- if (rc == -1) {
- test_fail("write");
- }
-
- memset(buf, '\0', BUFSIZE);
- rc = read(sd, buf, BUFSIZE);
- if (rc == -1) {
- test_fail("read");
- }
-
- if (strcmp("Hello, My Name is Server.", buf) != 0) {
- test_fail("didn't read the correct string");
- }
- }
-
- rc = close(sd);
- if (rc == -1) {
- test_fail("close");
- }
-
- exit(errct);
-}
-
-static void test_simple_server(int type, pid_t pid)
-{
- char buf[BUFSIZE];
- int sd, rc, client_sd, status;
- struct sockaddr_un addr;
- socklen_t addr_len;
-
- addr_len = sizeof(struct sockaddr_un);
-
- sd = socket(PF_UNIX, type, 0);
- if (sd == -1) {
- test_fail("socket");
- }
-
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("bind");
- }
-
- if (type == SOCK_DGRAM) {
-
- /* ready for client */
- kill(pid, SIGUSR1);
-
- rc = recvfrom(sd, buf, BUFSIZE, 0,
- (struct sockaddr *) &addr, &addr_len);
- if (rc == -1) {
- test_fail("recvfrom");
- }
-
- } else {
-
- rc = listen(sd, 5);
- if (rc == -1) {
- test_fail("listen");
- }
-
- /* we're ready for connections, time to tell the client
- * to start the test
- */
- kill(pid, SIGUSR1);
-
- client_sd = accept(sd, (struct sockaddr *) &addr, &addr_len);
- if (client_sd == -1) {
- test_fail("accept");
- }
-
- memset(buf, '\0', BUFSIZE);
- rc = read(client_sd, buf, BUFSIZE);
- if (rc == -1) {
- test_fail("read");
- }
-
- if (strcmp("Hello, My Name is Client.", buf) != 0) {
- test_fail("didn't read the correct string");
- }
-
- /* added for extra fun to make the client block on read() */
- sleep(1);
-
- bzero(buf, BUFSIZE);
- snprintf(buf, BUFSIZE-1, "Hello, My Name is Server.");
-
- rc = write(client_sd, buf, strlen(buf) + 1);
- if (rc == -1) {
- test_fail("write");
- }
- rc = close(client_sd);
- if (rc == -1) {
- test_fail("close");
- }
- }
-
- rc = close(sd);
- if (rc == -1) {
- test_fail("close");
- }
-
- /* wait for client to exit */
- do {
- errno = 0;
- rc = waitpid(pid, &status, 0);
- } while (rc == -1 && errno == EINTR);
-
- /* we use the exit status to get its error count */
- errct += WEXITSTATUS(status);
-}
-
-static void test_abort_client_server(int abort_type)
-{
- pid_t pid;
- debug("test_simple_client_server()");
-
- UNLINK(TEST_SUN_PATH);
-
- /* the signal handler is only used by the client, but we have to
- * install it now. if we don't the server may signal the client
- * before the handler is installed.
- */
- debug("installing signal handler");
- if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
- test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
- }
-
- debug("signal handler installed");
-
- server_ready = 0;
-
- pid = fork();
- if (pid == -1) {
- test_fail("fork() failed");
- return;
- } else if (pid == 0) {
- debug("child");
- test_abort_client(abort_type);
- test_fail("we should never get here");
- exit(1);
- } else {
- debug("parent");
- test_abort_server(pid, abort_type);
- debug("parent done");
- }
-
- UNLINK(TEST_SUN_PATH);
-}
-
-static void test_abort_client(int abort_type)
-{
- char buf[BUFSIZE];
- int sd, rc;
- struct sockaddr_un addr;
-
- sd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (sd == -1) {
- test_fail("socket");
- exit(errct);
- }
-
- while (server_ready == 0) {
- debug("[client] waiting for the server");
- sleep(1);
- }
-
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- bzero(buf, BUFSIZE);
- snprintf(buf, BUFSIZE-1, "Hello, My Name is Client.");
-
- rc = connect(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("connect");
- exit(errct);
- }
-
- if (abort_type == 2) {
- /* Give server a chance to close connection */
- sleep(2);
- rc = write(sd, buf, strlen(buf) + 1);
- if (rc != -1) {
- test_fail("write should have failed\n");
- }
- if (errno != ECONNRESET) {
- test_fail("errno should've been ECONNRESET\n");
- }
- }
-
- rc = close(sd);
- if (rc == -1) {
- test_fail("close");
- }
-
- exit(errct);
-}
-
-static void test_abort_server(pid_t pid, int abort_type)
-{
- char buf[BUFSIZE];
- int sd, rc, client_sd, status;
- struct sockaddr_un addr;
- socklen_t addr_len;
-
- addr_len = sizeof(struct sockaddr_un);
-
- sd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (sd == -1) {
- test_fail("socket");
- }
-
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- addr.sun_family = AF_UNIX;
-
- rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
- if (rc == -1) {
- test_fail("bind");
- }
-
- rc = listen(sd, 5);
- if (rc == -1) {
- test_fail("listen");
- }
-
- /* we're ready for connections, time to tell the client
- * to start the test
- */
- kill(pid, SIGUSR1);
-
- client_sd = accept(sd, (struct sockaddr *) &addr, &addr_len);
- if (client_sd == -1) {
- test_fail("accept");
- }
-
- if (abort_type == 1) {
- memset(buf, '\0', BUFSIZE);
- rc = read(client_sd, buf, BUFSIZE);
- if (rc != -1) {
- test_fail("read should've failed\n");
- }
- if (errno != ECONNRESET) {
- test_fail("errno should've been ECONNRESET\n");
- }
- } /* else if (abort_type == 2) { */
- rc = close(client_sd);
- if (rc == -1) {
- test_fail("close");
- }
- /* } */
-
- rc = close(sd);
- if (rc == -1) {
- test_fail("close");
- }
-
- /* wait for client to exit */
- do {
- errno = 0;
- rc = waitpid(pid, &status, 0);
- } while (rc == -1 && errno == EINTR);
-
- /* we use the exit status to get its error count */
- errct += WEXITSTATUS(status);
-}
-
-static void test_simple_client_server(int type)
-{
- pid_t pid;
- debug("test_simple_client_server()");
-
- UNLINK(TEST_SUN_PATH);
-
- /* the signal handler is only used by the client, but we have to
- * install it now. if we don't the server may signal the client
- * before the handler is installed.
- */
- debug("installing signal handler");
- if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
- test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
- }
-
- debug("signal handler installed");
-
- server_ready = 0;
-
- pid = fork();
- if (pid == -1) {
- test_fail("fork() failed");
- return;
- } else if (pid == 0) {
- debug("child");
- test_simple_client(type);
- test_fail("we should never get here");
- exit(1);
- } else {
- debug("parent");
- test_simple_server(type, pid);
- debug("parent done");
- }
-
- UNLINK(TEST_SUN_PATH);
-}
-
-static void test_vectorio(int type)
-{
- int sv[2];
- int rc;
- struct iovec iov[3];
- char buf1[BUFSIZE];
- char buf2[BUFSIZE];
- char buf3[BUFSIZE];
- char buf4[BUFSIZE*3];
- const struct iovec *iovp = iov;
-
- debug("begin vectorio tests");
-
- memset(buf1, '\0', BUFSIZE);
- strncpy(buf1, "HELLO ", BUFSIZE - 1);
-
- memset(buf2, '\0', BUFSIZE);
- strncpy(buf2, "WORLD", BUFSIZE - 1);
-
- memset(buf3, '\0', BUFSIZE);
-
- rc = socketpair(PF_UNIX, type, 0, sv);
- if (rc == -1) {
- test_fail("socketpair");
- }
-
- iov[0].iov_base = buf1;
- iov[0].iov_len = strlen(buf1);
- iov[1].iov_base = buf2;
- iov[1].iov_len = strlen(buf2);
- iov[2].iov_base = buf3;
- iov[2].iov_len = 1;
-
- rc = writev(sv[0], iovp, 3);
- if (rc == -1) {
- test_fail("writev");
- }
-
- memset(buf4, '\0', BUFSIZE*3);
-
- rc = read(sv[1], buf4, BUFSIZE*3);
- if (rc == -1) {
- test_fail("read");
- }
-
- if (strncmp(buf4, "HELLO WORLD", strlen("HELLO WORLD"))) {
- test_fail("the string we read was not 'HELLO WORLD'");
- }
-
- memset(buf1, '\0', BUFSIZE);
- strncpy(buf1, "Unit Test Time", BUFSIZE - 1);
-
- rc = write(sv[1], buf1, strlen(buf1) + 1);
- if (rc == -1) {
- test_fail("write");
- }
-
- memset(buf2, '\0', BUFSIZE);
- memset(buf3, '\0', BUFSIZE);
- memset(buf4, '\0', BUFSIZE*3);
-
- iov[0].iov_base = buf2;
- iov[0].iov_len = 5;
- iov[1].iov_base = buf3;
- iov[1].iov_len = 5;
- iov[2].iov_base = buf4;
- iov[2].iov_len = 32;
-
- rc = readv(sv[0], iovp, 3);
- if (rc == -1) {
- test_fail("readv");
- }
-
- if (strncmp(buf2, "Unit ", 5) || strncmp(buf3, "Test ", 5) ||
- strncmp(buf4, "Time", 4)) {
- test_fail("readv");
- }
-
- rc = close(sv[0]);
- if (rc == -1) {
- test_fail("close");
- }
-
- rc = close(sv[1]);
- if (rc == -1) {
- test_fail("close");
- }
-
- debug("done vector io tests");
-}
-
-static void test_msg(int type)
-{
- int sv[2];
+ int sv[2];
int rc;
struct msghdr msg1;
struct msghdr msg2;
msg2.msg_controllen = 0;
msg2.msg_flags = 0;
- rc = recvmsg(sv[0], &msg2, 0);
- if (rc == -1) {
- test_fail("readv");
- }
-
- if (strncmp(buf2, "Unit ", 5) || strncmp(buf3, "Test ", 5) ||
- strncmp(buf4, "Time", 4)) {
- test_fail("readv");
- }
-
- rc = close(sv[0]);
- if (rc == -1) {
- test_fail("close");
- }
-
- rc = close(sv[1]);
- if (rc == -1) {
- test_fail("close");
- }
-}
-
-static void test_msg_dgram(void)
-{
- int rc;
- int src;
- int dst;
- struct sockaddr_un addr;
- struct iovec iov[3];
- struct msghdr msg1;
- struct msghdr msg2;
- char buf1[BUFSIZE];
- char buf2[BUFSIZE];
- char buf3[BUFSIZE];
- socklen_t addrlen = sizeof(struct sockaddr_un);
-
- debug("test msg_dgram");
-
- UNLINK(TEST_SUN_PATH);
- UNLINK(TEST_SUN_PATHB);
-
- src = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (src == -1) {
- test_fail("socket");
- }
-
- dst = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (dst == -1) {
- test_fail("socket");
- }
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, TEST_SUN_PATHB, sizeof(addr.sun_path) - 1);
- rc = bind(src, (struct sockaddr *) &addr, addrlen);
- if (rc == -1) {
- test_fail("bind");
- }
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
-
- rc = bind(dst, (struct sockaddr *) &addr, addrlen);
- if (rc == -1) {
- test_fail("bind");
- }
-
- memset(&buf1, '\0', BUFSIZE);
- memset(&buf2, '\0', BUFSIZE);
- memset(&buf3, '\0', BUFSIZE);
-
- strncpy(buf1, "Minix ", BUFSIZE-1);
- strncpy(buf2, "is ", BUFSIZE-1);
- strncpy(buf3, "great!", BUFSIZE-1);
-
- iov[0].iov_base = buf1;
- iov[0].iov_len = 6;
- iov[1].iov_base = buf2;
- iov[1].iov_len = 3;
- iov[2].iov_base = buf3;
- iov[2].iov_len = 32;
-
- memset(&msg1, '\0', sizeof(struct msghdr));
- msg1.msg_name = &addr;
- msg1.msg_namelen = addrlen;
- msg1.msg_iov = iov;
- msg1.msg_iovlen = 3;
- msg1.msg_control = NULL;
- msg1.msg_controllen = 0;
- msg1.msg_flags = 0;
-
- rc = sendmsg(src, &msg1, 0);
- if (rc == -1) {
- test_fail("sendmsg");
- }
-
- memset(&buf1, '\0', BUFSIZE);
- memset(&buf2, '\0', BUFSIZE);
-
- iov[0].iov_base = buf1;
- iov[0].iov_len = 9;
- iov[1].iov_base = buf2;
- iov[1].iov_len = 32;
-
- memset(&addr, '\0', sizeof(struct sockaddr_un));
- memset(&msg2, '\0', sizeof(struct msghdr));
- msg2.msg_name = &addr;
- msg2.msg_namelen = sizeof(struct sockaddr_un);
- msg2.msg_iov = iov;
- msg2.msg_iovlen = 2;
- msg2.msg_control = NULL;
- msg2.msg_controllen = 0;
- msg2.msg_flags = 0;
-
- rc = recvmsg(dst, &msg2, 0);
- if (rc == -1) {
- test_fail("recvmsg");
- }
-
- if (strncmp(buf1, "Minix is ", 9) || strncmp(buf2, "great!", 6)) {
- test_fail("recvmsg");
+ rc = recvmsg(sv[0], &msg2, 0);
+ if (rc == -1) {
+ test_fail("readv");
}
- /* we need to use the full path "/usr/src/test/DIR_56/testb.sock"
- * because that is what is returned by recvmsg().
- */
- if (addr.sun_family != AF_UNIX || strcmp(addr.sun_path,
- fullpath(TEST_SUN_PATHB))) {
- test_fail("recvmsg");
+ if (strncmp(buf2, "Unit ", 5) || strncmp(buf3, "Test ", 5) ||
+ strncmp(buf4, "Time", 4)) {
+ test_fail("readv");
}
- rc = close(dst);
+ rc = close(sv[0]);
if (rc == -1) {
test_fail("close");
}
- rc = close(src);
+ rc = close(sv[1]);
if (rc == -1) {
test_fail("close");
}
-
- UNLINK(TEST_SUN_PATH);
- UNLINK(TEST_SUN_PATHB);
}
static void test_scm_credentials(void)
UNLINK(TEST_SUN_PATHB);
}
-static void test_connect(void)
+static void test_connect(const struct socket_test_info *info)
{
int i, sd, sds[2], rc;
}
for (i = 0; i < 3; i++) {
- test_simple_client_server(types[i]);
+ test_simple_client_server(info, types[i]);
}
rc = close(sds[1]);
close(socks[1]);
}
-static void
-check_select(int sd, int rd, int wr, int block)
-{
- fd_set read_set, write_set;
- struct timeval tv;
-
- FD_ZERO(&read_set);
- if (rd != -1)
- FD_SET(sd, &read_set);
-
- FD_ZERO(&write_set);
- if (wr != -1)
- FD_SET(sd, &write_set);
-
- tv.tv_sec = block ? 2 : 0;
- tv.tv_usec = 0;
-
- if (select(sd + 1, &read_set, &write_set, NULL, &tv) < 0)
- test_fail("select() failed unexpectedly");
-
- if (rd != -1 && !!FD_ISSET(sd, &read_set) != rd)
- test_fail("select() mismatch on read operation");
-
- if (wr != -1 && !!FD_ISSET(sd, &write_set) != wr)
- test_fail("select() mismatch on write operation");
-}
-
-/*
- * Verify that:
- * - a nonblocking connecting socket for which there is no accepter, will
- * return EINPROGRESS and complete in the background later;
- * - a nonblocking listening socket will return EAGAIN on accept;
- * - connecting a connecting socket yields EALREADY;
- * - connecting a connected socket yields EISCONN;
- * - selecting for read and write on a connecting socket will only satisfy the
- * write only once it is connected;
- * - doing a nonblocking write on a connecting socket yields EAGAIN;
- * - doing a nonblocking read on a connected socket with no pending data yields
- * EAGAIN.
- */
-static void
-test_nonblock(void)
-{
- char buf[BUFSIZE];
- socklen_t len;
- int server_sd, client_sd;
- struct sockaddr_un server_addr, client_addr, addr;
- int status;
-
- memset(buf, 0, sizeof(buf));
-
- memset(&server_addr, 0, sizeof(server_addr));
- strlcpy(server_addr.sun_path, TEST_SUN_PATH,
- sizeof(server_addr.sun_path));
- server_addr.sun_family = AF_UNIX;
-
- client_addr = server_addr;
-
- SOCKET(server_sd, PF_UNIX, SOCK_STREAM, 0);
-
- if (bind(server_sd, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr_un)) == -1)
- test_fail("bind() should have worked");
-
- if (listen(server_sd, 8) == -1)
- test_fail("listen() should have worked");
-
- fcntl(server_sd, F_SETFL, fcntl(server_sd, F_GETFL) | O_NONBLOCK);
-
- check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- len = sizeof(addr);
- if (accept(server_sd, (struct sockaddr *) &addr, &len) != -1 ||
- errno != EAGAIN)
- test_fail("accept() should have yielded EAGAIN");
-
- SOCKET(client_sd, PF_UNIX, SOCK_STREAM, 0);
-
- fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != EINPROGRESS)
- test_fail("connect() should have yielded EINPROGRESS");
-
- check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != EALREADY)
- test_fail("connect() should have yielded EALREADY");
-
- if (recv(client_sd, buf, sizeof(buf), 0) != -1 || errno != EAGAIN)
- test_fail("recv() should have yielded EAGAIN");
-
- /* This may be an implementation aspect, or even plain wrong (?). */
- if (send(client_sd, buf, sizeof(buf), 0) != -1 || errno != EAGAIN)
- test_fail("send() should have yielded EAGAIN");
-
- switch (fork()) {
- case 0:
- close(client_sd);
-
- check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- len = sizeof(addr);
- client_sd = accept(server_sd, (struct sockaddr *) &addr, &len);
- if (client_sd == -1)
- test_fail("accept() should have succeeded");
-
- check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- close(server_sd);
-
- /* Let the socket become writable in the parent process. */
- sleep(1);
-
- if (write(client_sd, buf, 1) != 1)
- test_fail("write() should have succeeded");
-
- /* Wait for the client side to close. */
- check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
- check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
- check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- exit(errct);
- case -1:
- test_fail("can't fork");
- default:
- break;
- }
-
- close(server_sd);
-
- check_select(client_sd, 0 /*read*/, 1 /*write*/, 1 /*block*/);
- check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != EISCONN)
- test_fail("connect() should have yielded EISCONN");
-
- check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
- check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- if (read(client_sd, buf, 1) != 1)
- test_fail("read() should have succeeded");
-
- check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- if (read(client_sd, buf, 1) != -1 || errno != EAGAIN)
- test_fail("read() should have yielded EAGAIN");
-
- /* Let the child process block on the select waiting for the close. */
- sleep(1);
-
- close(client_sd);
-
- if (wait(&status) <= 0)
- test_fail("wait() should have succeeded");
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- test_fail("child process failed the test");
-
- UNLINK(TEST_SUN_PATH);
-}
-
-/*
- * Verify that a nonblocking connect for which there is an accepter, succeeds
- * immediately. A pretty lame test, only here for completeness.
- */
-static void
-test_connect_nb(void)
-{
- socklen_t len;
- int server_sd, client_sd;
- struct sockaddr_un server_addr, client_addr, addr;
- int status;
-
- memset(&server_addr, 0, sizeof(server_addr));
- strlcpy(server_addr.sun_path, TEST_SUN_PATH,
- sizeof(server_addr.sun_path));
- server_addr.sun_family = AF_UNIX;
-
- client_addr = server_addr;
-
- SOCKET(server_sd, PF_UNIX, SOCK_STREAM, 0);
-
- if (bind(server_sd, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr_un)) == -1)
- test_fail("bind() should have worked");
-
- if (listen(server_sd, 8) == -1)
- test_fail("listen() should have worked");
-
- switch (fork()) {
- case 0:
- len = sizeof(addr);
- if (accept(server_sd, (struct sockaddr *) &addr, &len) == -1)
- test_fail("accept() should have succeeded");
-
- exit(errct);
- case -1:
- test_fail("can't fork");
- default:
- break;
- }
-
- close(server_sd);
-
- sleep(1);
-
- SOCKET(client_sd, PF_UNIX, SOCK_STREAM, 0);
-
- fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != 0)
- test_fail("connect() should have succeeded");
-
- close(client_sd);
-
- if (wait(&status) <= 0)
- test_fail("wait() should have succeeded");
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- test_fail("child process failed the test");
-
- UNLINK(TEST_SUN_PATH);
-}
-
-static void
-dummy_handler(int sig)
-{
- /* Nothing. */
-}
-
-/*
- * Verify that:
- * - interrupting a blocking connect will return EINTR but complete in the
- * background later;
- * - doing a blocking write on an asynchronously connecting socket succeeds
- * once the socket is connected.
- * - doing a nonblocking write on a connected socket with lots of pending data
- * yields EAGAIN.
- */
-static void
-test_intr(void)
-{
- struct sigaction act, oact;
- char buf[BUFSIZE];
- socklen_t len;
- int server_sd, client_sd;
- struct sockaddr_un server_addr, client_addr, addr;
- int r, status;
-
- memset(buf, 0, sizeof(buf));
-
- memset(&server_addr, 0, sizeof(server_addr));
- strlcpy(server_addr.sun_path, TEST_SUN_PATH,
- sizeof(server_addr.sun_path));
- server_addr.sun_family = AF_UNIX;
-
- client_addr = server_addr;
-
- SOCKET(server_sd, PF_UNIX, SOCK_STREAM, 0);
-
- if (bind(server_sd, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr_un)) == -1)
- test_fail("bind() should have worked");
-
- if (listen(server_sd, 8) == -1)
- test_fail("listen() should have worked");
-
- SOCKET(client_sd, PF_UNIX, SOCK_STREAM, 0);
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = dummy_handler;
- if (sigaction(SIGALRM, &act, &oact) == -1)
- test_fail("sigaction() should have succeeded");
-
- alarm(1);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != EINTR)
- test_fail("connect() should have yielded EINTR");
-
- check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
-
- switch (fork()) {
- case 0:
- close(client_sd);
-
- check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- len = sizeof(addr);
- client_sd = accept(server_sd, (struct sockaddr *) &addr, &len);
- if (client_sd == -1)
- test_fail("accept() should have succeeded");
-
- check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- close(server_sd);
-
- check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
- check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- if (recv(client_sd, buf, sizeof(buf), 0) != sizeof(buf))
- test_fail("recv() should have yielded bytes");
-
- /* No partial transfers should be happening. */
- check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- sleep(1);
-
- fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) |
- O_NONBLOCK);
-
- /* We can only test nonblocking writes by filling the pipe. */
- while ((r = write(client_sd, buf, sizeof(buf))) > 0);
-
- if (r != -1 || errno != EAGAIN)
- test_fail("write() should have yielded EAGAIN");
-
- check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
-
- if (write(client_sd, buf, 1) != -1 || errno != EAGAIN)
- test_fail("write() should have yielded EAGAIN");
-
- exit(errct);
- case -1:
- test_fail("can't fork");
- default:
- break;
- }
-
- close(server_sd);
-
- if (send(client_sd, buf, sizeof(buf), 0) != sizeof(buf))
- test_fail("send() should have succeded");
-
- check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- if (wait(&status) <= 0)
- test_fail("wait() should have succeeded");
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- test_fail("child process failed the test");
-
- check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- close(client_sd);
-
- sigaction(SIGALRM, &oact, NULL);
-
- UNLINK(TEST_SUN_PATH);
-}
-
-/*
- * Verify that closing a connecting socket before it is accepted will result in
- * no activity on the accepting side later.
- */
-static void
-test_connect_close(void)
-{
- int server_sd, client_sd;
- struct sockaddr_un server_addr, client_addr;
- socklen_t len;
-
- memset(&server_addr, 0, sizeof(server_addr));
- strlcpy(server_addr.sun_path, TEST_SUN_PATH,
- sizeof(server_addr.sun_path));
- server_addr.sun_family = AF_UNIX;
-
- client_addr = server_addr;
-
- SOCKET(server_sd, PF_UNIX, SOCK_STREAM, 0);
-
- if (bind(server_sd, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr_un)) == -1)
- test_fail("bind() should have worked");
-
- if (listen(server_sd, 8) == -1)
- test_fail("listen() should have worked");
-
- fcntl(server_sd, F_SETFL, fcntl(server_sd, F_GETFL) | O_NONBLOCK);
-
- check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- SOCKET(client_sd, PF_UNIX, SOCK_STREAM, 0);
-
- fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != EINPROGRESS)
- test_fail("connect() should have yielded EINPROGRESS");
-
- check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
- check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- close(client_sd);
-
- check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
-
- len = sizeof(client_addr);
- if (accept(server_sd, (struct sockaddr *) &client_addr, &len) != -1 ||
- errno != EAGAIN)
- test_fail("accept() should have yielded EAGAIN");
-
- close(server_sd);
-
- UNLINK(TEST_SUN_PATH);
-}
-
-/*
- * Verify that closing a listening socket will cause a blocking connect to fail
- * with ECONNRESET, and that a subsequent write will yield EPIPE.
- */
-static void
-test_listen_close(void)
-{
- int server_sd, client_sd;
- struct sockaddr_un server_addr, client_addr;
- int status;
- char byte;
-
- memset(&server_addr, 0, sizeof(server_addr));
- strlcpy(server_addr.sun_path, TEST_SUN_PATH,
- sizeof(server_addr.sun_path));
- server_addr.sun_family = AF_UNIX;
-
- client_addr = server_addr;
-
- SOCKET(server_sd, PF_UNIX, SOCK_STREAM, 0);
-
- if (bind(server_sd, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr_un)) == -1)
- test_fail("bind() should have worked");
-
- if (listen(server_sd, 8) == -1)
- test_fail("listen() should have worked");
-
- switch (fork()) {
- case 0:
- sleep(1);
-
- exit(0);
- case -1:
- test_fail("can't fork");
- default:
- break;
- }
-
- close(server_sd);
-
- SOCKET(client_sd, PF_UNIX, SOCK_STREAM, 0);
-
- byte = 0;
- if (write(client_sd, &byte, 1) != -1 || errno != ENOTCONN)
- /* Yes, you fucked up the fix for the FIXME below. */
- test_fail("write() should have yielded ENOTCONN");
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != ECONNRESET)
- test_fail("connect() should have yielded ECONNRESET");
-
- /*
- * FIXME: currently UDS cannot distinguish between sockets that have
- * not yet been connected, and sockets that have been disconnected.
- * Thus, we get the same error for both: ENOTCONN instead of EPIPE.
- */
-#if 0
- if (write(client_sd, &byte, 1) != -1 || errno != EPIPE)
- test_fail("write() should have yielded EPIPE");
-#endif
-
- close(client_sd);
-
- if (wait(&status) <= 0)
- test_fail("wait() should have succeeded");
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- test_fail("child process failed the test");
-
- UNLINK(TEST_SUN_PATH);
-}
-
-/*
- * Verify that closing a listening socket will cause a nonblocking connect to
- * result in the socket becoming readable and writable, and yielding ECONNRESET
- * and EPIPE on the next two writes, respectively.
- */
-static void
-test_listen_close_nb(void)
-{
- int server_sd, client_sd;
- struct sockaddr_un server_addr, client_addr;
- int status;
- char byte;
-
- memset(&server_addr, 0, sizeof(server_addr));
- strlcpy(server_addr.sun_path, TEST_SUN_PATH,
- sizeof(server_addr.sun_path));
- server_addr.sun_family = AF_UNIX;
-
- client_addr = server_addr;
-
- SOCKET(server_sd, PF_UNIX, SOCK_STREAM, 0);
-
- if (bind(server_sd, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr_un)) == -1)
- test_fail("bind() should have worked");
-
- if (listen(server_sd, 8) == -1)
- test_fail("listen() should have worked");
-
- switch (fork()) {
- case 0:
- sleep(1);
-
- exit(0);
- case -1:
- test_fail("can't fork");
- default:
- break;
- }
-
- close(server_sd);
-
- SOCKET(client_sd, PF_UNIX, SOCK_STREAM, 0);
-
- fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
-
- if (connect(client_sd, (struct sockaddr *) &client_addr,
- sizeof(struct sockaddr_un)) != -1 || errno != EINPROGRESS)
- test_fail("connect() should have yielded EINPROGRESS");
-
- check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
- check_select(client_sd, 1 /*read*/, 1 /*write*/, 1 /*block*/);
-
- byte = 0;
- if (write(client_sd, &byte, 1) != -1 || errno != ECONNRESET)
- test_fail("write() should have yielded ECONNRESET");
-
- /*
- * FIXME: currently UDS cannot distinguish between sockets that have
- * not yet been connected, and sockets that have been disconnected.
- * Thus, we get the same error for both: ENOTCONN instead of EPIPE.
- */
-#if 0
- if (write(client_sd, &byte, 1) != -1 || errno != EPIPE)
- test_fail("write() should have yielded EPIPE");
-#endif
-
- check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
-
- close(client_sd);
-
- if (wait(&status) <= 0)
- test_fail("wait() should have succeeded");
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- test_fail("child process failed the test");
-
- UNLINK(TEST_SUN_PATH);
-}
-
int main(int argc, char *argv[])
{
int i;
+ struct sockaddr_un clientaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = TEST_SUN_PATH,
+ };
+ struct sockaddr_un clientaddr2 = {
+ .sun_family = AF_UNIX,
+ .sun_path = TEST_SUN_PATHB,
+ };
+ struct sockaddr_un clientaddrsym = {
+ .sun_family = AF_UNIX,
+ .sun_path = TEST_SYM_A,
+ };
+ const struct socket_test_info info = {
+ .clientaddr = (struct sockaddr *) &clientaddr,
+ .clientaddrlen = sizeof(clientaddr),
+ .clientaddr2 = (struct sockaddr *) &clientaddr2,
+ .clientaddr2len = sizeof(clientaddr2),
+ .clientaddrsym = (struct sockaddr *) &clientaddrsym,
+ .clientaddrsymlen = sizeof(clientaddrsym),
+ .domain = PF_UNIX,
+ .expected_rcvbuf = PIPE_BUF,
+ .expected_sndbuf = PIPE_BUF,
+ .serveraddr = (struct sockaddr *) &clientaddr,
+ .serveraddrlen = sizeof(clientaddr),
+ .serveraddr2 = (struct sockaddr *) &clientaddr2,
+ .serveraddr2len = sizeof(clientaddr2),
+ .type = SOCK_STREAM,
+ .types = types,
+ .typecount = 3,
+ .callback_check_sockaddr = callback_check_sockaddr,
+ .callback_cleanup = callback_cleanup,
+ .callback_xfer_prepclient = callback_xfer_prepclient,
+ .callback_xfer_peercred = callback_xfer_peercred,
+ };
debug("entering main()");
start(56);
- test_socket();
- test_bind();
- test_listen();
- test_getsockname();
+ test_socket(&info);
+ test_bind(&info);
+ test_bind_unix();
+ test_listen(&info);
+ test_getsockname(&info);
test_header();
- test_shutdown();
- test_close();
+ test_shutdown(&info);
+ test_close(&info);
test_permissions();
- test_dup();
- test_dup2();
+ test_dup(&info);
+ test_dup2(&info);
test_socketpair();
- test_shutdown();
- test_read();
- test_write();
- test_sockopts();
+ test_shutdown(&info);
+ test_read(&info);
+ test_write(&info);
+ test_sockopts(&info);
test_ucred();
- test_xfer();
+ test_xfer(&info);
for (i = 0; i < 3; i++) {
- test_simple_client_server(types[i]);
+ test_simple_client_server(&info, types[i]);
if (types[i] != SOCK_DGRAM) test_vectorio(types[i]);
if (types[i] != SOCK_DGRAM) test_msg(types[i]);
}
- test_abort_client_server(1);
- test_abort_client_server(2);
- test_msg_dgram();
- test_connect();
+
+ test_abort_client_server(&info, 1);
+ test_abort_client_server(&info, 2);
+ test_msg_dgram(&info);
+ test_connect(&info);
test_multiproc_read();
test_multiproc_write();
test_scm_credentials();
test_select();
test_select_close();
test_fchmod();
- test_nonblock();
- test_connect_nb();
- test_intr();
- test_connect_close();
- test_listen_close();
- test_listen_close_nb();
+ test_nonblock(&info);
+ test_connect_nb(&info);
+ test_intr(&info);
+ test_connect_close(&info);
+ test_listen_close(&info);
+ test_listen_close_nb(&info);
quit();
--- /dev/null
+/*
+ * test80: use the functions originally written for test56 to test TCP
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include "common.h"
+#include "common-socket.h"
+
+#define PORT1 4321
+#define PORT2 4322
+
+static void callback_check_sockaddr(const struct sockaddr *sockaddr,
+ socklen_t sockaddrlen, const char *callname, int addridx) {
+ char buf[256];
+ int port;
+ const struct sockaddr_in *sockaddr_in =
+ (const struct sockaddr_in *) sockaddr;
+
+ switch (addridx) {
+ case 1: port = PORT1; break;
+ case 2: port = PORT2; break;
+ default:
+ fprintf(stderr, "error: invalid addridx %d in "
+ "callback_check_sockaddr\n", addridx);
+ abort();
+ }
+
+ if (sockaddr_in->sin_family != AF_INET ||
+ sockaddr_in->sin_port != htons(port)) {
+ snprintf(buf, sizeof(buf), "%s() didn't return the right addr",
+ callname);
+ test_fail(buf);
+
+ memset(buf, 0, sizeof(buf));
+ inet_ntop(sockaddr_in->sin_family, &sockaddr_in->sin_addr,
+ buf, sizeof(buf));
+ fprintf(stderr, "exp: localhost:%d | got: %s:%d\n", port, buf,
+ ntohs(sockaddr_in->sin_port));
+ }
+}
+
+static void callback_cleanup(void) {
+ /* nothing to do */
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct sockaddr_in clientaddr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT1),
+ .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
+ };
+ struct sockaddr_in clientaddr2 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT2),
+ .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
+ };
+ struct sockaddr_in serveraddr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT1),
+ .sin_addr = { .s_addr = htonl(INADDR_ANY) },
+ };
+ struct sockaddr_in serveraddr2 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT2),
+ .sin_addr = { .s_addr = htonl(INADDR_ANY) },
+ };
+ const struct socket_test_info info = {
+ .clientaddr = (struct sockaddr *) &clientaddr,
+ .clientaddrlen = sizeof(clientaddr),
+ .clientaddr2 = (struct sockaddr *) &clientaddr2,
+ .clientaddr2len = sizeof(clientaddr2),
+ .clientaddrsym = (struct sockaddr *) &clientaddr,
+ .clientaddrsymlen = sizeof(clientaddr),
+ .domain = PF_INET,
+ .expected_rcvbuf = -1,
+ .expected_sndbuf = -1,
+ .serveraddr = (struct sockaddr *) &serveraddr,
+ .serveraddrlen = sizeof(serveraddr),
+ .serveraddr2 = (struct sockaddr *) &serveraddr2,
+ .serveraddr2len = sizeof(serveraddr2),
+ .type = SOCK_STREAM,
+ .types = &info.type,
+ .typecount = 1,
+
+ .bug_bind_in_use = 1,
+ .bug_bind_null = 1,
+ .bug_connect_after_close = 1,
+ .bug_shutdown_not_conn = 1,
+ .bug_shutdown_read = 1,
+ .ignore_accept_delay = 1,
+ .ignore_connect_unaccepted = 1,
+ .ignore_connect_delay = 1,
+ .ignore_read_conn_reset = 1,
+ .ignore_select_delay = 1,
+ .ignore_send_waiting = 1,
+ .ignore_write_conn_reset = 1,
+
+ .callback_check_sockaddr = callback_check_sockaddr,
+ .callback_cleanup = callback_cleanup,
+ .callback_xfer_prepclient = NULL,
+ .callback_xfer_peercred = NULL,
+ };
+
+ debug("entering main()");
+
+ start(80);
+
+ test_socket(&info);
+ test_bind(&info);
+ test_listen(&info);
+ test_getsockname(&info);
+ test_shutdown(&info);
+ test_close(&info);
+ test_dup(&info);
+ test_dup2(&info);
+ test_shutdown(&info);
+ test_read(&info);
+ test_write(&info);
+ test_sockopts(&info);
+ test_xfer(&info);
+ test_simple_client_server(&info, info.type);
+ test_abort_client_server(&info, 1);
+ test_abort_client_server(&info, 2);
+ test_nonblock(&info);
+ test_connect_nb(&info);
+ test_intr(&info);
+ test_connect_close(&info);
+ test_listen_close(&info);
+ test_listen_close_nb(&info);
+
+ quit();
+
+ return -1; /* we should never get here */
+}
--- /dev/null
+/*
+ * test81: use the functions originally written for test56 to test UDP
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include "common.h"
+#include "common-socket.h"
+
+#define PORT1 4321
+#define PORT2 4322
+
+static void callback_check_sockaddr(const struct sockaddr *sockaddr,
+ socklen_t sockaddrlen, const char *callname, int addridx) {
+ char buf[256];
+ int port;
+ const struct sockaddr_in *sockaddr_in =
+ (const struct sockaddr_in *) sockaddr;
+
+ switch (addridx) {
+ case 1: port = PORT1; break;
+ case 2: port = PORT2; break;
+ default:
+ fprintf(stderr, "error: invalid addridx %d in "
+ "callback_check_sockaddr\n", addridx);
+ abort();
+ }
+
+ if (sockaddr_in->sin_family != AF_INET ||
+ sockaddr_in->sin_port != htons(port)) {
+ snprintf(buf, sizeof(buf), "%s() didn't return the right addr",
+ callname);
+ test_fail(buf);
+
+ memset(buf, 0, sizeof(buf));
+ inet_ntop(sockaddr_in->sin_family, &sockaddr_in->sin_addr,
+ buf, sizeof(buf));
+ fprintf(stderr, "exp: localhost:%d | got: %s:%d\n", port, buf,
+ ntohs(sockaddr_in->sin_port));
+ }
+}
+
+static void callback_cleanup(void) {
+ /* nothing to do */
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct sockaddr_in clientaddr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT1),
+ .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
+ };
+ struct sockaddr_in clientaddr2 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT2),
+ .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
+ };
+ struct sockaddr_in serveraddr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT1),
+ .sin_addr = { .s_addr = htonl(INADDR_ANY) },
+ };
+ struct sockaddr_in serveraddr2 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(PORT2),
+ .sin_addr = { .s_addr = htonl(INADDR_ANY) },
+ };
+ const struct socket_test_info info = {
+ .clientaddr = (struct sockaddr *) &clientaddr,
+ .clientaddrlen = sizeof(clientaddr),
+ .clientaddr2 = (struct sockaddr *) &clientaddr2,
+ .clientaddr2len = sizeof(clientaddr2),
+ .clientaddrsym = (struct sockaddr *) &clientaddr,
+ .clientaddrsymlen = sizeof(clientaddr),
+ .domain = PF_INET,
+ .expected_rcvbuf = -1,
+ .expected_sndbuf = -1,
+ .serveraddr = (struct sockaddr *) &serveraddr,
+ .serveraddrlen = sizeof(serveraddr),
+ .serveraddr2 = (struct sockaddr *) &serveraddr2,
+ .serveraddr2len = sizeof(serveraddr2),
+ .type = SOCK_DGRAM,
+ .types = &info.type,
+ .typecount = 1,
+
+ .bug_bind_in_use = 1,
+ .bug_bind_null = 1,
+ .bug_connect_after_close = 1,
+ .bug_shutdown = 1, /* UDP only problem */
+ .bug_shutdown_not_conn = 1,
+ .bug_shutdown_read = 1,
+ .bug_sockopt_rcvbuf = 1, /* UDP only problem */
+ .bug_sockopt_sndbuf = 1, /* UDP only problem */
+ .ignore_accept_delay = 1,
+ .ignore_connect_unaccepted = 1,
+ .ignore_connect_delay = 1,
+ .ignore_read_conn_reset = 1,
+ .ignore_select_delay = 1,
+ .ignore_send_waiting = 1,
+ .ignore_write_conn_reset = 1,
+
+ .callback_check_sockaddr = callback_check_sockaddr,
+ .callback_cleanup = callback_cleanup,
+ .callback_xfer_prepclient = NULL,
+ .callback_xfer_peercred = NULL,
+ };
+
+ debug("entering main()");
+
+ start(81);
+
+ test_socket(&info);
+ test_bind(&info);
+ test_getsockname(&info);
+ test_shutdown(&info);
+ test_close(&info);
+ test_dup(&info);
+ test_dup2(&info);
+ test_shutdown(&info);
+ test_read(&info);
+ test_write(&info);
+ test_sockopts(&info);
+ test_simple_client_server(&info, info.type);
+
+ quit();
+
+ return -1; /* we should never get here */
+}