Date: Sat, 29 Aug 1998 19:29:10 +0200 (CEST) From: Dirk-Willem van Gulik <dirk.vangulik@jrc.it> To: chanders@timing.com Cc: Bill Paul <wpaul@skynet.ctr.columbia.edu>, freebsd-hackers@FreeBSD.ORG Subject: Re: Help with passing fd on FreeBSD Message-ID: <Pine.BSF.3.96.980829192032.7282A-100000@elpc36.jrc.it> In-Reply-To: <Pine.BSF.3.96.980829094358.398B-100000@heidi.plazza.it>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 29 Aug 1998, Bill Paul wrote: > Of all the gin joints in all the towns in all the world, Craig Anderson > had to walk into mine and say: > > > > Can someone give me pointers on passing open file descriptors on FreeBSD? > > This is covered in W. Richard Stevens Advanced programming book, but > > the structs in FreeBSD are slightly different, and I've never done this. > > Sure. Appended to this message are two small programs: r.c and s.c. > s.c sends a descriptor and r.c receives it. Last time I used this > was on FreeBSD 2.1.0 but it should still work. The descriptor being > sent is actually the AF_LOCAL socket that s.c creates to talk to > r.c, which is kind of pointless but you can use any other descriptor > index you want (as long as it refers to a valid open descriptor). I struggeled with the same, in particular as the most recent book of Stevens uses the API as described in RFC2292. And two of the macro's are not quite part of socket.h. (why is this actually?) Below is Bill Pauls example again, but now with the newer (supposedly IPv6 compliant macros), they are just patched/diff-ed back in with a #define. Note that it is just the way of writing, as it al boils down to the same thing of course. But I just found it easier myself to write it down that way to follow the examples. See secion 4.3.x of the RFC for more details. Dw. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <err.h> #include <sys/types.h> #include <sys/time.h> #include <string.h> #include <sys/uio.h> #include <sys/fcntl.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/stat.h> #ifdef RFC2292API #include <sys/param.h> /* for ALIGN */ #endif /* RFC2292API */ #ifndef lint #ifndef RFC2292API static const char rcsid[] = "$Id: r.c,v 1.4 1998/08/29 01:03:52 wpaul Exp $"; #else static const char rcsid[] = "$Id: r.c,v 1.4 1998/08/30 07:21:10 dirkx Exp $"; #endif /* RFC2292API */ #endif #ifndef RFC2292API struct cmessage { struct cmsghdr cmsg; int fd; }; #else #ifndef CMSG_LEN # define CMSG_LEN(x) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(x)) #endif #ifndef CMSG_SPACE # define CMSG_SPACE(x) ( ALIGN(sizeof(struct cmsghdr)) + x) #endif #endif /* RFC2292API */ int main() { struct iovec iov[1]; struct msghdr msg; #ifndef RFC2292API struct cmessage cm; #else union { struct cmsghdr cm; char control[ CMSG_SPACE( sizeof( int ) ) ]; } cmsgbuf; struct cmsghdr * cmptr; #endif /* RFC2292API */ struct sockaddr_un sun; int s,fd; int sock; int len; fd_set readfds; char recbuf[1024]; if (unlink("/tmp/testsock") == -1) warn("couldn't remove old socket"); strcpy(sun.sun_path, "/tmp/testsock"); sun.sun_family = AF_UNIX; len = sun.sun_len = sizeof(sun.sun_len) + sizeof(sun.sun_family) + strlen(sun.sun_path) + 1; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket creation failed"); iov[0].iov_base = (char *)&recbuf; iov[0].iov_len = sizeof(recbuf); #ifndef RFC2292API bzero((char *)&cm, sizeof(cm)); #else bzero((char *)&cmsgbuf, sizeof(cmsgbuf)); #endif /* RFC2292API */ bzero((char *)&msg, sizeof(msg)); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_flags = 0; #ifndef RFC2292API msg.msg_control = (caddr_t)&cm; msg.msg_controllen = sizeof(struct cmessage); #else msg.msg_control = (caddr_t)&cmsgbuf.control; msg.msg_controllen = sizeof cmsgbuf.control; #endif /* RFC2292API */ if (bind(s, (struct sockaddr *)&sun, len) == -1) err(1, "couldn't bind socket"); listen(s, 2); if ((sock = accept(s, (struct sockaddr *)&sun, &len)) == -1) err(1, "accept failed"); FD_ZERO(&readfds); FD_SET(sock, &readfds); select(FD_SETSIZE, &readfds, NULL, NULL, NULL); if ((len = recvmsg(sock, &msg, 0)) == -1) err(1, "recvmsg failed"); printf ("read %d bytes\n", len); #ifndef RFC2292API if (cm.cmsg.cmsg_type != SCM_RIGHTS) warnx("message didn't contain SCM_RIGHTS"); fd=cm.fd; #else /* account for alignment issues */ if ((cmptr=CMSG_FIRSTHDR(&msg)) == NULL ) err(1,"Not the right msg struct"); if (cmptr->cmsg_len != CMSG_LEN(sizeof(int))) err(1,"Not the right length for a file descriptor"); if ( cmptr->cmsg_level != SOL_SOCKET) err(1,"Not the right SOCKED packet"); if (cmptr->cmsg_type != SCM_RIGHTS) err(1,"Not the right RIGHTS packet"); fd= *(int *)CMSG_DATA(cmptr); #endif /* RFC2292API */ printf ("FD: %d\n", fd); if ((lseek(fd,0,SEEK_END))==-1) err(1,"could not set fileptr"); if ((write(fd,"GOTCHA\n",7))==-1) err(1,"could not write"); close(fd); close(sock); close(s); exit(0); } /*>r,c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <err.h> #include <sys/types.h> #include <sys/time.h> #include <string.h> #include <sys/uio.h> #include <sys/socket.h> #include <sys/un.h> #include <fcntl.h> #include <sys/fcntl.h> #include <sys/stat.h> #ifdef RFC2292API #include <sys/param.h> /* for ALIGN macro */ #endif /* RFC2292API */ #ifndef lint #ifdef RFC2292API static const char rcsid[] = "$Id: r.c,v 1.4 1998/08/30 07:21:11 dirkx Exp $"; #else static const char rcsid[] = "$Id: s.c,v 1.4 1998/08/29 01:05:28 wpaul Exp $"; #endif /* RFC2292API */ #endif #ifndef RFC2292API struct cmessage { struct cmsghdr cmsg; int fd; }; #else #ifndef CMSG_LEN # define CMSG_LEN(x) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(x)) #endif #ifndef CMSG_SPACE # define CMSG_SPACE(x) ( ALIGN(sizeof(struct cmsghdr)) + x) #endif #endif /* RFC2292API */ int main() { struct iovec iov[1]; struct msghdr msg; #ifndef RFC2292API struct cmessage cm; #else union { struct cmsghdr cm; char control[ CMSG_SPACE( sizeof( int ) ) ]; } cmsgbuf; struct cmsghdr * cmptr; #endif /* RFC2292API */ struct sockaddr_un sun; int s,fd; int len; char sendbuf[] = "This is a test buffer."; if ((fd=open("/tmp/test",O_CREAT|O_RDWR|O_TRUNC,0666))==-1) err(1,"could not open file"); if ((fd = open("/tmp/test",O_CREAT | O_RDWR,0666)) == -1) err(1,"could not create my file"); if ((write(fd,"SEND\n",5))==-1) err(1,"Could not write"); strcpy(sun.sun_path, "/tmp/testsock"); sun.sun_family = AF_UNIX; len = sun.sun_len = sizeof(sun.sun_len) + sizeof(sun.sun_family) + strlen(sun.sun_path) + 1; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket creation failed"); if (connect(s, (struct sockaddr *)&sun, len) == -1) err(1, "couldn't connect socket"); iov[0].iov_base = (char *)&sendbuf; iov[0].iov_len = sizeof(sendbuf); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_flags = 0; #ifndef RFC2292API msg.msg_control = (caddr_t)&cm; msg.msg_controllen = sizeof(struct cmessage); cm.cmsg.cmsg_type = SCM_RIGHTS; cm.cmsg.cmsg_level = SOL_SOCKET; cm.cmsg.cmsg_len = sizeof(struct cmessage); cm.fd = fd; /* file descriptor to be transfered */ #else msg.msg_control = (caddr_t)&cmsgbuf.control; msg.msg_controllen = sizeof cmsgbuf.control; /* make sure we are aligned... */ cmptr = CMSG_FIRSTHDR( &msg ); cmptr->cmsg_len = CMSG_LEN( sizeof(int) ); cmptr->cmsg_level = SOL_SOCKET; cmptr->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmptr) = fd; /* file descriptor to be transfered */ #endif /* RFC2292API */ if ((len = sendmsg(s, &msg, 0)) == -1) err(1, "sendmsg failed"); printf ("sent message (%d bytes), fd=%d sending data...\n", len,fd); close(fd); close(s); exit(0); } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.96.980829192032.7282A-100000>