| |
| /* On AIX 5.2, _LINUX_SOURCE_COMPAT needs to be defined when reading |
| sys/socket.h in order to make CMSG_SPACE and CMSG_LEN visible. */ |
| |
| #if defined(_AIX) |
| #define _LINUX_SOURCE_COMPAT 1 |
| #endif |
| |
| #include <sys/socket.h> |
| |
| #if defined(_AIX) |
| #undef _LINUX_SOURCE_COMPAT |
| #endif |
| |
| |
| /* Needed for 'memset' on AIX 5.2 */ |
| #if defined(_AIX) |
| # include <memory.h> |
| #endif |
| |
| |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/un.h> |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| |
| |
| char filea[24]; |
| char fileb[24]; |
| char sock[24]; |
| |
| void |
| server (void) |
| { |
| int s, fd1, fd2; |
| struct sockaddr_un addr; |
| |
| fd1 = open(filea, O_RDWR | O_CREAT | O_TRUNC, 0750); |
| if(fd1 == -1) { |
| perror("open"); |
| exit(1); |
| } |
| |
| fd2 = open(fileb, O_RDWR | O_CREAT | O_TRUNC, 0750); |
| if(fd2 == -1) { |
| perror("open"); |
| exit(1); |
| } |
| |
| s = socket(PF_UNIX, SOCK_STREAM, 0); |
| if(s == -1) { |
| perror("socket"); |
| exit(1); |
| } |
| |
| memset(&addr, 0, sizeof(addr)); |
| addr.sun_family = AF_UNIX; |
| sprintf(addr.sun_path, sock); |
| |
| unlink(addr.sun_path); |
| if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { |
| perror("bind"); |
| exit(1); |
| } |
| |
| if(listen(s, 5) == -1) { |
| perror("listen"); |
| exit(1); |
| } |
| |
| { |
| int x; |
| int baddrsize = 0; |
| struct sockaddr_un baddr; |
| struct msghdr msg = {NULL, 0, NULL, 0, 0, 0, 0}; |
| struct cmsghdr *cmsg; |
| char buf[CMSG_SPACE(sizeof(int) * 2)]; |
| struct iovec iov[1]; |
| |
| memset(&baddr, 0, sizeof(baddr)); |
| x = accept(s, (struct sockaddr *)&baddr, &baddrsize); |
| if(x == -1) { |
| perror("accept"); |
| exit(1); |
| } |
| |
| msg.msg_control = buf; |
| msg.msg_controllen = sizeof(buf); |
| cmsg = CMSG_FIRSTHDR(&msg); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = SCM_RIGHTS; |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 2); |
| ((int *)CMSG_DATA(cmsg))[0] = fd1; |
| ((int *)CMSG_DATA(cmsg))[1] = fd2; |
| |
| iov[0].iov_base = "hello"; |
| iov[0].iov_len = 6; |
| |
| msg.msg_iov = iov; |
| msg.msg_iovlen = 1; |
| |
| if(sendmsg(x, &msg, 0) == -1) { |
| perror("sendmsg"); |
| exit(1); |
| } |
| } |
| } |
| |
| void |
| client (void) |
| { |
| int s, fd1 = -1, fd2 = -1, size, count = 0, ret; |
| struct sockaddr_un addr; |
| struct iovec iov[1]; |
| union { |
| struct cmsghdr cm; |
| char control[CMSG_SPACE(sizeof(int) * 2)]; |
| } control_un; |
| struct msghdr msg = { NULL, 0, iov, 1, control_un.control, |
| sizeof(control_un), 0 }; |
| struct cmsghdr *cmsg = &control_un.cm; |
| char buf[1024]; |
| |
| iov[0].iov_base = buf; |
| iov[0].iov_len = sizeof(buf); |
| |
| s = socket(PF_UNIX, SOCK_STREAM, 0); |
| if(s == -1) { |
| perror("socket"); |
| exit(1); |
| } |
| |
| addr.sun_family = AF_UNIX; |
| sprintf(addr.sun_path, sock); |
| |
| do { |
| count++; |
| ret = connect(s, (struct sockaddr *)&addr, sizeof(addr)); |
| if(ret == -1) sleep(1); |
| } while (count < 10 && ret == -1); |
| |
| if(ret == -1) { |
| perror("connect"); |
| exit(1); |
| } |
| |
| again: |
| if((size = recvmsg(s, &msg, 0)) == -1) { |
| if (errno == EINTR) |
| goto again; /* SIGCHLD from server exiting could interrupt */ |
| perror("recvmsg"); |
| exit(1); |
| } |
| |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| while(cmsg) { |
| if(cmsg->cmsg_level == SOL_SOCKET && |
| cmsg->cmsg_type == SCM_RIGHTS && |
| cmsg->cmsg_len == CMSG_LEN(sizeof(int) * 2)) { |
| fd1 = ((int *)CMSG_DATA(cmsg))[0]; |
| fd2 = ((int *)CMSG_DATA(cmsg))[1]; |
| } |
| |
| cmsg = CMSG_NXTHDR(&msg, cmsg); |
| } |
| |
| if(fd1 != -1) write(fd1, "Yeah 1\n", 8); |
| if(fd2 != -1) write(fd2, "Yeah 2\n", 8); |
| } |
| |
| |
| int |
| main (int argc, char **argv) |
| { |
| int pid, status; |
| |
| /* |
| * Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it |
| * now to get consistent results across different releases. |
| */ |
| |
| close(10); |
| |
| pid = getpid(); |
| sprintf(filea, "/tmp/data1.%d", pid); |
| sprintf(fileb, "/tmp/data2.%d", pid); |
| sprintf(sock, "/tmp/sock.%d", pid); |
| |
| if((pid = fork()) == 0) { |
| server(); |
| return 0; |
| } |
| |
| client(); |
| |
| wait(&status); |
| |
| unlink(filea); |
| unlink(fileb); |
| unlink(sock); |
| return 0; |
| } |