Posted to tcl by evilotto at Fri Feb 04 01:33:16 GMT 2011view raw

  1. #include "tcl.h"
  2. #include <sys/socket.h>
  3. #include <sys/types.h>
  4. #include <sys/un.h>
  5.  
  6. /*
  7. * sender:
  8. * xfd_send path $fd
  9. *
  10. * receiver:
  11. * set fdx [xfd_listen path]
  12. * set fd [xfd_get $fdx]
  13. */
  14.  
  15. Tcl_ObjCmdProc xfdSendCmd, xfdListenCmd, xfdGetCmd;
  16.  
  17. int xfdSendCmd(ClientData cd, Tcl_Interp *interp, int ac, Tcl_Obj *const av[]) {
  18. int sfd,l;
  19. char *path=Tcl_GetStringFromObj(av[1],&l);
  20. struct sockaddr_un sa;
  21. struct msghdr msg;
  22. struct cmsghdr *cmsg;
  23. int fds[1];
  24. char buf[CMSG_SPACE(sizeof(fds))];
  25.  
  26. int s=socket(AF_UNIX, SOCK_DGRAM, 0);
  27. memset(&sa,0,sizeof(sa));
  28. sa.sun_family=AF_UNIX;
  29. strncpy(sa.sun_path,path,l);
  30. connect(s,(struct sockaddr *)&sa,sizeof(sa));
  31.  
  32. Tcl_GetChannelHandle(Tcl_GetChannel(interp,Tcl_GetString(av[2]),NULL),TCL_READABLE,(ClientData *)&sfd);
  33. fds[0]=sfd;
  34.  
  35. msg.msg_iov=NULL;
  36. msg.msg_iovlen=0;
  37. msg.msg_name=NULL;
  38. msg.msg_namelen=0;
  39.  
  40. msg.msg_control=buf;
  41. msg.msg_controllen=sizeof(buf);
  42. cmsg=CMSG_FIRSTHDR(&msg);
  43. cmsg->cmsg_level=SOL_SOCKET;
  44. cmsg->cmsg_type=SCM_RIGHTS;
  45. cmsg->cmsg_len=CMSG_LEN(sizeof(int));
  46. memcpy(CMSG_DATA(cmsg), fds, sizeof(int));
  47. sendmsg(s,&msg,0);
  48. return TCL_OK;
  49. }
  50.  
  51. int xfdListenCmd(ClientData cd, Tcl_Interp *interp, int ac, Tcl_Obj *const av[]) {
  52. int l;
  53. char *path=Tcl_GetStringFromObj(av[1],&l);
  54. struct sockaddr_un sa;
  55.  
  56. int s=socket(AF_UNIX, SOCK_DGRAM, 0);
  57. sa.sun_family=AF_UNIX;
  58. strncpy(sa.sun_path,path,l);
  59. unlink(path);
  60. bind(s,(struct sockaddr *)&sa,sizeof(sa));
  61. /* listen(s,5); */
  62. Tcl_SetObjResult(interp, Tcl_NewIntObj(s));
  63. return TCL_OK;
  64. }
  65.  
  66. int xfdGetCmd(ClientData cd, Tcl_Interp *interp, int ac, Tcl_Obj *const av[]) {
  67. int rfd;
  68. struct msghdr msg;
  69. struct cmsghdr *cmsg;
  70. int fds[1];
  71. char buf[CMSG_SPACE(sizeof(fds))];
  72. Tcl_Channel new;
  73.  
  74. Tcl_GetIntFromObj(interp,av[1],&rfd);
  75.  
  76. msg.msg_control=buf;
  77. msg.msg_controllen=sizeof(buf);
  78. recvmsg(rfd,&msg,0);
  79.  
  80. cmsg=CMSG_FIRSTHDR(&msg);
  81. memcpy(fds,CMSG_DATA(cmsg), sizeof(int));
  82. fprintf(stderr,"fd %d\n",fds[0]);
  83. new=Tcl_MakeFileChannel((ClientData)fds[0],TCL_READABLE|TCL_WRITABLE);
  84. Tcl_RegisterChannel(interp,new);
  85. Tcl_SetResult(interp,Tcl_GetChannelName(new),TCL_VOLATILE);
  86. return TCL_OK;
  87. }
  88.  
  89. int Xfd_Init(Tcl_Interp *interp) {
  90. Tcl_CreateObjCommand(interp,"xfd_send",xfdSendCmd,NULL,NULL);
  91. Tcl_CreateObjCommand(interp,"xfd_listen",xfdListenCmd,NULL,NULL);
  92. Tcl_CreateObjCommand(interp,"xfd_get",xfdGetCmd,NULL,NULL);
  93. return TCL_OK;
  94. }
  95.  
  96.  
  97. /*
  98. # send an open fd to another process
  99.  
  100. load xfd.so
  101. set f [open /etc/passwd]
  102.  
  103. xfd_send /tmp/xfr $f
  104.  
  105. close $f
  106.  
  107. */
  108.  
  109.  
  110. /*
  111. # receive an open fd from another process
  112.  
  113. load xfd.so
  114. set fdx [xfd_listen /tmp/xfr]
  115. set f [xfd_get $fdx]
  116.  
  117. puts [read $f]
  118.  
  119. close $f
  120.  
  121. */
  122.