#define _XOPEN_SOURCE 1 #define _XOPEN_SOURCE_EXTENDED 1 /* hacked from a source by Kragen Sitaker, see http://lists.canonical.org/pipermail/kragen-hacks/2002-January/000292.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /***** FIRST PROCESS CODE HERE ******/ static struct sockaddr_un unix_socket_name = {0}; static int send_connection(int fd, int unix_socket_fd) { struct msghdr msg; char ccmsg[CMSG_SPACE(sizeof(fd))]; struct cmsghdr *cmsg; struct iovec vec; /* stupidity: must send/receive at least one byte */ char *str = "x"; int rv; msg.msg_name = (struct sockaddr*)&unix_socket_name; msg.msg_namelen = sizeof(unix_socket_name); vec.iov_base = str; vec.iov_len = 1; msg.msg_iov = &vec; msg.msg_iovlen = 1; /* old BSD implementations should use msg_accrights instead of * msg_control; the interface is different. */ msg.msg_control = ccmsg; msg.msg_controllen = sizeof(ccmsg); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); *(int*)CMSG_DATA(cmsg) = fd; msg.msg_controllen = cmsg->cmsg_len; msg.msg_flags = 0; rv = (sendmsg(unix_socket_fd, &msg, 0) != -1); if (rv) close(fd); return rv; } #ifndef UNIX_PATH_MAX /* uh-oh, nothing safe to do here */ static int UNIX_PATH_MAX = sizeof(unix_socket_name.sun_path); #endif static int open_unix_fd(const char *path) { int unix_socket_fd; unix_socket_name.sun_family = AF_UNIX; if (strlen(path) >= UNIX_PATH_MAX - 1) return 0; strcpy(unix_socket_name.sun_path, path); unix_socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (unix_socket_fd == -1) return -1; return unix_socket_fd; } int proc1(const char *filename, const char *sockpath) { int fd; int sockfd; if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) < 0) { perror("opening file"); exit(1); } if ((sockfd = open_unix_fd(sockpath)) < 0) { perror("opening Unix fd"); exit(1); } sleep(1); /* hack: make sure child is ready (should use real IPC) */ if (!send_connection(fd, sockfd)) { perror("send_connection"); exit(1); } exit(0); } /******* PROCESS 2 CODE HERE *******/ /* open a PF_UNIX SOCK_DGRAM socket bound to 'path' */ static int sock_dgram(const char *path) { struct sockaddr_un unix_socket_name = {0}; int fd; if (unlink(path) < 0) { if (errno != ENOENT) { fprintf(stderr, "%s: ", path); perror("unlink"); return -1; } } unix_socket_name.sun_family = AF_UNIX; if (strlen(path) >= sizeof(unix_socket_name.sun_path)) return -1; strcpy(unix_socket_name.sun_path, path); fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (fd == -1) return -1; if (bind(fd, (struct sockaddr *)&unix_socket_name, sizeof(unix_socket_name))) { close(fd); return -1; } return fd; } /* receive a file descriptor over file descriptor fd */ static int receive_fd(int fd) { struct msghdr msg; struct iovec iov; char buf[1]; int rv; int connfd = -1; char ccmsg[CMSG_SPACE(sizeof(connfd))]; struct cmsghdr *cmsg; iov.iov_base = buf; iov.iov_len = 1; msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; /* old BSD implementations should use msg_accrights instead of * msg_control; the interface is different. */ msg.msg_control = ccmsg; msg.msg_controllen = sizeof(ccmsg); /* ? seems to work... */ rv = recvmsg(fd, &msg, 0); if (rv == -1) { perror("recvmsg"); return -1; } cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg->cmsg_type == SCM_RIGHTS) { fprintf(stderr, "got control message of unknown type %d\n", cmsg->cmsg_type); return -1; } return *(int*)CMSG_DATA(cmsg); } void proc2(const char *path) { int sockfd; int fd; char *string = "hello, world!\n"; sockfd = sock_dgram(path); if (sockfd == -1) { perror("sock_dgram"); return; } fd = receive_fd(sockfd); if (fd == -1) { close(sockfd); return; } write(fd, string, strlen(string)); exit(0); } /******* MAIN CODE HERE *******/ int main(int argc, char **argv) { const char *sockpath = "/tmp/mysocket"; const char *filename = "/tmp/foobar"; pid_t pid1, pid2; int status; if ((pid1 = fork()) == 0) proc1(filename, sockpath); if ((pid2 = fork()) == 0) proc2(sockpath); waitpid(pid1, &status, 0); waitpid(pid2, &status, 0); return 0; }