User Tools

Site Tools


Sending file/socket descriptors between pair of processes

mainserv.c
/*
 * Copyright 2004-2019 Oleg Borodin  <borodin@unix7.org>
 */
 
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
 
ssize_t sendfd(int sock, int fd) {
    struct msghdr msg;
    struct cmsghdr* cmsg;
    union {
        struct cmsghdr hdr;
        unsigned char buf[CMSG_SPACE(sizeof(int))];
    } cmsgbuf;
 
    struct iovec iov[1];
    char ch = '*';
    iov[0].iov_base = &ch;
    iov[0].iov_len = 1;
 
    memset(&msg, 0, sizeof(msg));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
 
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    *(int*)CMSG_DATA(cmsg) = fd;
 
    ssize_t res = -1;
    res = sendmsg(sock, &msg, 0);
    return res;
}
 
int main(int argc, char **argv) {
 
    char sockpath[] = "/tmp/unix-socket";
 
    pid_t pid = fork();
    if (pid == 0){
        /* into the child */
        char subserv[] = "./subserv";
        char* args[] = { subserv, sockpath, NULL };
        int res = execv(subserv, args);
 
        fprintf(stderr, "exec res %d\n", res);
    }
    if (pid < 0) {
        fprintf(stderr, "unable fork, exit\n");
        exit(1);
    }
 
    int sock = -1;
    if((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
        fprintf(stderr, "unable create unix socket, exit\n");
        exit(1);
    }
 
    struct sockaddr sockaddr;
    memset(&sockaddr, 0, sizeof(struct sockaddr));
 
    struct sockaddr_un* paddr = (struct sockaddr_un*)&sockaddr;
    paddr->sun_family = AF_UNIX;
    strcpy(paddr->sun_path, sockpath);
 
    socklen_t socklen = sizeof(struct sockaddr_un);
 
    sleep(1);
 
    if (connect(sock, (struct sockaddr*)&sockaddr, socklen) < 0) {
        fprintf(stderr, "unable connect to unix socket, exit.\n");
        exit(1);
    }
 
    fprintf(stderr, "connect to unix socket %d\n", sock);
 
    int fd = -1;
    if ((fd = open("test.txt", O_RDWR | O_APPEND | O_CREAT, 0644)) < 0) {
        fprintf(stderr, "unable open file, exit.\n");
        exit(1);
    }
 
    while(true) {
        ssize_t res = sendfd(sock, fd);
        fprintf(stderr, "send %d chars\n", (int)res);
        sleep(1);
    }
    close(fd);
    close(sock);
 
    kill(pid, SIGTERM);
 
    int status;
    waitpid(pid, &status, 0);
 
    return 0;
}
subserv.c
/*
 * Copyright 2004-2019 Oleg Borodin  <borodin@unix7.org>
 */
 
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/un.h>
#include <string.h>
#include <err.h>
 
int recvfd (int sock) {
        struct msghdr msg;
        struct cmsghdr *cmsg;
        union {
            struct cmsghdr hdr;
            unsigned char buf[CMSG_SPACE(sizeof(int))];
        } cmsgbuf;
        struct iovec iov[1];
        char ch;
        iov[0].iov_base = &ch;
        iov[0].iov_len = 1;
 
        memset(&msg, 0, sizeof(msg));
        msg.msg_control = &cmsgbuf.buf;
        msg.msg_controllen = sizeof(cmsgbuf.buf);
        msg.msg_iov = iov;
        msg.msg_iovlen = 1;
 
        if (recvmsg(sock, &msg, 0) == -1) {
            return -1;
        }
        if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) {
            return -1;
        }
        for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
            if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
                int fd = *(int*)CMSG_DATA(cmsg);
                return fd;
            }
        }
        return -1;
}
 
int main(int argc, char **argv) {
 
    //const char sockpath[] = "unix-socket";
    char* sockpath = argv[1];
 
    int sock = -1;
    if((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
        fprintf(stderr, "unable create unix socket, exit\n");
        exit(1);
    }
 
    struct sockaddr sockaddr;
    memset(&sockaddr, 0, sizeof(struct sockaddr));
 
    struct sockaddr_un* paddr = (struct sockaddr_un*)&sockaddr;
    paddr->sun_family = AF_UNIX;
    strcpy(paddr->sun_path, sockpath);
 
    unlink(sockpath);
 
    socklen_t socklen = sizeof(struct sockaddr_un);
 
    if (bind(sock, (struct sockaddr*)paddr, socklen) < 0) {
        fprintf(stderr, "unable bind unix socket, exit\n");
        close(sock);
        exit(1);
    }
    int backlog = 1024;
    if (listen(sock, backlog) < 0) {
        fprintf(stderr, "unable listen unix socket, exit\n");
        close(sock);
        exit(1);
    }
 
    fprintf(stderr, "do accept with socket %d\n", sock);
 
    while (1) {
        int fd = -1;
        if ((fd = recvfd(sock)) > 0) {
            write(fd, "hello\n", 6);
            close(fd);
        }
    }
    close(sock);
    unlink(sockpath);
 
    return 0;
}

First PagePrevious PageBack to overviewNext PageLast Page