Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 Nov 1996 09:01:11 PST
From:      "Marty Leisner" <leisner@sdsp.mc.xerox.com>
To:        Bill Paul <wpaul@skynet.ctr.columbia.edu>
Cc:        hackers@freebsd.org
Subject:   Re: descriptors and sockets and pipes, oh my 
Message-ID:  <9611261701.AA12903@gnu.sdsp.mc.xerox.com>
In-Reply-To: Your message of "Sat, 23 Nov 1996 10:02:10 PST." <199611231802.NAA05597@skynet.ctr.columbia.edu> 

next in thread | previous in thread | raw e-mail | index | archive | help

In message <199611231802.NAA05597@skynet.ctr.columbia.edu>,   you write:
>
>Does anyone have a source code example handy of passing a file
>descriptor from one process to anyther via an AF_UNIX socket?
>_UNIX Network Programming_ only provides an example for 4.3BSD; in 
>4.4BSD, the msghdr structure has changed. Also, is it possible to
>pass descriptors between totally unrelated processes, or must
>they be parent and child?
>
>Lastly, is it still possible to exchange file descriptors with the
>new pipe code in 2.2.x? The example in the book uses pipe(), but
>that's because pipes were really AF_UNIX sockets in disguise; this
>isn't true in FreeBSD 2.2.x anymore.
>
>-Bill
>
>-- 

This is the copy I had a work...(I think I have a newer one a home).

I didn't run it recently...but it shows what to do for 4.3/4.4:

/*
 *
 * Fork off a subprocessor.
 * Block SIGUSR1
 * Parent continuously:
 *	make a pipe
 *	write a simple message into the pipe (programmable, <  1 pipebuf)
 *  	close write side
 *	pass read side with small buffer via sendmsg to child
 *		(rendzvous at /tmp/child.sock.<pid>
 *	child receives message, responds with sigusr1 to parent (in global
 *	parent_pid).
 */


#ifdef __linux__
#define __USE_BSD_SIGNAL
#endif


#include <stdio.h>
#include <sys/types.h>

#include <sys/uio.h>

#include <sys/socket.h>
#include <sys/un.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>
#include <sys/time.h>
#ifdef __sun__
#include <sys/param.h>
#define PATH_MAX MAXPATHLEN
#define atexit(a)	on_exit(a, 0);
#endif
/* for solaris? */
#if defined(__svr4__)
#include <sys/rusage.h>
#endif
#include <sys/resource.h>

#ifdef BSD44
#ifndef CMSG_DATA
#define CMSG_DATA(a)		(((void *) a) + sizeof(struct cmsghdr))
#endif
#define CMSG_INT		(sizeof(struct cmsghdr) + sizeof(int))
#endif
/* available to parent and child */
static pid_t parent_pid;

static int errors = 0;

/* only available in parent */
static pid_t child_pid = 0;

/* should be sig_atomic_t */
static int sigusr1_occurred = 0;

/* number of times send data */
static int count = 0;

/* times failed */
static int failures = 0;
static char rendezvous[PATH_MAX];

/* bytes for message and pipe, less
 * than pipe buf 
 */
static int send_size;

static int debug = 0;


/* if set, report statitistics */
static int want_to_report = 0;

static void sigusr1(void)
{
	sigusr1_occurred++;
}

static void do_report(void)
{
	want_to_report++;
}
/* SIGUSR1 is normally blocked -- wait for any signal to occur.
 * 
 */
static void wait_for_sigusr1(void)
{
	sigset_t zeromask;

	sigemptyset(&zeromask);
	while(!sigusr1_occurred)
		sigsuspend(&zeromask);
	sigusr1_occurred = 0;
}
	
static void message_parent(void)
{
	int status;

	status = kill(parent_pid, SIGUSR1);
	if(status < 0) {
		perror("kill");
		exit(1);
	}
}

static int make_receive_socket(void)
{
	int fd;
	struct sockaddr_un sin;
	int status;

	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
	if(fd < 0) {
		perror("child socket");
		exit(1);
	}
	
	sin.sun_family = AF_UNIX;
	strcpy((char *) &sin.sun_path, rendezvous);
	status = bind(fd, (struct sockaddr *) &sin,
		sizeof(struct sockaddr_un));
	if(status < 0) {
		perror("child bind");
		exit(1);
	}
	return fd;
}

static void do_receive(const int fd)
{
	
#ifdef BSD44
	struct cmsghdr *cmptr;

	cmptr = alloca(CMSG_INT);

#endif
	while(1) {
		struct msghdr sockmsg;

		int receive_fd;
		int size;
		int bytes_read;
		struct iovec iovec[1];
		char buffer[send_size];
		char read_buffer[PIPE_BUF];

		iovec[0].iov_base = buffer;
		iovec[0].iov_len = sizeof(buffer);
		sockmsg.msg_name = 0;
		sockmsg.msg_namelen = 0;
		sockmsg.msg_iov = iovec;
		sockmsg.msg_iovlen = 1;
#ifdef BSD44
		sockmsg.msg_control = (caddr_t) cmptr;
		sockmsg.msg_controllen = CMSG_INT;	
		cmptr->cmsg_type = SCM_RIGHTS;
		cmptr->cmsg_level = SOL_SOCKET;
		cmptr->cmsg_len = CMSG_INT;
#else
		receive_fd = -1;
		sockmsg.msg_accrights = &receive_fd;
		sockmsg.msg_accrightslen = sizeof(receive_fd);
#endif


		size = recvmsg(fd, &sockmsg, 0);	
		if(size < 0) {
			perror("recvmsg");
			exit(1);
		}
#ifdef BSD44
		if(sockmsg.msg_controllen != CMSG_INT) {
			fprintf(stderr, "controllen wrong, = %d\n",
				sockmsg.msg_controllen);
			exit(1);
		}
		receive_fd = *(int *) CMSG_DATA(cmptr);
#endif
		if(receive_fd < 0) {
			fprintf(stderr, "no receive fd");
			exit(1);
		}
		bytes_read = read(receive_fd, &read_buffer, sizeof(read_buffer));	

		if(debug) 
			printf("message size = %d, bytes read = %d\n",
				size, bytes_read);
		count++;
		close(receive_fd);
		message_parent();
		if(want_to_report)
			report_statistics();
	}
}

static int child(void)
{
	int fd;
	
	fd = make_receive_socket();
	message_parent();
	
	do_receive(fd);
}


static void kill_child(void)
{
	if(child_pid)
		kill(child_pid, SIGTERM);
	printf("Count = %d\n", count);
	unlink(rendezvous);
}

static void make_child(void)
{
	int status;

	status = fork();
	switch(status) {
		case 0:
			child();
		case -1:
			perror("fork");
			exit(1);
		default:
			child_pid = status;
	}
	
	printf("Parent = %d, child = %d\n", getpid(), child_pid);

}

static void block_sig(const int signo)
{
	sigset_t mask;
	int status;
	
	sigemptyset(&mask);
	sigaddset(&mask, signo);
	status = sigprocmask(SIG_BLOCK, &mask, NULL);
	if(status != 0) {
		perror("sigprocmask");
		exit(1);
	}

}
	

static void make_sock_name(void)
{
	sprintf(rendezvous, "/tmp/socket.%d", getpid());
}

static int send_data(const int size)
{
	struct sockaddr_un sin;
	struct msghdr sockmsg;
	struct iovec iovec[1];
	int fds[2];
	int status;
	char buffer[size];
	static int sock_fd = -1;
#ifdef BSD44
	struct cmsghdr  *cmsg;

	cmsg = alloca(CMSG_INT);
#endif
	if(sock_fd < 0) {
		sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
		if(sock_fd < 0) {
			perror("parent socket");
			exit(1);
		}
	}
	status = pipe(fds);
	if(status < 0) {
		perror("pipe");
		exit(1);
	}

	iovec[0].iov_base = buffer;
	iovec[0].iov_len = size;
	status = write(fds[1], &buffer, size);
	if(status != size) {
		perror("write failed");
		exit(1);
	}
	close(fds[1]);
	
	sin.sun_family = AF_UNIX;
	strcpy((char *) &sin.sun_path, rendezvous);
	sockmsg.msg_name = (caddr_t) &sin;
	sockmsg.msg_namelen = sizeof(struct sockaddr_un);
	sockmsg.msg_iov = &iovec;
	sockmsg.msg_iovlen = 1;

#ifdef BSD44
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg->cmsg_len = CMSG_INT;
	sockmsg.msg_control = (caddr_t) cmsg;
	sockmsg.msg_controllen = CMSG_INT;
	*(int *) CMSG_DATA(cmsg) = fds[0];
#else
	sockmsg.msg_accrightslen = sizeof(fds[0]);
	sockmsg.msg_accrights = &fds[0];
#endif
	status = sendmsg(sock_fd, &sockmsg, 0);
	if(status < 0) {
		perror("sendmsg");
		errors++;
	}
	close(fds[0]);
	if(status)
		return 0;
	else	return 1;
}	
	

static void usage(const char *name)
{
	fprintf(stderr, "%s [-o] [-d]\n", name);
	exit(1);
}

static double convert_time(struct timeval *p)
{
	double seconds;

	seconds = p->tv_sec;
	seconds += ((double) p->tv_usec ) / 1000000.0;
	return seconds;
}

static void report_statistics(void)
{
	struct rusage usage;
	int result;
	pid_t pid = 0;

	if(!pid)
		pid = getpid();

	want_to_report = 0;
	
	result = getrusage(RUSAGE_SELF, &usage);
	if(result < 0) {
		perror("getrusage");
		return;
	}
	
	printf("Process: %d count = %d, failures = %d ", 
			pid, count, failures);

	printf("User time %.3f Sys time %.3f\n",
			convert_time(&usage.ru_utime), 
			convert_time(&usage.ru_stime));
	
	kill(child_pid, SIGUSR2);
}



main(int argc, char **argv)
{
	
	const char *options = "do";
	int c;
	char *progname;
	int one_shot = 0;

	send_size = 100;

		
	progname = argv[0];
	while(1) {
		c = getopt(argc, argv, "od");
		if(c == EOF)
			break;
		switch(c) {
			case 'd':
				debug = 1;
				break;
			case 'o':
				one_shot = 1;
				break;
			default: 
				usage(progname);
		}

	}
	
	
	parent_pid = getpid();
	block_sig(SIGUSR1);
	signal(SIGUSR1, sigusr1);
#if 0
	signal(SIGUSR2, do_report);
#endif
	atexit(kill_child);
	atexit(report_statistics);
	make_sock_name();
	make_child();
	wait_for_sigusr1();	
	alarm(10);
	signal(SIGALRM, do_report);
	while(1) {
		int result;
		result = send_data(send_size);
		if(one_shot) {
			sleep(1);
			exit(0);
		}
		if(!result)
			count++;
		else	failures++;
		if(want_to_report) {
			report_statistics();
			exit(0);
		}	
	}
	
}





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9611261701.AA12903>