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 getsockname (struct sockaddr *name, int *namelen);
|
||||||
int getpeername (struct sockaddr *name, int *namelen);
|
int getpeername (struct sockaddr *name, int *namelen);
|
||||||
int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid);
|
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);
|
int open (int flags, mode_t mode = 0);
|
||||||
void __reg3 read (void *ptr, size_t& len);
|
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;
|
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
|
void
|
||||||
|
|
|
@ -2767,201 +2767,98 @@ cygwin_bindresvport (int fd, struct sockaddr_in *sin)
|
||||||
return cygwin_bindresvport_sa (fd, (struct sockaddr *) sin);
|
return cygwin_bindresvport_sa (fd, (struct sockaddr *) sin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* socketpair: standards? */
|
/* socketpair: POSIX.1-2001, POSIX.1-2008, 4.4BSD. */
|
||||||
/* Win32 supports AF_INET only, so ignore domain and protocol arguments */
|
|
||||||
extern "C" int
|
extern "C" int
|
||||||
socketpair (int family, int type, int protocol, int *sb)
|
socketpair (int af, int type, int protocol, int *sb)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
SOCKET insock = INVALID_SOCKET;
|
const device *dev;
|
||||||
SOCKET outsock = INVALID_SOCKET;
|
fhandler_socket *fh_in, *fh_out;
|
||||||
SOCKET newsock = INVALID_SOCKET;
|
|
||||||
struct sockaddr_in sock_in, sock_out;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
__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;
|
case AF_LOCAL:
|
||||||
type &= ~_SOCK_FLAG_MASK;
|
|
||||||
|
|
||||||
if (family != AF_LOCAL && family != AF_INET)
|
|
||||||
{
|
|
||||||
set_errno (EAFNOSUPPORT);
|
|
||||||
__leave;
|
|
||||||
}
|
|
||||||
if (type != SOCK_STREAM && type != SOCK_DGRAM)
|
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);
|
fd_in.release ();
|
||||||
__leave;
|
goto done;
|
||||||
}
|
|
||||||
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 */
|
fh_in = (fhandler_socket *) build_fh_dev (*dev);
|
||||||
newsock = socket (AF_INET, type, 0);
|
fh_out = (fhandler_socket *) build_fh_dev (*dev);
|
||||||
if (newsock == INVALID_SOCKET)
|
if (fh_in && fh_out
|
||||||
|
&& fh_in->socketpair (af, type, protocol, flags, fh_out) == 0)
|
||||||
{
|
{
|
||||||
debug_printf ("first socket call failed");
|
fd_in = fh_in;
|
||||||
set_winsock_errno ();
|
fd_out = fh_out;
|
||||||
__leave;
|
if (fd_in <= 2)
|
||||||
}
|
set_std_handle (fd_in);
|
||||||
|
if (fd_out <= 2)
|
||||||
/* bind the socket to any unused port */
|
set_std_handle (fd_out);
|
||||||
sock_in.sin_family = AF_INET;
|
__try
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
debug_printf ("bind failed");
|
sb[0] = fd_in;
|
||||||
set_winsock_errno ();
|
sb[1] = fd_out;
|
||||||
__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;
|
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
else
|
__except (EFAULT) {}
|
||||||
sb0.release ();
|
__endtry
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fd_in.release ();
|
||||||
|
fd_out.release ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__except (EFAULT) {}
|
|
||||||
__endtry
|
done:
|
||||||
syscall_printf ("%R = socketpair(...)", res);
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue