Using Haskell's FFI to send ancillary data over Unix domain sockets

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Using Haskell's FFI to send ancillary data over Unix domain sockets

ihope
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?
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Using Haskell's FFI to send ancillary data over Unix domain sockets

Maurí­cio CA
 > 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.

The basic answer is that you can use tools like hsc2hs, c2hs or
greencard.

I also wrote this package that may be of help:

   http://hackage.haskell.org/package/bindings-posix

You may want to look at the source code to see how to apply the
idea to your needs. Note that this package uses a lot of macros
I wrote myself (see package bindings-DSL), so you should not use
them if you want to stick with standard tools.

Best,

Maurício

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe