User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

c:sendfd [2019-05-28 15:26] (current)
Line 1: Line 1:
 +
 +=====Sending file/socket descriptors between pair of processes =====
 +
 +<code C 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;
 +}
 +</​code>​
 +
 +<code C 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;
 +}
 +</​code>​
 +
 +----
 +[<>]