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>
This commit is contained in:
parent
cff85eaddc
commit
4e04751fc7
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
const device *dev;
|
||||
fhandler_socket *fh_in, *fh_out;
|
||||
|
||||
__try
|
||||
int flags = type & _SOCK_FLAG_MASK;
|
||||
type &= ~_SOCK_FLAG_MASK;
|
||||
|
||||
debug_printf ("socket (%d, %d (flags %y), %d)", af, type, flags, protocol);
|
||||
|
||||
switch (af)
|
||||
{
|
||||
int flags = type & _SOCK_FLAG_MASK;
|
||||
type &= ~_SOCK_FLAG_MASK;
|
||||
|
||||
if (family != AF_LOCAL && family != AF_INET)
|
||||
{
|
||||
set_errno (EAFNOSUPPORT);
|
||||
__leave;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
{
|
||||
cygheap_fdnew fd_in;
|
||||
if (fd_in < 0)
|
||||
goto done;
|
||||
|
||||
cygheap_fdnew fd_out (fd_in, false);
|
||||
if (fd_out < 0)
|
||||
{
|
||||
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;
|
||||
fd_in.release ();
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* create the first socket */
|
||||
newsock = socket (AF_INET, type, 0);
|
||||
if (newsock == INVALID_SOCKET)
|
||||
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)
|
||||
{
|
||||
debug_printf ("first socket call failed");
|
||||
set_winsock_errno ();
|
||||
__leave;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* For stream sockets, create a listener */
|
||||
if (type == SOCK_STREAM)
|
||||
listen (newsock, 2);
|
||||
|
||||
/* create a connecting socket */
|
||||
outsock = socket (AF_INET, type, 0);
|
||||
if (outsock == INVALID_SOCKET)
|
||||
{
|
||||
debug_printf ("second socket call failed");
|
||||
set_winsock_errno ();
|
||||
__leave;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
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 ("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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Do a connect */
|
||||
if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
|
||||
{
|
||||
debug_printf ("connect error");
|
||||
set_winsock_errno ();
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (type == SOCK_STREAM)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
debug_printf ("accept error");
|
||||
set_winsock_errno ();
|
||||
__leave;
|
||||
}
|
||||
closesocket (newsock);
|
||||
newsock = INVALID_SOCKET;
|
||||
}
|
||||
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;
|
||||
sb[0] = fd_in;
|
||||
sb[1] = fd_out;
|
||||
res = 0;
|
||||
}
|
||||
else
|
||||
sb0.release ();
|
||||
__except (EFAULT) {}
|
||||
__endtry
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user