(or "local sockets" in POSIX-speak)

A type of local socket which has an associated path and inode on the filesystem. This is useful if you want sockets that can only be used with the local machine. You could get a similar result by using Internet domain sockets and connecting to 127.0.0.1, but that would be wasteful and a potential security hazard if you don't bind() properly. UNIX domain sockets are sometimes done with the X Window System, or say, esd and things like that.

Specified with domain family constant PF_UNIX (or PF_LOCAL in POSIX), or address family AF_UNIX (again, AF_LOCAL in POSIX). The address struct, struct sockaddr_un has 2 members: sun_family (set to AF_UNIX/AF_LOCAL) and sun_path (a char array; the filesystem path of the socket)
Here's a little creature of the night that sends a file descriptor between two Unix processes via a Unix domain socket.

I'm the author (i.e. no copyright problems). It has been on my web site for a few years now and is provided here for your entertainment and enlightenment.

Being able to pass a file descriptor between two processes is actually sometimes useful. For example, process A can prove to process B that process A is owned by root by opening a file that only root could open and then passing the file descriptor to process B. Process B then uses the fstat system call to verify that the file associated with the passed file descriptor could only have been opened by root (e.g. owned by root with no rights to group or others. In order to ensure that B doesn't clobber the file, the chosen file should be opened read-only.


/*
 * Send a file descriptor through a Unix domain socket
 *
 * Unfortunately, this program is not exactly 100% portable.
 *
 * One strange wrinkle required by at least some versions of Linux
 * is that you must also send a non-empty message (that's why the code
 * below sends the string "hello" in addition to the file descriptor).
 *
 * This demonstration program opens the file "/etc/motd" in one process,
 * sends the file descriptor to a second process which prints the contents
 * of the file onto stdout.
 *
 * IMPORTANT: this is a DEMONSTRATION program.  If it does something evil
 * to your system or opens a hole in the space-time continuum then I don't
 * want to hear about it!
 *
 * Author:  Daniel Boulet (danny@obtuse.com)
 *
 * Copyright 1997, 1999 Daniel Boulet
 * All rights reserved
 *
 * Permission is granted to use this software in any way you like as long
 * as this entire comment is included in the source code.
 *
 * THIS SOFTWARE IS PROVIDED WITHOUT WARRANTEE OF ANY KIND WHAT-SO-EVER.
 */

/*
 * Portability experience:
 *
 * OS                   Experience
 * --------------------------------------------------------------------
 * BSD/OS               seems to work as-is
 * Linux kernel 2.2     seems to work as-is
 * Linux kernel 2.4     seems to work as-is
 * AIX 4.3              seems to work as-is
 * OpenBSD              seems to work as-is
 * Solaris 2.6          requires a few changes:
 *                       - msg_control renamed as msg_accrights
 *                       - msg_controllen renamed as msg_accrightslen
 *                       - set msg_accrights to point at int containing fd
 *                       - set msg_accrights to sizeof(int)
 *
 * Please let me know your experiences on other Unix variants.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <stdio.h>

main()
{
    int pair[2];
    struct msghdr mh;
    struct cmsghdr cmh[2];
    struct iovec iov;
    char tbuf[100];
    int fd;
    int rlen;
    pid_t pid;
    char buffer[1024];

    if ( socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0 ) {
        perror("socketpair");
        exit(1);
    }

    fflush(stdout);
    fflush(stderr);

    switch ( pid = fork() ) {

    case 0:             /* Child sends the file descriptor */
        fd = open("/etc/motd",0);
        if ( fd < 0 ) {
            perror("open");
            exit(0);
        }
        memset(&mh,0,sizeof(mh));
        mh.msg_name = 0;
        mh.msg_namelen = 0;
        mh.msg_iov = &iov;
        mh.msg_iovlen = 1;
        mh.msg_control = (caddr_t)&cmh[0];
        mh.msg_controllen = sizeof(cmh[0]) + sizeof(int);
        mh.msg_flags = 0;
        iov.iov_base = "hello";
        iov.iov_len = strlen(iov.iov_base) + 1;
        cmh[0].cmsg_level = SOL_SOCKET;
        cmh[0].cmsg_type = SCM_RIGHTS;
        cmh[0].cmsg_len = sizeof(cmh[0]) + sizeof(int);
        *(int *)&cmh[1] = fd;
        if ( sendmsg(pair[1],&mh,0) < 0 ) {
            perror("sendmsg");
            exit(1);
        }
        close(fd);
        printf("child done\n");
        fflush(stdout);
        exit(0);

    case -1:            /* Oops! */
        perror("fork");
        exit(1);

    default:            /* Parent receives the file descriptor */
        mh.msg_name = 0;
        mh.msg_namelen = 0;
        mh.msg_iov = &iov;
        mh.msg_iovlen = 1;
        mh.msg_control = (caddr_t)&cmh[0];
        mh.msg_controllen = sizeof(cmh[0]) * 2;
        iov.iov_base = tbuf;
        iov.iov_len = sizeof(tbuf);
        cmh[0].cmsg_len = sizeof(cmh[0]) + sizeof(int);
        if ( (rlen = recvmsg(pair[0],&mh,0)) < 0 ) {
            perror("recvmsg");
            exit(1);
        }
        fd = *(int *)&cmh[1];
        printf("rlen = %d msg_controllen = %d, cmsg_len = %d\n",
            rlen,mh.msg_controllen,cmh[0].cmsg_len);
        printf("cmsg_level = %d, cmsg_type = %d, fd = %d\n",
            cmh[0].cmsg_level,cmh[0].cmsg_type,fd);
        while ( (rlen = read(fd,buffer,sizeof(buffer))) > 0 ) {
            write(1,buffer,rlen);
        }
        if ( rlen < 0 ) {
            perror("read");
            exit(1);
        }
        exit(0);
    }
}

Log in or register to write something here or to contact authors.