/* * Send a file descriptor through a Unix domain socket * * Unfortunately, this program is probably not exactly 100% portable. * * One strange wrinkle required by at least certain versions of Linux * is that you must also send a non-empty message (that's why the code * below sends the string "hello" in addition to the file descriptor). * * Author: Daniel Boulet (danny@obtuse.com) * * Copyright 1997, 1999 Daniel Boulet * All rights reserved * * Permission is granted to use this software in any way you like as long * as this entire comment is included in the source code. * * THIS SOFTWARE IS PROVIDED WITHOUT WARRANTEE OF ANY KIND WHAT-SO-EVER. */ /* * Portability experience: * * OS Experience * -------------------------------------------------------------------- * BSD/OS seems to work as-is * Linux kernel 2.2 seems to work as-is * AIX 4.3 seems to work as-is * OpenBSD seems to work as-is * Solaris 2.6 requires a few changes: * - msg_control renamed as msg_accrights * - msg_controllen renamed as msg_accrightslen * - set msg_accrights to point at int containing fd * - set msg_accrights to sizeof(int) * * Please let me know your experiences on other Unix variants. */ #include #include #include #include main() { int pair[2]; struct msghdr mh; struct cmsghdr cmh[2]; struct iovec iov; char tbuf[100]; int fd; int rlen; pid_t pid; char buffer[1024]; if ( socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0 ) { perror("socketpair"); exit(1); } fflush(stdout); fflush(stderr); switch ( pid = fork() ) { case 0: /* Child sends the file descriptor */ fd = open("sendfd.c",0); if ( fd < 0 ) { perror("open"); exit(0); } memset(&mh,0,sizeof(mh)); mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = (caddr_t)&cmh[0]; mh.msg_controllen = sizeof(cmh[0]) + sizeof(int); mh.msg_flags = 0; iov.iov_base = "hello"; iov.iov_len = strlen(iov.iov_base) + 1; cmh[0].cmsg_level = SOL_SOCKET; cmh[0].cmsg_type = SCM_RIGHTS; cmh[0].cmsg_len = sizeof(cmh[0]) + sizeof(int); *(int *)&cmh[1] = fd; if ( sendmsg(pair[1],&mh,0) < 0 ) { perror("sendmsg"); exit(1); } close(fd); printf("child done\n"); fflush(stdout); exit(0); case -1: /* Oops! */ perror("fork"); exit(1); default: /* Parent receives the file descriptor */ mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = (caddr_t)&cmh[0]; mh.msg_controllen = sizeof(cmh[0]) * 2; iov.iov_base = tbuf; iov.iov_len = sizeof(tbuf); cmh[0].cmsg_len = sizeof(cmh[0]) + sizeof(int); if ( (rlen = recvmsg(pair[0],&mh,0)) < 0 ) { perror("recvmsg"); exit(1); } fd = *(int *)&cmh[1]; printf("rlen = %d msg_controllen = %d, cmsg_len = %d\n", rlen,mh.msg_controllen,cmh[0].cmsg_len); printf("cmsg_level = %d, cmsg_type = %d, fd = %d\n", cmh[0].cmsg_level,cmh[0].cmsg_type,fd); while ( (rlen = read(fd,buffer,sizeof(buffer))) > 0 ) { write(1,buffer,rlen); } if ( rlen < 0 ) { perror("read"); exit(1); } exit(0); } }