Posted to tcl by evilotto at Fri Feb 04 01:33:16 GMT 2011view raw
- #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
- */