[Haskell-cafe] Using Haskell's FFI to send ancillary data over Unix domain sockets

ihope ihope127 at gmail.com
Fri Mar 5 01:17:12 EST 2010


Unix domain sockets are a type of socket created between two programs
on a single Unix system. They are useful in part because over them you
can send so-called ancillary data: file descriptors and credentials
(i.e. a proof of who the process on the other end is). The thing is,
Haskell doesn't have a nice way of sending ancillary data.

Network.Socket does have these really opaque functions for sending and
receiving ancillary data:

sendAncillary :: Socket -> Int -> Int -> Int -> Ptr a -> Int -> IO ()
sendAncillary sock level ty flags datum len = do ...

recvAncillary :: Socket -> Int -> Int -> IO (Int, Int, Ptr a, Int)
recvAncillary sock flags len = do ... return (lev,ty,pD,len)

Looking in the man page UNIX(7), which describes Unix domain sockets,
some enlightening information is given. It says that ancillary data is
sent and received using sendmsg(2) and recvmsg(2). Those two man pages
say that sock and flags are arguments to sendmsg and recvmsg. UNIX(7)
says that level is always SOL_SOCKET, and ty is either SCM_RIGHTS or
SCM_CREDENTIALS depending on whether the ancillary data is file
descriptors or credentials. In the former case, datum is "an integer
array of the file descriptors"; in the latter case, it's the following
struct:

struct ucred {
    pid_t pid;    /* process ID of the sending process */
    uid_t uid;    /* user ID of the sending process */
    gid_t gid;    /* group ID of the sending process */
};

As for len, this struct seems to be enlightening:

struct cmsghdr {
    socklen_t cmsg_len;    /* data byte count, including header */
    int       cmsg_level;  /* originating protocol */
    int       cmsg_type;   /* protocol-specific type */
    /* followed by unsigned char cmsg_data[]; */
};

So, sock is a Socket, level is the constant SOL_SOCKET, ty is either
SCM_RIGHTS or SCM_CREDENTIALS (strangely, Network.Socket contains the
former but not the latter), flags is the flags passed to sendmsg or
recvmsg (whatever those are--what are they?), datum is either a C
integer array or that struct, and len is the length in bytes of all
that.

For me, this presents a few problems. I don't know where to get the
SCM_CREDENTIALS constant, I have no idea what flags to use (does the
Network module help with that?), I don't know how to get from a list
of file descriptors or a tuple to a Ptr, and perhaps most importantly,
I have no idea how to get the lengths of pid_t, uid_t, gid_t, and
socklen_t.

Can anyone offer assistance?


More information about the Haskell-Cafe mailing list