From owner-freebsd-hackers Tue Nov 26 09:14:21 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.5/8.7.3) id JAA13901 for hackers-outgoing; Tue, 26 Nov 1996 09:14:21 -0800 (PST) Received: from alpha.xerox.com (alpha.Xerox.COM [13.1.64.93]) by freefall.freebsd.org (8.7.5/8.7.3) with SMTP id JAA13892 for ; Tue, 26 Nov 1996 09:14:13 -0800 (PST) Received: from www.sdsp.mc.xerox.com ([13.231.132.18]) by alpha.xerox.com with SMTP id <16836(1)>; Tue, 26 Nov 1996 09:13:40 PST Received: from gnu.sdsp.mc.xerox.com (gnu.sdsp.mc.xerox.com [13.231.133.90]) by www.sdsp.mc.xerox.com (8.8.3/8.7.5) with SMTP id MAA18270; Tue, 26 Nov 1996 12:01:13 -0500 (EST) Received: by gnu.sdsp.mc.xerox.com (4.1/client-1.3) id AA12903; Tue, 26 Nov 96 12:01:11 EST Message-Id: <9611261701.AA12903@gnu.sdsp.mc.xerox.com> To: Bill Paul Cc: hackers@freebsd.org Subject: Re: descriptors and sockets and pipes, oh my In-Reply-To: Your message of "Sat, 23 Nov 1996 10:02:10 PST." <199611231802.NAA05597@skynet.ctr.columbia.edu> Date: Tue, 26 Nov 1996 09:01:11 PST From: "Marty Leisner" Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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. * child receives message, responds with sigusr1 to parent (in global * parent_pid). */ #ifdef __linux__ #define __USE_BSD_SIGNAL #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __sun__ #include #define PATH_MAX MAXPATHLEN #define atexit(a) on_exit(a, 0); #endif /* for solaris? */ #if defined(__svr4__) #include #endif #include #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); } } }