Passing file descriptors in Python?
Tres Seaver
tseaver at starbase.neosoft.com
Wed Oct 6 22:27:49 EDT 1999
In article <37F85D6E.D50D1771 at compaq.com>,
Greg Ewing <greg.ewing at compaq.com> wrote:
>Guido van Rossum wrote:
>>
>> I would guess that creating a
>> server AF_UNIX socket in the parent and a client AF_UNIX socket in the
>> child, connecting the latter to the former, would allow you to do the
>> same thing.
>
>Try using an ordinary pipe first. On BSD-flavoured unices, pipes
>are often implemented as a pair of unix-domain sockets.
>
>You'll definitely need sendmsg() and recvmsg(), though, so
>you'll still have to write some C.
>
>Greg
Pipes would be less portable (SysV IPC uses another mechanism). Here is a
rendition of the actual read/write FD code which works on my Linux boxes,
and should work on *BSD as well:
------------------------- cut here -----------------------------------------
include <sys/socket.h>
#include <iovec.h>
typedef struct msghdr MsgHdr;
typedef struct cmsghdr CMsgHdr;
typedef struct iovec IOVec;
typedef union /* force alignment of trailing data */
{
CMsgHdr cm;
char control[ CMSG_SPACE( sizeof( int ) ) ];
} CMsgHdrUnion;
/*
* Pass a descriptor across a Unix domain stream socket. Return number of
* bytes of main payload passed (caller should pass at least one byte, to
* allow peer to detect EOF cleanly).
*
* See W. R. Stevens, Unix Network Programming (2nd ed), vol 1, p. 389.
*
* In "pre-forked child" use case, sockFD may be one end of a socketpair();
* for unrelated servers, should be created by bind()/connect().
*/
ssize_t
write_fd( int sockFD /* AF_UNIX stream socket */
, void* payload /* Payload buffer */
, size_t nPL /* Size of payload */
, int sendFD /* Descriptor to be passed */
)
{
MsgHdr msg; /* sendmsg() buffer */
IOVec iov[1]; /* scatter-gather payload vector */
CMsgHdrUnion controlX;
CMsgHdr* cmptr;
msg.msg_name = NULL; /* name not used for stream sockets. */
msg.msg_namelen = 0;
iov[0].iov_base = payload; /* set up scatter-gather. */
iov[0].iov_len = nPL;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
/*
* XXX: Older Unixen may use msg_accrights instead of msg_control.
*/
msg.msg_control = controlX.control;
msg.msg_controllen = sizeof( controlX.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;
return( sendmsg( sockFD, &msg, 0 ) );
}
/*
* Receive a descriptor across a Unix domain stream socket. Return number of
* bytes of main payload passed (should be least one byte, to distinguish
* EOF).
*
* See W. R. Stevens, Unix Network Programming (2nd ed), vol 1, p. 387.
*
* In "pre-forked child" use case, sockFD may be one end of a socketpair();
* for unrelated servers, should be created by bind()/connect().
*/
ssize_t
read_fd( int sockFD /* AF_UNIX socket over which to pass descriptor */
, void* payload /* Payload buffer */
, size_t maxPL /* Size of payload buffer */
, int* recvFD /* Address of descriptor being received */
)
{
MsgHdr msg; /* recvmsg() message buffer */
IOVec iov[1]; /* Scatter-gather payload vector */
ssize_t nPL; /* Size of actual payload received */
CMsgHdrUnion controlX;
CMsgHdr* cmptr;
msg.msg_name = NULL; /* name not used for stream sockets */
msg.msg_namelen = 0;
iov[0].iov_base = payload; /* set up scatter-gather */
iov[0].iov_len = maxPL;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
/*
* XXX: Older Unixen may use msg_accrights instead of msg_control.
*/
msg.msg_control = controlX.control;
msg.msg_controllen = sizeof( controlX.control );
/*
* XXX: Stevens does'nt pre-initialize cm, but RH 5.2 acts flaky
* without it.
*/
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 ) ) = -1;
nPL = recvmsg( sockFD, &msg, 0 );
if ( nPL <= 0 )
return( nPL );
/*
* XXX: Might realloc, so reseat?
*/
cmptr = CMSG_FIRSTHDR( &msg );
if ( cmptr != NULL
&& cmptr->cmsg_len == CMSG_LEN( sizeof( int ) )
&& cmptr->cmsg_level == SOL_SOCKET
&& cmptr->cmsg_type == SCM_RIGHTS
)
*recvFD = *( (int*) CMSG_DATA( cmptr ) );
else
*recvFD = -1; /* descriptor was not passed */
return( nPL );
}
--
---------------------------------------------------------------
Tres Seaver tseaver at palladion.com 713-523-6582
Palladion Software http://www.palladion.com
More information about the Python-list
mailing list