[netfilter-cvslog] r4320 - trunk/nfsim/core

rusty at netfilter.org rusty at netfilter.org
Thu Oct 6 20:21:58 CEST 2005


Author: rusty at netfilter.org
Date: 2005-10-06 20:21:57 +0200 (Thu, 06 Oct 2005)
New Revision: 4320

Modified:
   trunk/nfsim/core/fakesockopt.c
   trunk/nfsim/core/message.c
   trunk/nfsim/core/nfsockopt.h
Log:
Glibc seems to randomize mallocs now, so replay fails.  Make --failtest use fd passing (from K42 test code via Chris Yeoh) instead of trying to replay.  Should be faster, too.


Modified: trunk/nfsim/core/fakesockopt.c
===================================================================
--- trunk/nfsim/core/fakesockopt.c	2005-10-06 12:30:45 UTC (rev 4319)
+++ trunk/nfsim/core/fakesockopt.c	2005-10-06 18:21:57 UTC (rev 4320)
@@ -33,6 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <sys/wait.h>
 
 #include <dlfcn.h>
 
@@ -126,10 +127,40 @@
 	(*__close)(sd);
 }
 
+static int recv_fd(int from_fd)
+{
+	struct iovec iov[1];
+	struct msghdr msg;
+	char buf[1];
+	char cmsgbuf[1000];
+	struct cmsghdr *cmsg;
+	int ret;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = sizeof(buf);
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = cmsgbuf;
+	msg.msg_controllen = sizeof(cmsgbuf);
+	msg.msg_flags = MSG_WAITALL;
+
+	ret = recvmsg(from_fd, &msg, 0);
+	if (ret < 0) {
+		perror("recv_fd failed");
+		exit(EXIT_FAILURE);
+	}
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	return *((int*)CMSG_DATA(cmsg));
+}
+
 static void handle_kernelop(int fd, struct nf_userspace_message *msg)
 {
 	struct nf_userspace_message *reply;
-	int m_offset = sizeof(struct nf_userspace_message);
+	int pid, m_offset = sizeof(struct nf_userspace_message);
 
 	assert(msg->type = UM_KERNELOP);
 
@@ -150,7 +181,21 @@
 		reply->len = msg->args[2];
 
 		break;
-	
+	case KOP_FORK:
+		pid = fork();
+		if (pid < 0) {
+			perror("fork");
+			exit(EXIT_FAILURE);
+		}
+		reply = msg;
+		if (pid != 0) {
+			/* Retval for parent is status of child. */
+			waitpid(pid, &msg->retval, 0);
+			break;
+		}
+		reply->retval = getpid();
+		break;
+
 	default:
 		fprintf(stderr, "Invalid kernelop opcode\n");
 		return;
@@ -165,6 +210,14 @@
 
 	if (reply != msg)
 		free(reply);
+
+	if (msg->opcode == KOP_FORK && pid == 0) {
+		/* Child: get own fd for output. */
+		int newfd = recv_fd(sd);
+		dup2(newfd, STDOUT_FILENO);
+		dup2(newfd, STDERR_FILENO);
+		close(newfd);
+	}
 }
 
 /* send a syscall and wait for a response, processing any kernelops

Modified: trunk/nfsim/core/message.c
===================================================================
--- trunk/nfsim/core/message.c	2005-10-06 12:30:45 UTC (rev 4319)
+++ trunk/nfsim/core/message.c	2005-10-06 18:21:57 UTC (rev 4320)
@@ -32,10 +32,40 @@
 #include <linux/netfilter_ipv4/ip_tables.h>
 
 static int sock[2]; /* socket for messages. 0 = parent, 1 = child */
+static bool forked;
 
 static void send_userspace_message(struct nf_userspace_message *msg);
-static void handle_userspace_message(void);
 
+static void send_fd(int dest_fd, int fd)
+{
+	struct iovec iov[1];
+	struct cmsghdr *cmsg;
+	struct msghdr msg;
+	char buf[1];
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = sizeof(buf);
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = malloc(CMSG_SPACE(sizeof(fd)));
+	msg.msg_controllen = CMSG_SPACE(sizeof(fd));
+	msg.msg_flags = 0;
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	*(int*)CMSG_DATA(cmsg) = fd;
+
+	msg.msg_controllen = CMSG_SPACE(sizeof(fd));
+ 
+	if (sendmsg(dest_fd, &msg, 0) < 0)
+		barf_perror("sendfd failed");
+}
+
 void message_init(void)
 {
 	sigset_t ss;
@@ -70,42 +100,23 @@
 	sigprocmask(SIG_UNBLOCK, &ss, NULL);
 }
 
-struct message
-{
-	struct list_head list;
-	bool outgoing;
-	struct nf_userspace_message msg;
-	char data[0];
-};
-
 struct program
 {
-	char *name;
-	struct list_head messages;
 	pid_t pid;
+	int status;
 	int fd;
-	int argc;
-	char *argv[0];
 };
 static struct program *currprog;
 
 void start_program(const char *name, int argc, char *argv[])
 {
-	int i, childfd[2];
+	int childfd[2];
 
 	assert(!currprog);
-	currprog = talloc_size(NULL, sizeof(*currprog)
-			       + (argc+1)*sizeof(char *));
+	currprog = talloc(NULL, struct program);
 
-	currprog->name = talloc_strdup(currprog, name);
-	currprog->argc = argc;
-	for (i = 0; i < argc; i++)
-		currprog->argv[i] = talloc_strdup(currprog, argv[i]);
-	currprog->argv[argc] = NULL;
-	INIT_LIST_HEAD(&currprog->messages);
-
 	if (pipe(childfd) != 0)
-		barf_perror("%s pipe", currprog->name);
+		barf_perror("%s pipe", name);
 
 	fflush(stdout);
 	currprog->pid = fork();
@@ -117,23 +128,37 @@
 		dup2(childfd[1], STDERR_FILENO);
 		if (setenv("LD_PRELOAD", "fakesockopt.so.1.0", 1))
 			barf("putenv failed");
-		execvp(currprog->name, currprog->argv);
-		fprintf(stderr, "Could not exec %s!\n", currprog->name);
+		execvp(name, argv);
+		fprintf(stderr, "Could not exec %s!\n", name);
 		exit(EXIT_FAILURE);
 	}
 
 	close(childfd[1]);
 	currprog->fd = childfd[0];
+	currprog->status = -1;
 }
 
 int end_program(const char *name)
 {
 	int status;
 
-	while (waitpid(currprog->pid, &status, 0) <= 0)
-		if (errno != EINTR)
-			barf_perror("Waiting for child %s", name);
+	if (forked) {
+		/* Damn UNIX!  Not our child. */
 
+		/* Might have been read already. */
+		status = currprog->status;
+		if (status == -1) {
+			struct nf_userspace_message msg;
+			if (read(sock[0], &msg, sizeof(msg)) != sizeof(msg))
+				barf_perror("Reading child status");
+			status = msg.retval;
+		}
+	} else {
+		while (waitpid(currprog->pid, &status, 0) <= 0)
+			if (errno != EINTR)
+				barf_perror("Waiting for child %s", name);
+	}
+
 	close(currprog->fd);
 	talloc_free(currprog);
 	currprog = NULL;
@@ -141,43 +166,6 @@
 	return status;
 }
 
-static void add_message(bool outgoing, struct nf_userspace_message *msg,
-			int datalen, const void *data)
-{
-	struct message *new;
-
-	assert(currprog);
-	new = talloc_size(currprog, sizeof(*new) + datalen);
-	new->outgoing = outgoing;
-	new->msg = *msg;
-	memcpy(new->data, data, datalen);
-	list_add_tail(&new->list, &currprog->messages);
-}
-
-static void replay_messages(struct program *old)
-{
-	struct message *i, *in;
-	int totlen;
-
-	list_for_each_entry(i, &old->messages, list) {
-		add_message(i->outgoing, &i->msg, i->msg.len, &i->msg+1);
-		totlen = sizeof(i->msg) + i->msg.len;
-		if (i->outgoing) {
-			write(sock[0], &i->msg, totlen);
-			continue;
-		}
-
-		in = talloc_size(NULL, sizeof(*in) + i->msg.len);
-		/* Read in two parts: can be written that way. */
-		if (read(sock[0], &in->msg, sizeof(in->msg)) != sizeof(in->msg)
-		    || read(sock[0], in->data, i->msg.len) != i->msg.len)
-			barf_perror("read during replay");
-		if (memcmp(&in->msg, &i->msg, totlen) != 0)
-			barf_perror("replay turned out different");
-		talloc_free(in);
-	}
-}
-
 static const char *protofamily(int pf)
 {
 	switch (pf) {
@@ -258,7 +246,7 @@
 	return errstr;
 }
 
-void handle_userspace_message(void)
+static void handle_userspace_message(void)
 {
 	int len;
 	struct nf_userspace_message msg;
@@ -269,7 +257,6 @@
 		barf_perror("reading userspace message");
 
 	if (msg.type == UM_SYSCALL) {
-		add_message(false, &msg, 0, NULL);
 		switch (msg.opcode) {
 
 		case SYS_GETSOCKOPT:
@@ -289,7 +276,6 @@
 					  "    getsockopt -> %s (len %i)",
 					  err(msg.retval), msg.args[3]);
 			write(sock[0], &msg, sizeof(msg));
-			add_message(true, &msg, 0, NULL);
 			break;
 		case SYS_SETSOCKOPT:
 			if (strace)
@@ -307,7 +293,6 @@
 				nfsim_log(LOG_USERSPACE, "    setsockopt -> %s",
 					  err(msg.retval));
 			write(sock[0], &msg, sizeof(msg));
-			add_message(true, &msg, 0, NULL);
 			break;
 		default:
 			barf("Invalid syscall opcode %d\n", msg.opcode);
@@ -319,13 +304,18 @@
 			if (complete_read(sock[0], (char *)msg.args[0],
 					msg.args[2]) !=	msg.args[2])
 				barf_perror("read");
-			add_message(false, &msg, msg.args[2],
-				    (char *)msg.args[0]);
 			break;
 		case KOP_COPY_TO_USER:
-			add_message(false, &msg, 0, NULL);
 			/* copying has been done */
 			break;
+
+		case KOP_FORK:
+			if (!currprog->pid)
+				currprog->pid = msg.retval;
+			else
+				currprog->status = msg.retval;
+			break;
+
 		default:
 			barf("Invalid kernelop opcode %d\n", msg.opcode);
 		}
@@ -336,7 +326,7 @@
 void send_userspace_message(struct nf_userspace_message *msg)
 {
 	write(sock[0], msg, sizeof(struct nf_userspace_message) + msg->len);
-	add_message(true, msg, msg->len, msg+1);
+//	add_message(true, msg, msg->len, msg+1);
 	/* expect a reply */
 	handle_userspace_message();
 }
@@ -412,20 +402,36 @@
 /* This child wants a fresh program to play with */
 void fork_other_program(void)
 {
-	struct program *old;
+	struct nf_userspace_message msg;
+	int newsock[2];
 
-	/* Guarantee new socket for this child. */
-	message_cleanup();
-	message_init();
-
 	if (!currprog)
 		return;
 
-	old = currprog;
-	currprog = NULL;
-	start_program(old->name, old->argc, old->argv);
-	replay_messages(old);
-	talloc_free(old);
+	if (socketpair(PF_UNIX, SOCK_STREAM, PF_UNSPEC, newsock))
+		barf_perror("socket");
+
+	forked = true;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.type = UM_KERNELOP;
+	msg.opcode = KOP_FORK;
+	if (strace)
+		nfsim_log(LOG_USERSPACE, "        fork()");
+
+	/* Child will tell us pid. */
+	currprog->pid = 0;
+	currprog->status = -1;
+	send_userspace_message(&msg);
+
+	/* Now child expects us to supply new fd for stdout/stderr.
+	 * We use this to tell when it died. */
+	send_fd(sock[0], newsock[1]);
+
+	/* And use the new socket pair. */
+	close(currprog->fd);
+	close(newsock[1]);
+	currprog->fd = newsock[0];
 }
 
 /* Loop accepting messages from fakesockopt.  If child talks, return. */

Modified: trunk/nfsim/core/nfsockopt.h
===================================================================
--- trunk/nfsim/core/nfsockopt.h	2005-10-06 12:30:45 UTC (rev 4319)
+++ trunk/nfsim/core/nfsockopt.h	2005-10-06 18:21:57 UTC (rev 4320)
@@ -28,6 +28,7 @@
 
 #define KOP_COPY_TO_USER   1
 #define KOP_COPY_FROM_USER 2
+#define KOP_FORK 3
 
 #define MAX_MESSAGE_ARGS 4
 




More information about the netfilter-cvslog mailing list