Patch to pass file descriptors

David E Euresti davie@MIT.EDU
Thu Jun 27 00:33:00 GMT 2002


Hello,
	I finally am able to send in the patch to pass file descriptors.
There's still some work to be done like adding security and such, but
otherwise it works.
There are two new files cygserver_handle.cc and cygserver_handle.h  these
go into src/winsup/cygwin

The testfd.c is a test file.  Compile and run to see a process fork and
pass a file descriptor.  It also shows how to use sendmsg to pass a
descriptor.

Feel free to comment.

Thanks,
David
-------------- next part --------------
2002-06-18  David Euresti <davie@alum.mit.edu>



	* Makefile.in: add cygserver_handle.o to cygserver.exe. Fix formatting.

	* cygserver.cc: Include cygserver_handle.h

	(server_request::process) Use the new client_request_hold_handle

	and client_request_release_handle constructors.

	* cygserver_client.cc: Include cygserver_handle.h

	(client_request_hold_handle): New constructor.

	(client_request_release_handle): New constructor.

	* net.cc: Include cygserver_handle.h

	(struct passfd): New struct.

	(cygwin_handle_to_fd): New function.

	(cygwin_recv_msg): Decide whether file descriptor is being received.

	Call cygwin_recv if no msg_name is passed, instead of cygwin_recvfrom.

	If file descriptor is being received, call cygserver_release_handle and cygwin_handle_to_fd.

	Fix formatting.

	(cygwin_sendmsg): Decide whether file descriptor needs to be sent.

	If file descriptor will be passed, call cygserver_hold_handle.

	Call cygwin_send if no msg_name is passed, instead of cygwin_sendto.  Fix formatting

	* include/cygwin/cygserver.h (client_request_hold_handle): New class.

	(client_request_release_handle): New class.

	* cygserver_handle.cc: New file.

	* cygserver_handle.h: New file.

-------------- next part --------------
/* cygserver_handle.h



   Copyright 2001, 2002 Red Hat Inc.

   Written by David Euresti <davie@alum.mit.edu>



This file is part of Cygwin.



This software is a copyrighted work licensed under the terms of the

Cygwin license.  Please consult the file "CYGWIN_LICENSE" for

details. */



#include <sys/types.h>

#include "cygwin/cygserver_transport.h"

#include "cygwin/cygserver.h"



class client_request_hold_handle: public client_request

{

 public:

#ifndef __INSIDE_CYGWIN__

  virtual void serve (transport_layer_base *conn, class process_cache *cache);

#endif

  client_request_hold_handle();

  client_request_hold_handle(DWORD pid, HANDLE from_handle);

  struct request_hold_handle req;

  HANDLE cygserver_handle() {return req.cygserver_handle;}

};



class client_request_release_handle: public client_request

{

 public:

#ifndef __INSIDE_CYGWIN__

  virtual void serve (transport_layer_base *conn, class process_cache *cache);

#endif

  client_request_release_handle();

  client_request_release_handle(DWORD pid, HANDLE cygwin_handle);

  struct request_release_handle req;

  HANDLE to_handle() {return req.to_handle;}

};



-------------- next part --------------
/* cygserver_handle.cc: Handle passing interface for Cygwin



Copyright 2001, 2002 Red Hat, Inc.



Originally written by David Euresti <davie@alum.mit.edu>



This file is part of Cygwin.



This software is a copyrighted work licensed under the terms of the

Cygwin license.  Please consult the file "CYGWIN_LICENSE" for

details. */



#ifdef __OUTSIDE_CYGWIN__

#undef __INSIDE_CYGWIN__

#else

#include "winsup.h"

#endif



#ifndef __INSIDE_CYGWIN__

#define DEBUG 1

#define system_printf printf

#define debug_printf if (DEBUG) printf

#define api_fatal printf

#include <stdio.h>

#include <windows.h>

#endif

#include <errno.h>

#include <cygserver_handle.h>







client_request_hold_handle::client_request_hold_handle() : client_request(CYGSERVER_REQUEST_HOLD_HANDLE, sizeof(req))

{

  buffer = (char*)&req;

  req.pid = 0;

  req.from_handle = NULL;

  req.cygserver_handle = NULL;

}

client_request_release_handle::client_request_release_handle() : client_request(CYGSERVER_REQUEST_RELEASE_HANDLE, sizeof(req))

{

  buffer = (char*)&req;

  req.pid = 0;

  req.to_handle = NULL;

  req.cygserver_handle = NULL;

}



void

client_request_release_handle::serve(transport_layer_base *conn, class process_cache *cache)

{

  HANDLE to_process_handle = NULL;

  

  if (header.cb != sizeof (req))

    {

      header.error_code = EINVAL;

      return; 

    }



  debug_printf ("Release Handle CALL pid %ld Handle:(%p)\n", req.pid, req.cygserver_handle);



  to_process_handle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);



  if (!to_process_handle)

    {

      printf ("error opening process (%lu)\n", GetLastError ());

      header.error_code = EACCES;

      goto out;

    }



  //  debug_printf("DuplicateHandle handle:0x%X -> proc2:0x%X\n", req.cygserver_handle, to_process_handle);

  if (!DuplicateHandle (GetCurrentProcess(), req.cygserver_handle,

			to_process_handle, &req.to_handle,

			0, TRUE,

			DUPLICATE_SAME_ACCESS))

    {

      printf ("error duplicating from_master handle (%lu)\n", GetLastError ());

      header.error_code = EACCES;

      goto out;

    }

  CloseHandle(req.cygserver_handle);



  header.error_code = 0;



out:

  if (to_process_handle)

    CloseHandle (to_process_handle);

  debug_printf ("Hold Handle RETURN: ret:%d ret_handle(%p)\n", header.error_code, req.to_handle);



}



void

client_request_hold_handle::serve(transport_layer_base *conn, class process_cache *cache)

{

  HANDLE from_process_handle = NULL;

  

  if (header.cb != sizeof (req))

    {

      header.error_code = EINVAL;

      return;

    }



  debug_printf ("Hold Handle CALL: pid %ld Handle:(%p)\n", req.pid, req.from_handle);

  from_process_handle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);



  

  if (!from_process_handle)

    {

      printf ("error opening process (%lu)\n", GetLastError ());

      header.error_code = EACCES;

      goto out;

    }

  

  // debug_printf("DuplicateHandle proc1: 0x%X handle1:0x%X -> CurrentProcess\n", from_process_handle, req.from_handle);

  if (!DuplicateHandle (from_process_handle, req.from_handle,

			GetCurrentProcess(), &req.cygserver_handle,

			0, TRUE,

			DUPLICATE_SAME_ACCESS))

    {

      printf ("error duplicating from_master handle (%lu)\n", GetLastError ());

      header.error_code = EACCES;

      goto out;

    }



  header.error_code = 0;



out:

  if (from_process_handle)

    CloseHandle (from_process_handle);

  debug_printf ("Hold Handle RETURN: ret:%d ret_handle(%p)\n", header.error_code, req.cygserver_handle);



}





-------------- next part --------------
? cygwin/cygserver_handle.cc
? cygwin/cygserver_handle.h
Index: cygwin/Makefile.in
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v
retrieving revision 1.94
diff -u -p -r1.94 Makefile.in
--- cygwin/Makefile.in	22 Jun 2002 02:56:56 -0000	1.94
+++ cygwin/Makefile.in	26 Jun 2002 18:28:12 -0000
@@ -203,7 +203,7 @@ install-man:
 
 install_target: cygserver.exe
 	$(INSTALL_PROGRAM) cygserver.exe $(bindir)/cygserver.exe
-	
+
 install_host:
 
 
@@ -322,7 +322,10 @@ cygserver_client_outside.o: cygserver_cl
 cygserver_shm.o: cygserver_shm.cc
 	$(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $<
 
-cygserver.exe: cygserver.o cygserver_shm.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o
+cygserver_handle.o: cygserver_handle.cc
+	$(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $<
+
+cygserver.exe: cygserver.o cygserver_shm.o cygserver_handle.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o
 	$(CXX) -o $@ $^
 #ifdef VERBOSE
 #	$(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS)
Index: cygwin/cygserver.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygserver.cc,v
retrieving revision 1.4
diff -u -p -r1.4 cygserver.cc
--- cygwin/cygserver.cc	15 Mar 2002 21:52:05 -0000	1.4
+++ cygwin/cygserver.cc	26 Jun 2002 18:28:12 -0000
@@ -31,6 +31,7 @@
 #include "cygwin/cygserver_process.h"
 #include "cygwin/cygserver.h"
 #include "cygserver_shm.h"
+#include "cygserver_handle.h"
 
 /* for quieter operation, set to 0 */
 #define DEBUG 0
@@ -364,6 +365,10 @@ server_request::process ()
       req = new client_request_attach_tty (); break;
     case CYGSERVER_REQUEST_SHUTDOWN:
       req = new client_request_shutdown (); break;
+    case CYGSERVER_REQUEST_HOLD_HANDLE:
+      req = new client_request_hold_handle(); break;
+    case CYGSERVER_REQUEST_RELEASE_HANDLE:
+      req = new client_request_release_handle(); break;
     case CYGSERVER_REQUEST_SHM_GET:
      req = new client_request_shm (); break;
     default:
Index: cygwin/cygserver_client.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygserver_client.cc,v
retrieving revision 1.3
diff -u -p -r1.3 cygserver_client.cc
--- cygwin/cygserver_client.cc	13 Mar 2002 02:34:03 -0000	1.3
+++ cygwin/cygserver_client.cc	26 Jun 2002 18:28:12 -0000
@@ -30,6 +30,7 @@
 #include "cygwin/cygserver_transport_pipes.h"
 #include "cygwin/cygserver_transport_sockets.h"
 #include "cygwin/cygserver.h"
+#include "cygserver_handle.h"
 
 /* 0 = untested, 1 = running, 2 = dead */
 int cygserver_running=CYGSERVER_UNKNOWN;
@@ -58,6 +59,23 @@ client_request_attach_tty::client_reques
   req.from_master = nfrom_master;
   req.to_master = nto_master;
 }
+
+client_request_hold_handle::client_request_hold_handle(DWORD pid, HANDLE from) : client_request(CYGSERVER_REQUEST_HOLD_HANDLE, sizeof(req))
+{
+  buffer = (char*)&req;
+  req.pid = pid;
+  req.from_handle = from;
+  req.cygserver_handle = NULL;
+}
+
+client_request_release_handle::client_request_release_handle(DWORD pid, HANDLE cyghandle) : client_request(CYGSERVER_REQUEST_RELEASE_HANDLE, sizeof(req))
+{
+  buffer = (char*)&req;
+  req.pid = pid;
+  req.cygserver_handle = cyghandle;
+  req.to_handle = NULL;
+}
+
 
 client_request_shutdown::client_request_shutdown () : client_request (CYGSERVER_REQUEST_SHUTDOWN, 0)
 {
Index: cygwin/net.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/net.cc,v
retrieving revision 1.113
diff -u -p -r1.113 net.cc
--- cygwin/net.cc	10 Jun 2002 19:58:19 -0000	1.113
+++ cygwin/net.cc	26 Jun 2002 18:28:13 -0000
@@ -34,6 +34,7 @@ details. */
 #include "registry.h"
 #include "wsock_event.h"
 #include <sys/uio.h>
+#include "cygserver_handle.h"
 
 extern "C" {
 int h_errno;
@@ -2474,66 +2475,266 @@ endhostent (void)
 {
 }
 
+struct passfd {
+  unsigned int uiMagic;  // Magic number to recognize header data
+  HANDLE hHandle;        // Handle value valid in cygserver
+  BOOL bBinary;          // Binary or Text mode
+  BOOL bRead;            // Read access?
+  BOOL bWrite;           // Write access?
+  int iDevice;           // Device Type 
+  int iAF;               // If iDevice is FH_SOCKET Address Family of Socket
+};
+
+
+// Currently only FH_PIPER, FH_PIPEW, and FH_SOCKET are supported
+// Because of this bRead and bWrite are ignored.
+// Socket name on AF_LOCAL will be set to "".
+// Returns the fd or -1 if there's an error
+static int
+cygwin_handle_to_fd (HANDLE handle, struct passfd *fdp) 
+{
+  DWORD myaccess = (fdp->bRead ? GENERIC_READ : 0) | (fdp->bWrite ? GENERIC_WRITE : 0);
+  int devn = fdp->iDevice & FH_DEVMASK; 
+
+  int fd = -1;
+  switch (devn) {
+  case FH_PIPER: 
+    {
+      fd = cygheap->fdtab.find_unused_handle ();
+      fhandler_pipe *fhr = (fhandler_pipe *) 
+	cygheap->fdtab.build_fhandler (fd,FH_PIPER, "/dev/piper");
+      fhr->init (handle, GENERIC_READ, fdp->bBinary);
+    }
+    break;
+  case FH_PIPEW: 
+    {
+      fd = cygheap->fdtab.find_unused_handle ();
+      fhandler_pipe *fhw = (fhandler_pipe *) 
+	cygheap->fdtab.build_fhandler (fd, FH_PIPEW, "/dev/pipew");
+      fhw->init (handle, GENERIC_WRITE, fdp->bBinary);
+    }
+    break;
+  case FH_SOCKET:
+    {
+      fd = cygheap->fdtab.find_unused_handle ();
+      const char *name;
+      int type;
+      
+      WSAPROTOCOL_INFO ProtInfo;
+      int size = sizeof(ProtInfo);
+      getsockopt((SOCKET)handle, SOL_SOCKET, 
+		 SO_PROTOCOL_INFO, (char*)&ProtInfo, &size);
+
+      if (ProtInfo.iProtocol == IPPROTO_TCP) 
+	type = SOCK_STREAM;
+      else // XXX are there any others Protocols?
+	type = SOCK_DGRAM;
+
+      if (fdp->iAF == AF_INET)
+	name = (type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp");
+      else
+	name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket");
+      
+      fhandler_socket* fh = (fhandler_socket *) 
+	cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name);
+      if (fh)
+	{
+	  fh->set_io_handle (handle);
+	  fh->set_flags (O_RDWR, O_BINARY);
+	  fh->set_addr_family (fdp->iAF);
+	  fh->set_socket_type (type);
+	}
+    }
+    break;
+  }  
+  return fd;
+}
+
+
 /* exported as recvmsg: standards? */
 extern "C" int
 cygwin_recvmsg(int s, struct msghdr *msg, int flags)
 {
-    int ret, nb;
-    size_t tot = 0;
-    int i;
-    char *buf, *p;
-    struct iovec *iov = msg->msg_iov;
-
-    for(i = 0; i < msg->msg_iovlen; ++i)
-	tot += iov[i].iov_len;
-    buf = (char *) malloc(tot);
-    if (tot != 0 && buf == NULL)
+  int ret, nb;
+  size_t tot = 0;
+  int i;
+  char *buf, *p;
+  struct iovec *iov = msg->msg_iov;
+  struct passfd fdp[1];
+  int extradata = 0;
+  
+  for(i = 0; i < msg->msg_iovlen; ++i)
+    tot += iov[i].iov_len;
+
+  if (msg->msg_accrightslen) 
+      (*(int *)msg->msg_accrights) = -1;
+
+  fhandler_socket *sock = get (s);
+
+  if (sock && sock->get_addr_family () == AF_LOCAL) {
+    // We only worry about message headers under AF_LOCAL
+    // I know that using MSG_PEEK is considered incorrect sometimes,
+    // but not in this case because we're not trying to buffer data.
+
+    // XXX - We need to add this check to the other recv calls so that 
+    // they can strip off this extra data, i.e. somebody sends a descriptor, 
+    // the other calls recv instead of recv_msg
+
+    if (cygwin_recv(s, (char*) fdp, sizeof(fdp), MSG_PEEK) == sizeof (fdp) && 
+	fdp->uiMagic == 0xAABBCCDD) {
+      extradata = sizeof(fdp);
+      
+    }
+  }
+
+  buf = (char *) malloc(tot + extradata);
+  if (tot != 0 && buf == NULL)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  if (msg->msg_name) 
+    nb = ret = cygwin_recvfrom (s, buf, tot + extradata, flags,
+				(struct sockaddr *) msg->msg_name, 
+				(int *) &msg->msg_namelen);
+  else
+    nb = ret = cygwin_recv (s, buf, tot + extradata, flags);
+
+  nb = nb - extradata;
+
+  if (extradata) {
+    debug_printf("Handle in cygserver: 0x%X\n", fdp->hHandle);
+    client_request_release_handle *request = 
+      new client_request_release_handle((DWORD) GetCurrentProcessId(),
+				     (HANDLE) fdp->hHandle);
+    if (cygserver_request (request) == 0 &&
+	request->header.error_code == 0) 
       {
-	errno = ENOMEM;
-	return -1;
+	// We now have a handle that we want to turn into an fd.
+	debug_printf("Local Handle: 0x%X\n", request->to_handle());
+	if (msg->msg_accrightslen) 
+	  {
+	    (*(int *)msg->msg_accrights) = cygwin_handle_to_fd(request->to_handle(), fdp);
+	    debug_printf("New fd: %d", (*(int *)msg->msg_accrights));
+	  }
+	else
+	  { 
+	    // If the user didn't leave room for an fd just close the handle, we don't want extra handles floating around.
+	    CloseHandle(request->to_handle());
+	  }
       }
-    nb = ret = cygwin_recvfrom (s, buf, tot, flags,
-      (struct sockaddr *) msg->msg_name, (int *) &msg->msg_namelen);
-    p = buf;
-    while (nb > 0)
-      {
-	ssize_t cnt = min(nb, iov->iov_len);
+    delete request;
+  }
 
-	memcpy (iov->iov_base, p, cnt);
-	p += cnt;
-	nb -= cnt;
-	++iov;
-      }
-    free(buf);
-    return ret;
+  p = buf + extradata;
+  while (nb > 0)
+    {
+      ssize_t cnt = min(nb, iov->iov_len);
+      
+      memcpy (iov->iov_base, p, cnt);
+      p += cnt;
+      nb -= cnt;
+      ++iov;
+    }
+  free(buf);
+  return ret-extradata;
 }
 
 /* exported as sendmsg: standards? */
 extern "C" int
 cygwin_sendmsg(int s, const struct msghdr *msg, int flags)
 {
-    int ret;
-    size_t tot = 0;
-    int i;
-    char *buf, *p;
-    struct iovec *iov = msg->msg_iov;
-
-    for(i = 0; i < msg->msg_iovlen; ++i)
-	tot += iov[i].iov_len;
-    buf = (char *) malloc(tot);
-    if (tot != 0 && buf == NULL)
-      {
-	errno = ENOMEM;
-	return -1;
-      }
-    p = buf;
-    for (i = 0; i < msg->msg_iovlen; ++i)
+  int ret;
+  size_t tot = 0;
+  int i;
+  char *buf, *p;
+  struct iovec *iov = msg->msg_iov;
+  struct passfd fdp[1];
+  int extradata = 0;
+
+  fhandler_socket *sock = get (s);
+  syscall_printf ("send_msg (%d, %d, %d)", s, msg->msg_accrightslen, sock ? sock->get_addr_family(): -1);
+
+
+  if (msg->msg_accrightslen && sock && sock->get_addr_family () == AF_LOCAL) {
+    int wfd = *((int*) msg->msg_accrights);
+    
+    //fhandler_socket *h = get (wfd);
+    cygheap_fdget cfd (wfd);
+    syscall_printf("Sending socket: %d %u\n",wfd, cfd); 
+    if (cfd) 
       {
-	memcpy (p, iov[i].iov_base, iov[i].iov_len);
-	p += iov[i].iov_len;
-      }
-    ret = cygwin_sendto (s, buf, tot, flags,
-      (struct sockaddr *) msg->msg_name, msg->msg_namelen);
-    free (buf);
-    return ret;
+	debug_printf("Sending handle: 0x%X\n",cfd->get_handle()); 
+	fdp->uiMagic = 0xAABBCCDD;
+	client_request_hold_handle *request = 
+	  new client_request_hold_handle((DWORD) GetCurrentProcessId(),
+					 cfd->get_handle());
+	int res = cygserver_request(request);
+	syscall_printf("Request: %d, %d\n", res, request->header.error_code);
+	if (res == 0 && request->header.error_code == 0) 
+	  {
+	    fdp->hHandle = request->cygserver_handle();
+	    debug_printf("Handle in cygserver: 0x%X\n", fdp->hHandle); 
+	    fdp->bBinary = cfd->get_flags () & (O_BINARY | O_TEXT);
+	    fdp->iDevice = cfd->get_device();
+	    fdp->bRead = 1;
+	    fdp->bWrite =1;
+
+	    switch (fdp->iDevice) {
+	    case FH_PIPER:
+	      fdp->bWrite = 0;
+	      break;
+	    case FH_PIPEW:
+	      fdp->bRead = 0;
+	      break;
+	    case FH_SOCKET:
+	      fdp->iAF = cfd->is_socket()->get_addr_family ();
+	      break;
+	    default:
+	      break;
+	    }
+	    extradata = sizeof (struct passfd);
+	  }
+	delete request;
+      } 
+  }
+    
+  for(i = 0; i < msg->msg_iovlen; ++i)
+    tot += iov[i].iov_len;
+
+  buf = (char*) malloc (tot + extradata);
+  if (tot != 0 && buf == NULL)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  if (extradata)
+      memcpy (buf, fdp, sizeof (struct passfd));
+  p = buf + extradata;
+
+  for (i = 0; i < msg->msg_iovlen; ++i)
+    {
+      memcpy (p, iov[i].iov_base, iov[i].iov_len);
+      p += iov[i].iov_len;
+    }
+  if (msg->msg_name) 
+    {
+      // Sending an OOB message makes winsock preserve message boundaries
+      if (extradata)
+	cygwin_sendto (s, "k", 1, MSG_OOB, (struct sockaddr *) msg->msg_name, 
+		       msg->msg_namelen);
+      ret = cygwin_sendto (s, buf, tot+ extradata, flags,
+			   (struct sockaddr *) msg->msg_name, msg->msg_namelen);
+    } 
+  else 
+    {
+      // Sending an OOB message makes winsock preserve message boundaries
+      if (extradata) 
+	cygwin_send (s, "k", 1, MSG_OOB);
+      ret = cygwin_send (s, buf, tot + extradata, flags);
+    }
+  free (buf);
+  return ret-extradata;
 }
Index: cygwin/include/cygwin/cygserver.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/cygserver.h,v
retrieving revision 1.3
diff -u -p -r1.3 cygserver.h
--- cygwin/include/cygwin/cygserver.h	13 Mar 2002 02:34:05 -0000	1.3
+++ cygwin/include/cygwin/cygserver.h	26 Jun 2002 18:28:13 -0000
@@ -33,6 +33,8 @@ typedef enum {
   CYGSERVER_REQUEST_ATTACH_TTY,
   CYGSERVER_REQUEST_SHUTDOWN,
   CYGSERVER_REQUEST_SHM_GET,
+  CYGSERVER_REQUEST_HOLD_HANDLE,
+  CYGSERVER_REQUEST_RELEASE_HANDLE,
   CYGSERVER_REQUEST_LAST
 } cygserver_request_code;
 
@@ -82,6 +84,27 @@ struct request_attach_tty
   __attribute__ ((packed))
 #endif
 ;
+
+struct request_hold_handle
+{
+  DWORD pid;
+  HANDLE from_handle, cygserver_handle;
+}
+#ifdef __GNUC__
+  __attribute__ ((packed))
+#endif
+;
+
+struct request_release_handle
+{
+  DWORD pid;
+  HANDLE cygserver_handle, to_handle;
+}
+#ifdef __GNUC__
+  __attribute__ ((packed))
+#endif
+;
+
 
 class client_request
 {
-------------- next part --------------
#include <sys/socket.h>

#include <sys/uio.h>

#include <stdio.h>

#include <errno.h>



ssize_t

writefd (int fd, const void *buf, size_t len, int wfd)

{

  struct iovec iov[1];

  struct msghdr mh;

  int fdp[1];

  iov->iov_base = (void *) buf;

  iov->iov_len = len;



  *fdp = wfd;

  bzero (&mh, sizeof mh);

  mh.msg_iov = (struct iovec *) iov;

  mh.msg_iovlen = 1;

  mh.msg_accrights = (char *) fdp;

  mh.msg_accrightslen = sizeof (fdp);

  return sendmsg (fd, &mh, 0);

}



ssize_t

readfd (int fd, const void *buf, size_t len, int *rfdp)

{

  struct iovec iov[1];

  struct msghdr mh;

  int fdp[1];

  int n;



  iov->iov_base = (void*) buf;

  iov->iov_len = len;



  *fdp = -1;

  bzero (&mh, sizeof mh);

  mh.msg_iov = (struct iovec *) iov;

  mh.msg_iovlen = 1;

  mh.msg_accrights = (char *) fdp;

  mh.msg_accrightslen = sizeof (fdp);



  n = recvmsg (fd, &mh, 0);

  *rfdp = *fdp;

  if (*fdp >= 0 && n == 0) {

    n = -1;

    errno = EAGAIN;

  }

  return n;

}



void fatal(char* s) {

  printf(s);

  exit(1);

}



void fatal2(char* s, char* s2) {

  printf(s, s2);

  exit(1);

}

int

main (int argc, char **argv)

{

  int pid;

  int xfd;

  int rfd;

  int wfd;

  int fds[2];

  char c;

  char msg[] = "Test pattern";

  char buf[sizeof (msg)];



  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0)

    fatal ("socketpair\n");



  pid = fork ();

  if (pid == -1)

    fatal ("fork\n");

  else if (pid == 0) {

    xfd = fds[0];

    close (fds[1]);

  } else {

    xfd = fds[1];

    close (fds[0]);

  }



  if (socketpair (AF_INET, SOCK_STREAM, 0, fds) < 0)

    fatal ("socketpair\n");



  wfd = fds[1];

  if (writefd (xfd, "", 1, fds[0]) < 0)

    fatal ("writefd\n");

  close (fds[0]);



#if 0

  {

    char c;

    write (xfd, "\173", 1);

    read (xfd, &c, 1);

  }

#endif



  if (readfd (xfd, &c, 1, &rfd) < 0)

    fatal ("readfd\n");



  if (pid) {

    if (write (wfd, msg, sizeof (msg)) != sizeof (msg))

      fatal2 ("write: %s\n", (char*)strerror (errno));

    if (read (rfd, buf, sizeof (msg)) != sizeof (msg))

      fatal2 ("read: %s\n", (char*)strerror (errno));

    if (strncmp (msg, buf, sizeof (msg)))

      fatal ("Message corrupt\n");

    printf("Test passed!\n");

  }

  else {

    if (read (rfd, buf, sizeof (msg)) != sizeof (msg))

      fatal2 ("read: %s\n", (char*)strerror (errno));

    if (write (wfd, buf, sizeof (msg)) != sizeof (msg))

      fatal2 ("write: %s\n", (char*)strerror (errno));

  }



  exit (0);

}





More information about the Cygwin-patches mailing list