This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

File Descriptor passing fun


Hi,
	I wanted to submit my code to pass file descriptors in cygwin.

typedef u_int	SOCKET;
#include<windows.h>
#include<io.h>
#include <sys/cygwin.h>
#define DEADBEEF 3735928559
//extern void sfs_warn (const char *fmt, ...) __attribute__ ((format
(printf, 1, 2)));
const char *windows_device_names[] =
{
  NULL,
  "\\dev\\console",
  "conin",
  "conout",
  "\\dev\\ttym",
  "\\dev\\tty%d",
  "\\dev\\ptym",
  "\\\\.\\com%d",
  "\\dev\\pipe",
  "\\dev\\piper",
  "\\dev\\pipew",
  "/dev/udp",
  "\\dev\\windows",
  NULL, NULL, NULL,
  "\\dev\\disk",
  "\\dev\\fd%d",
  "\\dev\\st%d",
  "nul",
  "\\dev\\zero",
  "\\dev\\%srandom",
  "\\dev\\mem",
  "\\dev\\clipboard",
  "\\dev\\dsp"
};
struct passfd {
  unsigned int uiMagic;
  DWORD dwProcessID;
  HANDLE hHandle;
  BOOL bBinary;
  BOOL bRead;
  BOOL bWrite;
  DWORD dwDevice;
};
int getmode (int fd);
int
parse_fdp(struct passfd *fdp)
{
  BOOL bOk;
  int fd;
  int gread, gwrite;
  HANDLE hOther, hThis = NULL;
  HANDLE h = NULL;
  //sfs_warn("Received  ProcId %d, Handle 0x%x,
Device:%d\n",fdp->dwProcessID, fdp->hHandle, fdp->dwDevice);
  hOther = OpenProcess(PROCESS_DUP_HANDLE, FALSE, fdp->dwProcessID);
  hThis = OpenProcess(PROCESS_DUP_HANDLE, FALSE, GetCurrentProcessId());
  bOk = DuplicateHandle(hOther, fdp->hHandle, hThis,
			  &h, 0, TRUE, DUPLICATE_SAME_ACCESS);
  if (!bOk) {
	  //sfs_warn("Error in Duplicate Handle");
    return -1;
  }
  CloseHandle(hOther);
  CloseHandle(hThis);
  //sfs_warn("It is a %s type handle",(char*)
windows_device_names[fdp->dwDevice]);
  gread = (fdp->bRead ? GENERIC_READ : 0);
  gwrite = (fdp->bWrite ? GENERIC_WRITE : 0);
  fd = cygwin32_attach_handle_to_fd((char*)
windows_device_names[fdp->dwDevice], -1, h,
		fdp->bBinary, gread | gwrite);
  //sfs_warn("attach handle %d\n", fd);
  return fd;
}

ssize_t
writevfd (int fd, const struct iovec *iov, int iovcnt, int wfd)
{
  struct passfd fdp[1];
  struct stat sbuf;
  int tot = 0;
  int i, ret;
  char *buf,*p;
  struct sockaddr sa;
  int sal = sizeof (sa);
  //sfs_warn("Sending fd\n");
  fstat(wfd, &sbuf);
  fdp->uiMagic = DEADBEEF;
  fdp->dwProcessID = GetCurrentProcessId();
  fdp->hHandle = (HANDLE) get_osfhandle(wfd);
  fdp->bBinary = getmode(wfd);
  fdp->bRead = sbuf.st_mode & S_IRUSR;
  fdp->bWrite = sbuf.st_mode & S_IWUSR;
  fdp->dwDevice = sbuf.st_dev>>8;
  if ((fdp->dwDevice == 0) && getpeername (fd, &sa, &sal) == 0)
	  fdp->dwDevice = 11;  // CYGWIN magic number.
  //sfs_warn("Sending fd: %d, ProcId %d, Handle 0x%x, Device:%d\n",wfd,
fdp->dwProcessID, fdp->hHandle, fdp->dwDevice);
  for(i = 0; i < iovcnt; ++i)
    tot += iov[i].iov_len;
  buf = (char *) malloc(tot+sizeof(struct passfd));
  if (tot != 0 && buf == NULL) {
    errno = ENOMEM;
    return -1;
  }
  p = buf;
  memcpy(p, fdp, sizeof(struct passfd));
  p+= sizeof(struct passfd);
  for (i = 0; i < iovcnt; ++i) {
    memcpy (p, iov[i].iov_base, iov[i].iov_len);
    p += iov[i].iov_len;
  }
  ret = send (fd, buf, tot+sizeof(struct passfd), 0);
  free (buf);
  if (ret >= sizeof(struct passfd))
    return ret-sizeof(struct passfd);
  else
    return ret;
}

ssize_t
readvfd (int fd, const struct iovec *iov, int iovcnt, int *rfdp)
{
  int i;
  struct passfd fdp[1];
  int ret, nb;
  size_t tot = 0;
  char *buf, *p;

  //sfs_warn("Read fd\n");
  for(i = 0; i < iovcnt; ++i)
    tot += iov[i].iov_len;
  buf = (char *) malloc(tot+sizeof(struct passfd));
  if (tot != 0 && buf == NULL) {
    errno = ENOMEM;
    return -1;
  }
  nb = ret = recv (fd, buf, tot+sizeof(struct passfd), 0);
  p = buf;
  if (nb >= sizeof(struct passfd)) {
    memcpy(fdp, buf, sizeof(struct passfd));
    if (fdp->uiMagic == DEADBEEF) {
		//sfs_warn("Actually an fd!\n");
      p += sizeof(struct passfd);
      nb -= sizeof(struct passfd);
      *rfdp = parse_fdp(fdp);
      ret = nb;
    }
  }
  while (nb > 0) {
    ssize_t cnt = min(nb, iov->iov_len);

    memcpy (iov->iov_base, p, cnt);
    p += cnt;
    nb -= cnt;
    ++iov;
  }
  free(buf);

  if (*rfdp >= 0 && ret == 0) {
    ret = -1;
    errno = EAGAIN;
  }
  return ret;
}


Unfortunately it suffers from lineup issues.  If you try to send data,
then a file descriptor, then more data, the reader will get lost and not
find any file descriptor and return data that you never really sent.  If
anybody has any other ideas about how to do this, let me know.

Once it's fixed I'm sure this code will be useful in cygwin.

David


--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]