This is the mail archive of the cygwin-cvs@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]

[newlib-cygwin] Cygwin: socketpair: Move socketpair creation inside fhandler_socket class


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=4e04751fc76611c68460395b491990678f54e313

commit 4e04751fc76611c68460395b491990678f54e313
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Fri Feb 16 16:36:19 2018 +0100

    Cygwin: socketpair: Move socketpair creation inside fhandler_socket class
    
    Add fhandler_socket::socketpair method
    
    Deliberately disable AF_INET socketpairs for now
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/fhandler.h         |   2 +
 winsup/cygwin/fhandler_socket.cc | 124 ++++++++++++++++++++
 winsup/cygwin/net.cc             | 245 ++++++++++++---------------------------
 3 files changed, 197 insertions(+), 174 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 99cacd3..c24304b 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -588,6 +588,8 @@ class fhandler_socket: public fhandler_base
   int getsockname (struct sockaddr *name, int *namelen);
   int getpeername (struct sockaddr *name, int *namelen);
   int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid);
+  socketpair (int af, int type, int protocol, int flags,
+	      fhandler_socket *fh_out);
 
   int open (int flags, mode_t mode = 0);
   void __reg3 read (void *ptr, size_t& len);
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index d7e9171..3a18ff5 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -377,6 +377,130 @@ fhandler_socket::socket (int af, int type, int protocol, int flags)
   return ret;
 }
 
+/* fhandler_socket::socketpair is called on the fhandler handling the
+   accepting socket, fh_out is the fhandler for the connecting socket. */
+int
+fhandler_socket::socketpair (int af, int type, int protocol, int flags,
+			     fhandler_socket *fh_out)
+{
+  SOCKET insock = INVALID_SOCKET;
+  SOCKET outsock = INVALID_SOCKET;
+  SOCKET sock = INVALID_SOCKET;
+  struct sockaddr_in sock_in, sock_out;
+  int len;
+
+  /* create listening socket */
+  sock = ::socket (AF_INET, type, 0);
+  if (sock == INVALID_SOCKET)
+    {
+      set_winsock_errno ();
+      goto err;
+    }
+  /* bind to unused port */
+  sock_in.sin_family = AF_INET;
+  sock_in.sin_port = 0;
+  sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+  if (::bind (sock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
+    {
+      set_winsock_errno ();
+      goto err;
+    }
+  /* fetch socket name */
+  len = sizeof (sock_in);
+  if (::getsockname (sock, (struct sockaddr *) &sock_in, &len) < 0)
+    {
+      set_winsock_errno ();
+      goto err;
+    }
+  /* on stream sockets, create listener */
+  if (type == SOCK_STREAM && ::listen (sock, 2) < 0)
+    {
+      set_winsock_errno ();
+      goto err;
+    }
+  /* create connecting socket */
+  outsock = ::socket (AF_INET, type, 0);
+  if (outsock == INVALID_SOCKET)
+    {
+      set_winsock_errno ();
+      goto err;
+    }
+  /* on datagram sockets, bind connecting socket */
+  if (type == SOCK_DGRAM)
+    {
+      sock_out.sin_family = AF_INET;
+      sock_out.sin_port = 0;
+      sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+      if (::bind (outsock, (struct sockaddr *) &sock_out,
+		  sizeof (sock_out)) < 0)
+	{
+	  set_winsock_errno ();
+	  goto err;
+	}
+      /* ...and fetch name */
+      len = sizeof (sock_out);
+      if (::getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0)
+	{
+	  set_winsock_errno ();
+	  goto err;
+	}
+    }
+  sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+  if (type == SOCK_DGRAM)
+    sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+  /* connect */
+  if (::connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
+    {
+      set_winsock_errno ();
+      goto err;
+    }
+  if (type == SOCK_STREAM)
+    {
+      /* on stream sockets, accept connection and close listener */
+      len = sizeof (sock_in);
+      insock = ::accept (sock, (struct sockaddr *) &sock_in, &len);
+      if (insock == INVALID_SOCKET)
+	{
+	  set_winsock_errno ();
+	  goto err;
+	}
+      ::closesocket (sock);
+    }
+  else
+    {
+      /* on datagram sockets, connect vice versa */
+      if (::connect (sock, (struct sockaddr *) &sock_out,
+		   sizeof (sock_out)) < 0)
+	{
+	  set_winsock_errno ();
+	  goto err;
+	}
+      insock = sock;
+    }
+  sock = INVALID_SOCKET;
+
+  /* postprocessing */
+  connect_state (connected);
+  fh_out->connect_state (connected);
+  if (af == AF_LOCAL && type == SOCK_STREAM)
+    {
+      af_local_set_sockpair_cred ();
+      fh_out->af_local_set_sockpair_cred ();
+    }
+  if (set_socket_handle (insock, af, type, flags) < 0
+      || fh_out->set_socket_handle (outsock, af, type, flags) < 0)
+    goto err;
+
+  return 0;
+
+err:
+  if (sock != INVALID_SOCKET)
+    ::closesocket (sock);
+  if (insock != INVALID_SOCKET)
+    ::closesocket (insock);
+  if (outsock != INVALID_SOCKET)
+    ::closesocket (outsock);
+  return -1;
 }
 
 void
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 8497d59..b6209fc 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -2767,201 +2767,98 @@ cygwin_bindresvport (int fd, struct sockaddr_in *sin)
   return cygwin_bindresvport_sa (fd, (struct sockaddr *) sin);
 }
 
-/* socketpair: standards? */
-/* Win32 supports AF_INET only, so ignore domain and protocol arguments */
+/* socketpair: POSIX.1-2001, POSIX.1-2008, 4.4BSD. */
 extern "C" int
-socketpair (int family, int type, int protocol, int *sb)
+socketpair (int af, int type, int protocol, int *sb)
 {
   int res = -1;
-  SOCKET insock = INVALID_SOCKET;
-  SOCKET outsock = INVALID_SOCKET;
-  SOCKET newsock = INVALID_SOCKET;
-  struct sockaddr_in sock_in, sock_out;
-  int len;
-
-  __try
-    {
-      int flags = type & _SOCK_FLAG_MASK;
-      type &= ~_SOCK_FLAG_MASK;
-
-      if (family != AF_LOCAL && family != AF_INET)
-	{
-	  set_errno (EAFNOSUPPORT);
-	  __leave;
-	}
-      if (type != SOCK_STREAM && type != SOCK_DGRAM)
-	{
-	  set_errno (EPROTOTYPE);
-	  __leave;
-	}
-      if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0)
-	{
-	  set_errno (EINVAL);
-	  __leave;
-	}
-      if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL)
-	  || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET))
-	{
-	  set_errno (EPROTONOSUPPORT);
-	  __leave;
-	}
-
-      /* create the first socket */
-      newsock = socket (AF_INET, type, 0);
-      if (newsock == INVALID_SOCKET)
-	{
-	  debug_printf ("first socket call failed");
-	  set_winsock_errno ();
-	  __leave;
-	}
+  const device *dev;
+  fhandler_socket *fh_in, *fh_out;
 
-      /* bind the socket to any unused port */
-      sock_in.sin_family = AF_INET;
-      sock_in.sin_port = 0;
-      sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-      if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
-	{
-	  debug_printf ("bind failed");
-	  set_winsock_errno ();
-	  __leave;
-	}
-      len = sizeof (sock_in);
-      if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0)
-	{
-	  debug_printf ("getsockname error");
-	  set_winsock_errno ();
-	  __leave;
-	}
+  int flags = type & _SOCK_FLAG_MASK;
+  type &= ~_SOCK_FLAG_MASK;
 
-      /* For stream sockets, create a listener */
-      if (type == SOCK_STREAM)
-	listen (newsock, 2);
+  debug_printf ("socket (%d, %d (flags %y), %d)", af, type, flags, protocol);
 
-      /* create a connecting socket */
-      outsock = socket (AF_INET, type, 0);
-      if (outsock == INVALID_SOCKET)
-	{
-	  debug_printf ("second socket call failed");
-	  set_winsock_errno ();
-	  __leave;
-	}
+  switch (af)
+    {
+    case AF_LOCAL:
+      if (type != SOCK_STREAM && type != SOCK_DGRAM)
+        {
+          set_errno (EINVAL);
+          goto done;
+        }
+      if (protocol != 0)
+        {
+          set_errno (EPROTONOSUPPORT);
+          goto done;
+        }
+      dev = type == SOCK_STREAM ? stream_dev : dgram_dev;
+      break;
+#if 0 /* FIXME: Given neither BSD nor Linux support anything other than AF_LOCAL
+	 sockets, we deliberately disable AF_INIT socketpairs now and hope for
+	 the best. */
+    case AF_INET:
+      if (type != SOCK_STREAM && type != SOCK_DGRAM)
+        {
+          set_errno (EINVAL);
+          goto done;
+        }
+      dev = type == SOCK_STREAM ? tcp_dev : udp_dev;
+      break;
+#endif
+    default:
+      set_errno (EAFNOSUPPORT);
+      goto done;
+    }
 
-      /* For datagram sockets, bind the 2nd socket to an unused address, too */
-      if (type == SOCK_DGRAM)
-	{
-	  sock_out.sin_family = AF_INET;
-	  sock_out.sin_port = 0;
-	  sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-	  if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0)
-	    {
-	      debug_printf ("bind failed");
-	      set_winsock_errno ();
-	      __leave;
-	    }
-	  len = sizeof (sock_out);
-	  if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0)
-	    {
-	      debug_printf ("getsockname error");
-	      set_winsock_errno ();
-	      __leave;
-	    }
-	}
+  if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0)
+    {
+      set_errno (EINVAL);
+      goto done;
+    }
 
-      /* Force IP address to loopback */
-      sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-      if (type == SOCK_DGRAM)
-	sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+    {
+      cygheap_fdnew fd_in;
+      if (fd_in < 0)
+	goto done;
 
-      /* Do a connect */
-      if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
+      cygheap_fdnew fd_out (fd_in, false);
+      if (fd_out < 0)
 	{
-	  debug_printf ("connect error");
-	  set_winsock_errno ();
-	  __leave;
+	  fd_in.release ();
+	  goto done;
 	}
 
-      if (type == SOCK_STREAM)
+      fh_in = (fhandler_socket *) build_fh_dev (*dev);
+      fh_out = (fhandler_socket *) build_fh_dev (*dev);
+      if (fh_in && fh_out
+	  && fh_in->socketpair (af, type, protocol, flags, fh_out) == 0)
 	{
-	  /* For stream sockets, accept the connection and close the listener */
-	  len = sizeof (sock_in);
-	  insock = accept (newsock, (struct sockaddr *) &sock_in, &len);
-	  if (insock == INVALID_SOCKET)
+	  fd_in = fh_in;
+	  fd_out = fh_out;
+	  if (fd_in <= 2)
+	    set_std_handle (fd_in);
+	  if (fd_out <= 2)
+	    set_std_handle (fd_out);
+	  __try
 	    {
-	      debug_printf ("accept error");
-	      set_winsock_errno ();
-	      __leave;
+	      sb[0] = fd_in;
+	      sb[1] = fd_out;
+	      res = 0;
 	    }
-	  closesocket (newsock);
-	  newsock = INVALID_SOCKET;
+	  __except (EFAULT) {}
+	  __endtry
 	}
       else
 	{
-	  /* For datagram sockets, connect the 2nd socket */
-	  if (connect (newsock, (struct sockaddr *) &sock_out,
-		       sizeof (sock_out)) < 0)
-	    {
-	      debug_printf ("connect error");
-	      set_winsock_errno ();
-	      __leave;
-	    }
-	  insock = newsock;
-	  newsock = INVALID_SOCKET;
-	}
-
-      cygheap_fdnew sb0;
-      const device *dev;
-
-      if (family == AF_INET)
-	dev = (type == SOCK_STREAM ? tcp_dev : udp_dev);
-      else
-	dev = (type == SOCK_STREAM ? stream_dev : dgram_dev);
-
-      if (sb0 >= 0 && fdsock (sb0, dev, insock))
-	{
-	  ((fhandler_socket *) sb0)->set_addr_family (family);
-	  ((fhandler_socket *) sb0)->set_socket_type (type);
-	  ((fhandler_socket *) sb0)->connect_state (connected);
-	  if (flags & SOCK_NONBLOCK)
-	    ((fhandler_socket *) sb0)->set_nonblocking (true);
-	  if (flags & SOCK_CLOEXEC)
-	    ((fhandler_socket *) sb0)->set_close_on_exec (true);
-	  if (family == AF_LOCAL && type == SOCK_STREAM)
-	    ((fhandler_socket *) sb0)->af_local_set_sockpair_cred ();
-
-	  cygheap_fdnew sb1 (sb0, false);
-
-	  if (sb1 >= 0 && fdsock (sb1, dev, outsock))
-	    {
-	      ((fhandler_socket *) sb1)->set_addr_family (family);
-	      ((fhandler_socket *) sb1)->set_socket_type (type);
-	      ((fhandler_socket *) sb1)->connect_state (connected);
-	      if (flags & SOCK_NONBLOCK)
-		((fhandler_socket *) sb1)->set_nonblocking (true);
-	      if (flags & SOCK_CLOEXEC)
-		((fhandler_socket *) sb1)->set_close_on_exec (true);
-	      if (family == AF_LOCAL && type == SOCK_STREAM)
-		((fhandler_socket *) sb1)->af_local_set_sockpair_cred ();
-
-	      sb[0] = sb0;
-	      sb[1] = sb1;
-	      res = 0;
-	    }
-	  else
-	    sb0.release ();
+	  fd_in.release ();
+	  fd_out.release ();
 	}
     }
-  __except (EFAULT) {}
-  __endtry
+
+done:
   syscall_printf ("%R = socketpair(...)", res);
-  if (res == -1)
-    {
-      if (insock != INVALID_SOCKET)
-	closesocket (insock);
-      if (outsock != INVALID_SOCKET)
-	closesocket (outsock);
-      if (newsock != INVALID_SOCKET)
-	closesocket (newsock);
-    }
   return res;
 }


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