Posted to tcl by evilotto at Fri Feb 04 01:33:16 GMT 2011view pretty
#include "tcl.h" #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h> /* * sender: * xfd_send path $fd * * receiver: * set fdx [xfd_listen path] * set fd [xfd_get $fdx] */ Tcl_ObjCmdProc xfdSendCmd, xfdListenCmd, xfdGetCmd; int xfdSendCmd(ClientData cd, Tcl_Interp *interp, int ac, Tcl_Obj *const av[]) { int sfd,l; char *path=Tcl_GetStringFromObj(av[1],&l); struct sockaddr_un sa; struct msghdr msg; struct cmsghdr *cmsg; int fds[1]; char buf[CMSG_SPACE(sizeof(fds))]; int s=socket(AF_UNIX, SOCK_DGRAM, 0); memset(&sa,0,sizeof(sa)); sa.sun_family=AF_UNIX; strncpy(sa.sun_path,path,l); connect(s,(struct sockaddr *)&sa,sizeof(sa)); Tcl_GetChannelHandle(Tcl_GetChannel(interp,Tcl_GetString(av[2]),NULL),TCL_READABLE,(ClientData *)&sfd); fds[0]=sfd; msg.msg_iov=NULL; msg.msg_iovlen=0; msg.msg_name=NULL; msg.msg_namelen=0; msg.msg_control=buf; msg.msg_controllen=sizeof(buf); cmsg=CMSG_FIRSTHDR(&msg); cmsg->cmsg_level=SOL_SOCKET; cmsg->cmsg_type=SCM_RIGHTS; cmsg->cmsg_len=CMSG_LEN(sizeof(int)); memcpy(CMSG_DATA(cmsg), fds, sizeof(int)); sendmsg(s,&msg,0); return TCL_OK; } int xfdListenCmd(ClientData cd, Tcl_Interp *interp, int ac, Tcl_Obj *const av[]) { int l; char *path=Tcl_GetStringFromObj(av[1],&l); struct sockaddr_un sa; int s=socket(AF_UNIX, SOCK_DGRAM, 0); sa.sun_family=AF_UNIX; strncpy(sa.sun_path,path,l); unlink(path); bind(s,(struct sockaddr *)&sa,sizeof(sa)); /* listen(s,5); */ Tcl_SetObjResult(interp, Tcl_NewIntObj(s)); return TCL_OK; } int xfdGetCmd(ClientData cd, Tcl_Interp *interp, int ac, Tcl_Obj *const av[]) { int rfd; struct msghdr msg; struct cmsghdr *cmsg; int fds[1]; char buf[CMSG_SPACE(sizeof(fds))]; Tcl_Channel new; Tcl_GetIntFromObj(interp,av[1],&rfd); msg.msg_control=buf; msg.msg_controllen=sizeof(buf); recvmsg(rfd,&msg,0); cmsg=CMSG_FIRSTHDR(&msg); memcpy(fds,CMSG_DATA(cmsg), sizeof(int)); fprintf(stderr,"fd %d\n",fds[0]); new=Tcl_MakeFileChannel((ClientData)fds[0],TCL_READABLE|TCL_WRITABLE); Tcl_RegisterChannel(interp,new); Tcl_SetResult(interp,Tcl_GetChannelName(new),TCL_VOLATILE); return TCL_OK; } int Xfd_Init(Tcl_Interp *interp) { Tcl_CreateObjCommand(interp,"xfd_send",xfdSendCmd,NULL,NULL); Tcl_CreateObjCommand(interp,"xfd_listen",xfdListenCmd,NULL,NULL); Tcl_CreateObjCommand(interp,"xfd_get",xfdGetCmd,NULL,NULL); return TCL_OK; } /* # send an open fd to another process load xfd.so set f [open /etc/passwd] xfd_send /tmp/xfr $f close $f */ /* # receive an open fd from another process load xfd.so set fdx [xfd_listen /tmp/xfr] set f [xfd_get $fdx] puts [read $f] close $f */