UNP函数笔记十二: Unix域协议

第十五章  Unix域协议:

#include <sys/un.h>
struct sockaddr_un {
    sa_family_t  sun_family;    /* AF_LOCAL */
    char         sun_path[104]; /* null-teminated pathname */
};
sun_path[0] means any-address

#include <sys/socket.h>
int socketpair(int family, int type, int protocol, int sockfd[2]);
    family: AF_LOCAL
    type: SOCK_STREAM, SOCK_DGRAM
    protocol: 0
    success return non-zero, error return -1

#include <sys/socket.h>
struct cmsgcred { /* cannot find in Linux */
    pid_t  cmcred_pid;   /* PID of sending process */
    uid_t  cmcred_uid;   /* real UID of sending process */
    uid_t  cmcred_euid;  /* effective UID of sending process */
    gid_t  cmcred_gid;   /* read GID of sending process */
    short  cmcred_ngroups;  /* number of groups */
    gid_t  cmcred_groups[CMGROUP_MAX];  /* groups */
};
CMGROUP_MAX is 16, cmcred_ngroups >= 1, cmcred_groups[0] is effective gid

示例:

#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>

#include "err_exit.h"
#include "my_signal.h"

#define PORT        9999
#define ADDR        "127.0.0.1"
#define MAXBACKLOG  100

struct sockaddr_in  serv;
pid_t               pid;

int            pipefd[2];

void do_parent(void);
void do_child(void);

int 
main(int argc, char ** argv)
{
    if (argc != 1) {
        printf("usage: %s\n", argv[0]);
    }

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd) == -1) {
        err_exit("socketpair error");
    }

    bzero(&serv, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(PORT);
    if (inet_pton(AF_INET, ADDR, &serv.sin_addr) <= 0) {
        err_exit("inet_pton error");
    }

    if ((pid = fork()) < 0) {
        err_exit("fork error");
    }
    else if (pid == 0) {
        do_child();
    }
    else {
        do_parent();
    }
        
    exit(0);
}

void 
parent_alrm(int signo)
{
    return;  /* just interrupt blocked connect() */
}

void 
do_parent(void)
{
    int  backlog;
    int  j;
    int  k;
    int  junk;
    int  fd[MAXBACKLOG + 1];

    if (close(pipefd[0]) == -1) {
        err_exit("close error");
    }
    if (my_signal(SIGALRM, parent_alrm) == SIG_ERR) {
        err_exit("my_signal error");
    }

    for (backlog = 0; backlog <= 14; backlog++) {
        printf("backlog = %d: ", backlog);

        /* tell child value */
        if (write(pipefd[1], &backlog, sizeof(int)) != sizeof(int)) {
            err_exit("write error");
        }

        /* wait for child */
        if (read(pipefd[1], &junk, sizeof(int)) < 0) {
            err_exit("read error");
        }

        for (j = 1; j <= MAXBACKLOG; j++) {
            if ((fd[j] = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                err_exit("socket error");
            }
            alarm(2);
            if (connect(fd[j], (struct sockaddr *)&serv, sizeof(serv)) < 0) {
                if (errno != EINTR) {
                    printf("connect error, j = %d\n", j);
                    exit(1);
                }
                printf("timeout, %d connections completed\n", j-1);
                for (k = 1; k <= j; k++) {
                    if (close(fd[k]) == -1) {
                        err_exit("close error");
                    }
                }
                break;  /* next value of backlog */
            }
            alarm(0);
        }
        if (j > MAXBACKLOG) {
            printf("%d connections?\n", MAXBACKLOG);
        }
    }
    backlog = -1;  /* tell child we're all done */
    if (write(pipefd[1], &backlog, sizeof(int)) != sizeof(int)) {
        err_exit("write error");
    }
}

void 
do_child(void)
{
    int        listenfd;
    int        backlog;
    int        junk;
    const int  on = 1;

    if (close(pipefd[1]) == -1) {
        err_exit("close error");
    }

    /* wait for parent */
    if (read(pipefd[0], &backlog, sizeof(int)) != sizeof(int)) {
        err_exit("read error");
    }

    while (backlog >= 0) {
        if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            err_exit("socket error");
        }
        if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, 
                       sizeof(on)) == -1) {
            err_exit("setsockopt error");
        }
        if (bind(listenfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) {
            err_exit("bind error");
        }
        if (listen(listenfd, backlog) == -1) {  /* start the listen */
            err_exit("listen error");
        }

        /* tell parent */
        if (write(pipefd[0], &junk, sizeof(int)) != sizeof(int)) {
            err_exit("write error");
        }

        /* just wait for parent */
        if (read(pipefd[0], &backlog, sizeof(int)) != sizeof(int)) {
            err_exit("read error");
        }

        /* closes all queued connections, too */
        if (close(listenfd) == -1) {
            err_exit("close error");
        }
    }
}
#include <sys/socket.h>
#include <sys/param.h>

#include "err_exit.h"

#define HAVE_MSGHDR_MSG_CONTROL 1

ssize_t 
write_fd(int fd, void * ptr, size_t nbytes, int sendfd)
{
    struct msghdr  msg;
    struct iovec   iov[1];

#ifdef HAVE_MSGHDR_MSG_CONTROL
    union {
        struct cmsghdr  cm;
        char            control[CMSG_SPACE(sizeof(int))];
    } control_un;
    struct cmsghdr * cmptr;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);

    cmptr = CMSG_FIRSTHDR(&msg);
    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type = SCM_RIGHTS;
    *((int *)CMSG_DATA(cmptr)) = sendfd;
#else
    msg.msg_accrights = (caddr_t) &sendfd;
    msg.msg_accrightslen = sizeof(int);
#endif

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    return(sendmsg(fd, &msg, 0));
}
#include "err_exit.h"
#include "write_fd.h"

int 
main(int argc, char ** argv)
{
    int  fd;

    if (argc != 4) {
        printf("openfile <sockfd#> <filename> <mode>\n");
        exit(1);
    }

    if ((fd = open(argv[2], atoi(argv[3]))) < 0) {
        exit(errno > 0 ? errno : 255);
    }

    if (write_fd(atoi(argv[1]), "", 1, fd) < 0) {
        exit(errno > 0 ? errno : 255);
    }

    exit(0);
}
#include <sys/socket.h>
#include <sys/param.h>

#include "err_exit.h"

#define HAVE_MSGHDR_MSG_CONTROL 1

ssize_t 
read_fd(int fd, void * ptr, size_t nbytes, int * recvfd)
{
    struct msghdr  msg;
    struct iovec   iov[1];
    ssize_t        n;

#ifdef HAVE_MSGHDR_MSG_CONTROL
    union {
        struct cmsghdr  cm;
        char            control[CMSG_SPACE(sizeof(int))];
    } control_un;
    struct cmsghdr * cmptr;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);
#else
    int                newfd;

    msg.msg_accrights = (caddr_t) &newfd;
    msg.msg_accrightslen = sizeof(int);
#endif

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    if ((n = recvmsg(fd, &msg, 0)) <= 0) {
        return(n);
    }

#ifdef HAVE_MSGHDR_MSG_CONTROL
    if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
        cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
        if (cmptr->cmsg_level != SOL_SOCKET) {
            err_exit("control level != SOL_SOCKET");
        }
        if (cmptr->cmsg_type != SCM_RIGHTS) {
            err_exit("control type != SCM_RIGHTS");
        }
        *recvfd = *((int *)CMSG_DATA(cmptr));
    }
    else {
        *recvfd = -1;  /* descriptor was not passed */
    }
#else
    if (msg.msg_accrightslen == sizeof(int)) {
        *recvfd = newfd;
    }
    else {
        *recvfd = -1;  /* descriptor was not passed */
    }
#endif

    return(n);
}
#include <sys/socket.h>
#include <wait.h>
#include <unistd.h>

#include "err_exit.h"

int 
my_open(const char * pathname, int mode)
{
    int    fd;
    int    sockfd[2];
    int    status;
    pid_t  childpid;
    char   c;
    char   argsockfd[10];
    char   argmode[10];

    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) == -1) {
        err_exit("socketpair error");
    }

    if ((childpid = fork()) < 0) {
        err_exit("fork error");
    }
    else if (childpid == 0) {
        if (close(sockfd[0]) == -1) {
            err_exit("close error");
        }
        snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);
        snprintf(argmode, sizeof(argmode), "%d", mode);
        execl("./openfile", "openfile", argsockfd, pathname, argmode, NULL);
        err_exit("execl error");
    }

    if (close(sockfd[1]) == -1) {
        err_exit("close error");
    }

    if (waitpid(childpid, &status, 0) <= 0) {
        err_exit("waitpid error");
    }

    if (WIFEXITED(status) == 0) {
        err_exit("child did not terminate");
    }
    if ((status = WEXITSTATUS(status)) == 0) {
        if (read_fd(sockfd[0], &c, 1, &fd) <= 0) {
            err_exit("read_fd error");
        }
    }
    else {
        errno = status;  /* set errno value from child's status */
        fd = -1;
    }

    if (close(sockfd[0]) == -1) {
        err_exit("close error");
    }

    return(fd);
}
#include <fcntl.h>
#include <unistd.h>

#include "err_exit.h"
#include "myopen.h"

#define BUFFSIZE 4096

int 
main(int argc, char ** argv)
{
    int   fd;
    int   n;
    char  buff[BUFFSIZE];

    if (argc != 2) {
        printf("usage: mycat <pathname>\n");
        exit(1);
    }

    if ((fd = my_open(argv[1], O_RDONLY)) < 0) {
        printf("cannot open %s\n", argv[1]);
        exit(1);
    }

    while ((n = read(fd, buff, BUFFSIZE)) > 0) {
        if (write(STDOUT_FILENO, buff, n) != n) {
            err_exit("write error");
        }
    }
    if (n < 0) {
        err_exit("read error");
    }

    exit(0);
}
#include <sys/socket.h>
#include <sys/un.h>
#include "err_exit.h"

int 
main(int argc, char ** argv)
{
    int                 sockfd;
    socklen_t           len;
    struct sockaddr_un  addr1;
    struct sockaddr_un  addr2;

    if (argc != 2) {
        printf("usage: unixbind <pathname>\n");
        exit(1);
    }

    if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
        err_exit("socket error");
    }

    unlink(argv[1]);  /* OK if this fails */

    bzero(&addr1, sizeof(addr1));
    addr1.sun_family = AF_LOCAL;
    strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path)-1);
    if (bind(sockfd, (struct sockaddr *)&addr1, SUN_LEN(&addr1)) == -1) {
        err_exit("bind error");
    }

    len = sizeof(addr2);
    if (getsockname(sockfd, (struct sockaddr *)&addr2, &len) == -1) {
        err_exit("getsockname error");
    }
    printf("bound name = %s, returned len = %d\n", addr2.sun_path, len);
    
    exit(0);
}
#include <sys/socket.h>
#include <sys/un.h>

#include "err_exit.h"

#define UNIXDG_PATH "/tmp/uinxdg"

int 
main(int argc, char ** argv)
{
    int                 sockfd;
    struct sockaddr_un  servaddr;
    struct sockaddr_un  cliaddr;

    if ((sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) {
        err_exit("socket error");
    }

    unlink(UNIXDG_PATH);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sun_family = AF_LOCAL;
    strcpy(servaddr.sun_path, UNIXDG_PATH);

    if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
        err_exit("bind error");
    }

    dg_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
}
#include <sys/socket.h>
#include <sys/un.h>
#include "err_exit.h"

#define UNIXDG_PATH "/tmp/uinxdg"

int 
main(int argc, char ** argv)
{
    int                 sockfd;
    struct sockaddr_un  cliaddr;
    struct sockaddr_un  servaddr;

    if ((sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) {
        err_exit("socket error");
    }

    bzero(&cliaddr, sizeof(cliaddr));  /* bind an address for us */
    cliaddr.sun_family = AF_LOCAL;
    strcpy(cliaddr.sun_path, tmpnam(NULL));

    if (bind(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) == -1) {
        err_exit("bind error");
    }

    bzero(&servaddr, sizeof(servaddr));  /* fill in server's address */
    servaddr.sun_family = AF_LOCAL;
    strcpy(servaddr.sun_path, UNIXDG_PATH);

    dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    exit(0);
}
#include <sys/socket.h>
#include <sys/un.h>

#include "err_exit.h"

#define UNIXSTR_PATH "/tmp/unixstr"

int 
main(int argc, char ** argv)
{
    int                 sockfd;
    struct sockaddr_un  servaddr;

    if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
        err_exit("socket error");
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sun_family = AF_LOCAL;
    strcpy(servaddr.sun_path, UNIXSTR_PATH);

    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
        err_exit("connect error");
    }

    str_cli(stdin, sockfd);

    exit(0);
}
#include <sys/socket.h>
#include <sys/un.h>
#include "err_exit.h"
#include "my_signal.h"

#define LISTENQ 1024
#define UNIXSTR_PATH "/tmp/unixstr"

void 
sig_chld(int signo)
{
    pid_t  pid;
    int    stat;

    while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
        printf("child %d terminated\n", pid);
    }
    return;
}

int 
main(int argc, char ** argv)
{
    int                 listenfd;
    int                 connfd;
    pid_t               childpid;
    socklen_t           clilen;
    struct sockaddr_un  cliaddr;
    struct sockaddr_un  servaddr;

    if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
        err_exit("socket error");
    }

    unlink(UNIXSTR_PATH);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sun_family = AF_LOCAL;
    strcpy(servaddr.sun_path, UNIXSTR_PATH);

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
        err_exit("bind error");
    }

    if (listen(listenfd, LISTENQ) == -1) {
        err_exit("listen error");
    }

    if (my_signal(SIGCHLD, sig_chld) == SIG_ERR) {
        err_exit("my_signal error");
    }

    for ( ; ; ) {
        clilen = sizeof(cliaddr);
        if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, 
                             &clilen)) < 0) {
            if (errno == EINTR) {
                continue;  /* back to for() */
            }
            else {
                err_exit("accept error");
            }
        }

        if ((childpid = fork()) < 0) {
            err_exit("fork error");
        }
        else if (childpid == 0) {
            if (close(listenfd) == -1) {
                err_exit("close error");
            }
            str_echo(connfd);
            exit(0);
        }
        if (close(connfd) == -1) {
            err_exit("close error");
        }
    }
}
#include <sys/socket.h>

#include "err_exit.h"

#define  CONTROL_LEN  (sizeof(struct cmsghdr) + sizeof(struct cmsgcred))

ssize_t 
read_cred(int fd, void * ptr, size_t nbytes, struct cmsgcred * cmsgcredptr)
{
    struct msghdr  msg;
    struct iovec   iov[1];
    char           control[CONTROL_LEN];
    int            n;

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = control;
    msg.msg_controllen = sizeof(control);
    msg.msg_flags = 0;

    if ((n = recvmsg(fd, &msg, 0)) < 0) {
        return(n);
    }

    cmsgcredptr->cmcred_ngroups = 0;  /* indicates no credentials returned */
    if (cmsgcredptr && msg.msg_controllen > 0) {
        struct cmsghdr * cmptr = (struct cmsghdr *)control;

        if (cmptr->cmsg_len < CONTROL_LEN) {
            printf("control length = %d\n", cmptr->cmsg_len);
            exit(1);
        }
        if (cmptr->cmsg_level != SOL_SOCKET) {
            err_exit("control level != SOL_SOCKET");
        }
        if (cmptr->cmsg_type != SCM_CREDS) {
            err_exit("control type != SCM_CREDS");
        }

        memcpy(cmsgcredptr, CMSG_DATA(cmptr), sizeof(struct cmsgcred));
    }

    return(n);
}
#include <sys/socket.h>

#include "err_exit.h"
#include "writen.h"
#include "readcred.h"

ssize_t read_cred(int, void *, size_t, struct cmsgcred *);

#define MAXLINE 4096

void 
str_echo(int sockfd)
{
    ssize_t          n;
    int              i;
    char             buf[MAXLINE];
    struct cmsgcred  cred;

again:
    while ((n = read_cred(sockfd, buf, MAXLINE, &cred)) > 0) {
        if (cred.cmcred_ngroups == 0) {
            printf("(no credentials returned)\n");
        }
        else {
            printf("PID of sender = %d\n", cred.cmcred_pid);
            printf("real user ID = %d\n", cred.cmcred_uid);
            printf("real group ID = %d\n", cred.cmcred_gid);
            printf("effective user ID = %d\n", cred.cmcred_euid);
            printf("%d groups:", cred.cmcred_ngroups - 1);
            for (i = 1; i < cred.cmcred_ngroups; i++) {
                printf(" %d", cred.cmcred_groups[i]);
            }
            printf("\n");
        }
        if (writen(sockfd, buf, n) != n) {
            err_exit("write error");
        }
    }

    if (n < 0 && errno == EINTR) {
        goto again;
    }
    else if (n < 0) {
        err_exit("str_echo: read error");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值