#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
ssize_t send_fd(int sock, const char *buf, size_t len, int fd);
ssize_t recv_fd(int sock, char *buf, size_t len, int *fd);
void child_process();
const char *socket_path = "fd.sock";
int main(int argc, char **argv) {
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, socket_path);
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock == -1) {
perror("socket");
return -1;
}
if(bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
perror("bind");
return -1;
}
if(listen(sock, 8) == -1) {
perror("listen");
return -1;
}
pid_t pid = fork();
if(pid == 0) {
close(sock);
child_process();
return 0;
}
int fd = accept(sock, NULL, 0);
if(fd == -1) {
perror("accept");
return -1;
}
printf("client connected\n");
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int file = open("testfile", O_WRONLY | O_CREAT, mode);
printf("testfile fd = %d\n", file);
const char *msg = "Hello World!";
send_fd(fd, msg, strlen(msg), file);
int status;
waitpid(pid, &status, 0);
close(file);
close(fd);
close(sock);
if(unlink(socket_path)) {
perror("unlink");
}
return 0;
}
void child_process() {
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, socket_path);
int client = socket(AF_UNIX, SOCK_STREAM, 0);
if(client == -1) {
perror("client: socket");
return;
}
if(connect(client, (struct sockaddr*)&addr, sizeof(addr))) {
perror("client: connect");
return;
}
printf("client connected\n");
char buf[1024];
int fd;
ssize_t r = recv_fd(client, buf, 1024, &fd);
printf("msg: {%.*s}\n", (int)r, buf);
printf("fd: %d\n", fd);
if(r > 0 && fd != -1) {
printf("write msg to fd\n");
write(fd, buf, r);
close(fd);
}
close(client);
}
ssize_t send_fd(int sock, const char *buf, size_t len, int fd) {
struct msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
struct iovec iov[1] ;
iov[0].iov_base = (void*)buf;
iov[0].iov_len = len;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
char cmsg_buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr *cmsg = (struct cmsghdr*)cmsg_buf;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
int *data = (int*)CMSG_DATA(cmsg);
*data = fd;
msg.msg_control = cmsg;
msg.msg_controllen = CMSG_LEN(sizeof(int));
msg.msg_flags = 0;
return sendmsg(sock, &msg, 0);
}
ssize_t recv_fd(int sock, char *buf, size_t len, int *fd) {
struct msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
struct iovec iov[1];
iov[0].iov_base = buf;
iov[0].iov_len = len;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
char cmsg_buf[CMSG_SPACE(sizeof(int))];
memset(cmsg_buf, 0, CMSG_SPACE(sizeof(int)));
struct cmsghdr *cmsg = (struct cmsghdr*)cmsg_buf;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
msg.msg_control = cmsg;
msg.msg_controllen = CMSG_LEN(sizeof(int));
msg.msg_flags = 0;
ssize_t r = recvmsg(sock, &msg, 0);
if(r != -1) {
int *data = (int*)CMSG_DATA(cmsg);
*fd = *data;
} else {
*fd = -1;
}
return r;
}