Unix-domain socket

Unix-domain socket code is akin to its network counterpart, and they share one readwrite() function. So I only list the caveats during creating Unix-domain socket connection:

(1) Like network socket, Unix-domain socket also supports connection & connection-less services; instead of using IP address + port, Unix-domain should bind to a filesystem pathname. Check unix_bind function:

/*
 * unix_bind()
 * Returns a unix socket bound to the given path
 */
int
unix_bind(char *path, int flags)
{
    struct sockaddr_un s_un;
    int s, save_errno;

    /* Create unix domain socket. */
    if ((s = socket(AF_UNIX, flags | (uflag ? SOCK_DGRAM : SOCK_STREAM),
        0)) < 0)
        return -1;

    memset(&s_un, 0, sizeof(struct sockaddr_un));
    s_un.sun_family = AF_UNIX;

    if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
        sizeof(s_un.sun_path)) {
        close(s);
        errno = ENAMETOOLONG;
        return -1;
    }

    if (bind(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
        save_errno = errno;
        close(s);
        errno = save_errno;
        return -1;
    }

    return s;
}

(2) The biggest surprise is connection-less Unix-domain client also needs to be bound to a pathname:

......
/* Get name of temporary socket for unix datagram client */
if ((family == AF_UNIX) && uflag && !lflag) {
    if (sflag) {
        unix_dg_tmp_socket = sflag;
    } else {
        strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
            UNIX_DG_TMP_SOCKET_SIZE);
        if (mktemp(unix_dg_tmp_socket_buf) == NULL)
            err(1, "mktemp");
        unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
    }
}
......

sflag will be set with -s source option:

......
char   *sflag;                    /* Source Address */
......

So if user doesn't specify a pathname for client, the client will create a temporary socket.

Therefore, the connection-less client also needs to call unix_bind() before connecting server:

/*
 * unix_connect()
 * Returns a socket connected to a local unix socket. Returns -1 on failure.
 */
int
unix_connect(char *path)
{
    struct sockaddr_un s_un;
    int s, save_errno;

    if (uflag) {
        if ((s = unix_bind(unix_dg_tmp_socket, SOCK_CLOEXEC)) < 0)
            return -1;
    } else {
        if ((s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
            return -1;
    }

    ......
    if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
        ......
    }
    return s;

}

For the connection-less server part, there is also one more step needed:

......
if (family == AF_UNIX && uflag) {
    if (connect(s, NULL, 0) < 0)
        err(1, "connect");
}
......

results matching ""

    No results matching ""