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>
