* fhandler.h (fhandler_socket::bind): Add method definition.

(fhandler_socket::connect): Ditto.
	(fhandler_socket::listen): Ditto.
	(fhandler_socket::accept): Ditto.
	(fhandler_socket::getsockname): Ditto.
	(fhandler_socket::getpeername): Ditto.
	(fhandler_socket::recvfrom): Ditto.
	(fhandler_socket::recvmsg): Ditto.
	(fhandler_socket::sendto): Ditto.
	(fhandler_socket::sendmsg): Ditto.
	(fhandler_socket::shutdown): Ditto.
	* fhandler_socket.cc (get_inet_addr): Move here from net.cc.
	(fhandler_socket::bind): New method.
	(fhandler_socket::connect): Ditto.
	(fhandler_socket::listen): Ditto.
	(fhandler_socket::accept): Ditto.
	(fhandler_socket::getsockname): Ditto.
	(fhandler_socket::getpeername): Ditto.
	(fhandler_socket::recvfrom): Ditto.
	(fhandler_socket::recvmsg): Ditto.
	(fhandler_socket::sendto): Ditto.
	(fhandler_socket::sendmsg): Ditto.
	(fhandler_socket::shutdown): Ditto.
	* net.cc: Various formatting cleanups throughout.
	(get_inet_addr): Move to fhandler_socket.cc.
	(cygwin_bind): Move base functionality to appropriate fhandler_socket
	method.
	(cygwin_connect): Ditto.
	(cygwin_listen): Ditto.
	(cygwin_accept): Ditto.
	(cygwin_getsockname): Ditto.
	(cygwin_getpeername): Ditto.
	(cygwin_recvfrom): Ditto.
	(cygwin_recvmsg): Ditto.
	(cygwin_sendto): Ditto.
	(cygwin_sendmsg): Ditto.
	(cygwin_shutdown): Ditto.
This commit is contained in:
Corinna Vinschen 2002-06-26 19:25:09 +00:00
parent 0431ed4e0d
commit be5007aa52
4 changed files with 649 additions and 484 deletions

View File

@ -1,3 +1,43 @@
2002-06-26 Corinna Vinschen <corinna@vinschen.de>
* fhandler.h (fhandler_socket::bind): Add method definition.
(fhandler_socket::connect): Ditto.
(fhandler_socket::listen): Ditto.
(fhandler_socket::accept): Ditto.
(fhandler_socket::getsockname): Ditto.
(fhandler_socket::getpeername): Ditto.
(fhandler_socket::recvfrom): Ditto.
(fhandler_socket::recvmsg): Ditto.
(fhandler_socket::sendto): Ditto.
(fhandler_socket::sendmsg): Ditto.
(fhandler_socket::shutdown): Ditto.
* fhandler_socket.cc (get_inet_addr): Move here from net.cc.
(fhandler_socket::bind): New method.
(fhandler_socket::connect): Ditto.
(fhandler_socket::listen): Ditto.
(fhandler_socket::accept): Ditto.
(fhandler_socket::getsockname): Ditto.
(fhandler_socket::getpeername): Ditto.
(fhandler_socket::recvfrom): Ditto.
(fhandler_socket::recvmsg): Ditto.
(fhandler_socket::sendto): Ditto.
(fhandler_socket::sendmsg): Ditto.
(fhandler_socket::shutdown): Ditto.
* net.cc: Various formatting cleanups throughout.
(get_inet_addr): Move to fhandler_socket.cc.
(cygwin_bind): Move base functionality to appropriate fhandler_socket
method.
(cygwin_connect): Ditto.
(cygwin_listen): Ditto.
(cygwin_accept): Ditto.
(cygwin_getsockname): Ditto.
(cygwin_getpeername): Ditto.
(cygwin_recvfrom): Ditto.
(cygwin_recvmsg): Ditto.
(cygwin_sendto): Ditto.
(cygwin_sendmsg): Ditto.
(cygwin_shutdown): Ditto.
2002-06-26 Corinna Vinschen <corinna@vinschen.de> 2002-06-26 Corinna Vinschen <corinna@vinschen.de>
* pwdgrp.h (pwdgrp_read::~pwdgrp_read): Avoid compiler warning. * pwdgrp.h (pwdgrp_read::~pwdgrp_read): Avoid compiler warning.

View File

@ -380,15 +380,30 @@ class fhandler_socket: public fhandler_base
void set_shutdown_read () {FHSETF (SHUTRD);} void set_shutdown_read () {FHSETF (SHUTRD);}
void set_shutdown_write () {FHSETF (SHUTWR);} void set_shutdown_write () {FHSETF (SHUTWR);}
int bind (const struct sockaddr *name, int namelen);
int connect (const struct sockaddr *name, int namelen);
int listen (int backlog);
int accept (struct sockaddr *peer, int *len);
int getsockname (struct sockaddr *name, int *namelen);
int getpeername (struct sockaddr *name, int *namelen);
int recv (void *ptr, size_t len, unsigned int flags); int recv (void *ptr, size_t len, unsigned int flags);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3))); int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
int recvfrom (void *ptr, size_t len, unsigned int flags,
struct sockaddr *from, int *fromlen);
int recvmsg (struct msghdr *msg, int flags);
int send (const void *ptr, size_t len, unsigned int flags); int send (const void *ptr, size_t len, unsigned int flags);
int write (const void *ptr, size_t len); int write (const void *ptr, size_t len);
int sendto (const void *ptr, size_t len, unsigned int flags,
const struct sockaddr *to, int tolen);
int sendmsg (const struct msghdr *msg, int flags);
int ioctl (unsigned int cmd, void *); int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, void *); int fcntl (int cmd, void *);
__off64_t lseek (__off64_t, int) { return 0; } __off64_t lseek (__off64_t, int) { return 0; }
int shutdown (int how);
int close (); int close ();
void hclose (HANDLE) {close ();} void hclose (HANDLE) {close ();}
int dup (fhandler_base *child); int dup (fhandler_base *child);

View File

@ -15,6 +15,8 @@
#include "winsup.h" #include "winsup.h"
#include <errno.h> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <stdlib.h> #include <stdlib.h>
@ -36,8 +38,59 @@
#define ENTROPY_SOURCE_NAME "/dev/urandom" #define ENTROPY_SOURCE_NAME "/dev/urandom"
#define ENTROPY_SOURCE_DEV_UNIT 9 #define ENTROPY_SOURCE_DEV_UNIT 9
extern fhandler_socket *fdsock (int& fd, const char *name, SOCKET soc);
extern "C" {
int sscanf (const char *, const char *, ...);
} /* End of "C" section */
fhandler_dev_random* entropy_source; fhandler_dev_random* entropy_source;
/* cygwin internal: map sockaddr into internet domain address */
static int
get_inet_addr (const struct sockaddr *in, int inlen,
struct sockaddr_in *out, int *outlen, int* secret = 0)
{
int secret_buf [4];
int* secret_ptr = (secret ? : secret_buf);
if (in->sa_family == AF_INET)
{
*out = * (sockaddr_in *)in;
*outlen = inlen;
return 1;
}
else if (in->sa_family == AF_LOCAL)
{
int fd = _open (in->sa_data, O_RDONLY);
if (fd == -1)
return 0;
int ret = 0;
char buf[128];
memset (buf, 0, sizeof buf);
if (read (fd, buf, sizeof buf) != -1)
{
sockaddr_in sin;
sin.sin_family = AF_INET;
sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",
&sin.sin_port,
secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3);
sin.sin_port = htons (sin.sin_port);
sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
*out = sin;
*outlen = sizeof sin;
ret = 1;
}
_close (fd);
return ret;
}
else
{
set_errno (EAFNOSUPPORT);
return 0;
}
}
/**********************************************************************/ /**********************************************************************/
/* fhandler_socket */ /* fhandler_socket */
@ -93,7 +146,7 @@ fhandler_socket::create_secret_event (int* secret)
struct sockaddr_in sin; struct sockaddr_in sin;
int sin_len = sizeof (sin); int sin_len = sizeof (sin);
if (getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len)) if (::getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
{ {
debug_printf ("error getting local socket name (%d)", WSAGetLastError ()); debug_printf ("error getting local socket name (%d)", WSAGetLastError ());
return NULL; return NULL;
@ -256,6 +309,293 @@ fhandler_socket::fstat (struct __stat64 *buf, path_conv *pc)
return res; return res;
} }
int
fhandler_socket::bind (const struct sockaddr *name, int namelen)
{
int res = -1;
if (name->sa_family == AF_LOCAL)
{
#define un_addr ((struct sockaddr_un *) name)
struct sockaddr_in sin;
int len = sizeof sin;
int fd;
if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN)
{
set_errno (ENAMETOOLONG);
goto out;
}
sin.sin_family = AF_INET;
sin.sin_port = 0;
sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
if (::bind (get_socket (), (sockaddr *) &sin, len))
{
syscall_printf ("AF_LOCAL: bind failed %d", get_errno ());
set_winsock_errno ();
goto out;
}
if (::getsockname (get_socket (), (sockaddr *) &sin, &len))
{
syscall_printf ("AF_LOCAL: getsockname failed %d", get_errno ());
set_winsock_errno ();
goto out;
}
sin.sin_port = ntohs (sin.sin_port);
debug_printf ("AF_LOCAL: socket bound to port %u", sin.sin_port);
/* bind must fail if file system socket object already exists
so _open () is called with O_EXCL flag. */
fd = _open (un_addr->sun_path,
O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
0);
if (fd < 0)
{
if (get_errno () == EEXIST)
set_errno (EADDRINUSE);
goto out;
}
set_connect_secret ();
char buf[sizeof (SOCKET_COOKIE) + 80];
__small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);
get_connect_secret (strchr (buf, '\0'));
len = strlen (buf) + 1;
/* Note that the terminating nul is written. */
if (_write (fd, buf, len) != len)
{
save_errno here;
_close (fd);
_unlink (un_addr->sun_path);
}
else
{
_close (fd);
chmod (un_addr->sun_path,
(S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask);
set_sun_path (un_addr->sun_path);
res = 0;
}
#undef un_addr
}
else if (::bind (get_socket (), name, namelen))
set_winsock_errno ();
else
res = 0;
out:
return res;
}
int
fhandler_socket::connect (const struct sockaddr *name, int namelen)
{
int res = -1;
BOOL secret_check_failed = FALSE;
BOOL in_progress = FALSE;
sockaddr_in sin;
int secret [4];
sigframe thisframe (mainthread);
if (!get_inet_addr (name, namelen, &sin, &namelen, secret))
return -1;
res = ::connect (get_socket (), (sockaddr *) &sin, namelen);
if (res)
{
/* Special handling for connect to return the correct error code
when called on a non-blocking socket. */
if (is_nonblocking ())
{
DWORD err = WSAGetLastError ();
if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
{
WSASetLastError (WSAEINPROGRESS);
in_progress = TRUE;
}
else if (err == WSAEINVAL)
WSASetLastError (WSAEISCONN);
}
set_winsock_errno ();
}
if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
{
if (!res || in_progress)
{
if (!create_secret_event (secret))
{
secret_check_failed = TRUE;
}
else if (in_progress)
signal_secret_event ();
}
if (!secret_check_failed && !res)
{
if (!check_peer_secret_event (&sin, secret))
{
debug_printf ( "accept from unauthorized server" );
secret_check_failed = TRUE;
}
}
if (secret_check_failed)
{
close_secret_event ();
if (res)
closesocket (res);
set_errno (ECONNREFUSED);
res = -1;
}
}
return res;
}
int
fhandler_socket::listen (int backlog)
{
int res = ::listen (get_socket (), backlog);
if (res)
set_winsock_errno ();
return res;
}
int
fhandler_socket::accept (struct sockaddr *peer, int *len)
{
int res = -1;
BOOL secret_check_failed = FALSE;
BOOL in_progress = FALSE;
sigframe thisframe (mainthread);
/* Allows NULL peer and len parameters. */
struct sockaddr_in peer_dummy;
int len_dummy;
if (!peer)
peer = (struct sockaddr *) &peer_dummy;
if (!len)
{
len_dummy = sizeof (struct sockaddr_in);
len = &len_dummy;
}
/* accept on NT fails if len < sizeof (sockaddr_in)
* some programs set len to
* sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain
*/
if (len && ((unsigned) *len < sizeof (struct sockaddr_in)))
*len = sizeof (struct sockaddr_in);
res = ::accept (get_socket (), peer, len); // can't use a blocking call inside a lock
if ((SOCKET) res == (SOCKET) INVALID_SOCKET &&
WSAGetLastError () == WSAEWOULDBLOCK)
in_progress = TRUE;
if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
{
if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress)
{
if (!create_secret_event ())
secret_check_failed = TRUE;
else if (in_progress)
signal_secret_event ();
}
if (!secret_check_failed &&
(SOCKET) res != (SOCKET) INVALID_SOCKET)
{
if (!check_peer_secret_event ((struct sockaddr_in*) peer))
{
debug_printf ("connect from unauthorized client");
secret_check_failed = TRUE;
}
}
if (secret_check_failed)
{
close_secret_event ();
if ((SOCKET) res != (SOCKET) INVALID_SOCKET)
closesocket (res);
set_errno (ECONNABORTED);
res = -1;
return res;
}
}
cygheap_fdnew res_fd;
if (res_fd < 0)
/* FIXME: what is correct errno? */;
else if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
set_winsock_errno ();
else
{
fhandler_socket* res_fh = fdsock (res_fd, get_name (), res);
if (get_addr_family () == AF_LOCAL)
res_fh->set_sun_path (get_sun_path ());
res_fh->set_addr_family (get_addr_family ());
res_fh->set_socket_type (get_socket_type ());
res = res_fd;
}
return res;
}
int
fhandler_socket::getsockname (struct sockaddr *name, int *namelen)
{
int res = -1;
sigframe thisframe (mainthread);
if (get_addr_family () == AF_LOCAL)
{
struct sockaddr_un *sun = (struct sockaddr_un *) name;
memset (sun, 0, *namelen);
sun->sun_family = AF_LOCAL;
if (!get_sun_path ())
sun->sun_path[0] = '\0';
else
/* According to SUSv2 "If the actual length of the address is
greater than the length of the supplied sockaddr structure, the
stored address will be truncated." We play it save here so
that the path always has a trailing 0 even if it's truncated. */
strncpy (sun->sun_path, get_sun_path (),
*namelen - sizeof *sun + sizeof sun->sun_path - 1);
*namelen = sizeof *sun - sizeof sun->sun_path
+ strlen (sun->sun_path) + 1;
res = 0;
}
else
{
res = ::getsockname (get_socket (), name, namelen);
if (res)
set_winsock_errno ();
}
return res;
}
int
fhandler_socket::getpeername (struct sockaddr *name, int *namelen)
{
sigframe thisframe (mainthread);
int res = ::getpeername (get_socket (), name, namelen);
if (res)
set_winsock_errno ();
return res;
}
int int
fhandler_socket::recv (void *ptr, size_t len, unsigned int flags) fhandler_socket::recv (void *ptr, size_t len, unsigned int flags)
{ {
@ -264,6 +604,7 @@ fhandler_socket::recv (void *ptr, size_t len, unsigned int flags)
LPWSAOVERLAPPED ovr; LPWSAOVERLAPPED ovr;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
if (is_nonblocking () || !(ovr = wsock_evt.prepare ())) if (is_nonblocking () || !(ovr = wsock_evt.prepare ()))
{ {
debug_printf ("Fallback to winsock 1 recv call"); debug_printf ("Fallback to winsock 1 recv call");
@ -298,6 +639,88 @@ fhandler_socket::read (void *ptr, size_t len)
return recv (ptr, len, 0); return recv (ptr, len, 0);
} }
int
fhandler_socket::recvfrom (void *ptr, size_t len, unsigned int flags,
struct sockaddr *from, int *fromlen)
{
int res = -1;
wsock_event wsock_evt;
LPWSAOVERLAPPED ovr;
sigframe thisframe (mainthread);
if (is_nonblocking () || !(ovr = wsock_evt.prepare ()))
{
debug_printf ("Fallback to winsock 1 recvfrom call");
if ((res = ::recvfrom (get_socket (), (char *) ptr, len, flags, from,
fromlen))
== SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
}
else
{
WSABUF wsabuf = { len, (char *) ptr };
DWORD ret = 0;
if (WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags,
from, fromlen, ovr, NULL) != SOCKET_ERROR)
res = ret;
else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
{
set_winsock_errno ();
res = -1;
}
else if ((res = wsock_evt.wait (get_socket (), (DWORD *)&flags)) == -1)
set_winsock_errno ();
}
return res;
}
int
fhandler_socket::recvmsg (struct msghdr *msg, int flags)
{
int res = -1;
int nb;
size_t tot = 0;
char *buf, *p;
struct iovec *iov = msg->msg_iov;
sigframe thisframe (mainthread);
if (get_addr_family () == AF_LOCAL)
{
/* On AF_LOCAL sockets the (fixed-size) name of the shared memory
area used for descriptor passing is transmitted first.
If this string is empty, no descriptors are passed and we can
go ahead recv'ing the normal data blocks. Otherwise start
special handling for descriptor passing. */
/*TODO*/
}
for (int i = 0; i < msg->msg_iovlen; ++i)
tot += iov[i].iov_len;
buf = (char *) alloca (tot);
if (tot != 0 && buf == NULL)
{
set_errno (ENOMEM);
return -1;
}
nb = res = recvfrom (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);
memcpy (iov->iov_base, p, cnt);
p += cnt;
nb -= cnt;
++iov;
}
return res;
}
int int
fhandler_socket::send (const void *ptr, size_t len, unsigned int flags) fhandler_socket::send (const void *ptr, size_t len, unsigned int flags)
{ {
@ -306,6 +729,7 @@ fhandler_socket::send (const void *ptr, size_t len, unsigned int flags)
LPWSAOVERLAPPED ovr; LPWSAOVERLAPPED ovr;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
if (is_nonblocking () || !(ovr = wsock_evt.prepare ())) if (is_nonblocking () || !(ovr = wsock_evt.prepare ()))
{ {
debug_printf ("Fallback to winsock 1 send call"); debug_printf ("Fallback to winsock 1 send call");
@ -340,11 +764,111 @@ fhandler_socket::write (const void *ptr, size_t len)
return send (ptr, len, 0); return send (ptr, len, 0);
} }
/* Cygwin internal */ int
fhandler_socket::sendto (const void *ptr, size_t len, unsigned int flags,
const struct sockaddr *to, int tolen)
{
int res = -1;
wsock_event wsock_evt;
LPWSAOVERLAPPED ovr;
sockaddr_in sin;
sigframe thisframe (mainthread);
if (!get_inet_addr (to, tolen, &sin, &tolen))
return -1;
if (is_nonblocking () || !(ovr = wsock_evt.prepare ()))
{
debug_printf ("Fallback to winsock 1 sendto call");
if ((res = ::sendto (get_socket (), (const char *) ptr, len, flags,
(sockaddr *) &sin, tolen)) == SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
}
else
{
WSABUF wsabuf = { len, (char *) ptr };
DWORD ret = 0;
if (WSASendTo (get_socket (), &wsabuf, 1, &ret, (DWORD)flags,
(sockaddr *) &sin, tolen, ovr, NULL) != SOCKET_ERROR)
res = ret;
else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
{
set_winsock_errno ();
res = -1;
}
else if ((res = wsock_evt.wait (get_socket (), (DWORD *)&flags)) == -1)
set_winsock_errno ();
}
return res;
}
int
fhandler_socket::sendmsg (const struct msghdr *msg, int flags)
{
size_t tot = 0;
char *buf, *p;
struct iovec *iov = msg->msg_iov;
if (get_addr_family () == AF_LOCAL)
{
/* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start
the special handling for descriptor passing. Otherwise just
transmit an empty string to tell the receiver that no
descriptor passing is done. */
/*TODO*/
}
for(int i = 0; i < msg->msg_iovlen; ++i)
tot += iov[i].iov_len;
buf = (char *) alloca (tot);
if (tot != 0 && buf == NULL)
{
set_errno (ENOMEM);
return -1;
}
p = buf;
for (int i = 0; i < msg->msg_iovlen; ++i)
{
memcpy (p, iov[i].iov_base, iov[i].iov_len);
p += iov[i].iov_len;
}
return sendto (buf, tot, flags, (struct sockaddr *) msg->msg_name,
msg->msg_namelen);
}
int
fhandler_socket::shutdown (int how)
{
int res = ::shutdown (get_socket (), how);
if (res)
set_winsock_errno ();
else
switch (how)
{
case SHUT_RD:
set_shutdown_read ();
break;
case SHUT_WR:
set_shutdown_write ();
break;
case SHUT_RDWR:
set_shutdown_read ();
set_shutdown_write ();
break;
}
return res;
}
int int
fhandler_socket::close () fhandler_socket::close ()
{ {
int res = 0; int res = 0;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
/* HACK to allow a graceful shutdown even if shutdown() hasn't been /* HACK to allow a graceful shutdown even if shutdown() hasn't been
@ -381,7 +905,6 @@ fhandler_socket::close ()
#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT) #define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
/* Cygwin internal */
int int
fhandler_socket::ioctl (unsigned int cmd, void *p) fhandler_socket::ioctl (unsigned int cmd, void *p)
{ {
@ -389,6 +912,7 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
int res; int res;
struct ifconf ifc, *ifcp; struct ifconf ifc, *ifcp;
struct ifreq *ifr, *ifrp; struct ifreq *ifr, *ifrp;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
switch (cmd) switch (cmd)

View File

@ -33,7 +33,6 @@ details. */
#include "pinfo.h" #include "pinfo.h"
#include "registry.h" #include "registry.h"
#include "wsock_event.h" #include "wsock_event.h"
#include <sys/uio.h>
extern "C" { extern "C" {
int h_errno; int h_errno;
@ -558,104 +557,20 @@ done:
return res; return res;
} }
/* cygwin internal: map sockaddr into internet domain address */
static int get_inet_addr (const struct sockaddr *in, int inlen,
struct sockaddr_in *out, int *outlen, int* secret = 0)
{
int secret_buf [4];
int* secret_ptr = (secret ? : secret_buf);
if (in->sa_family == AF_INET)
{
*out = * (sockaddr_in *)in;
*outlen = inlen;
return 1;
}
else if (in->sa_family == AF_LOCAL)
{
int fd = _open (in->sa_data, O_RDONLY);
if (fd == -1)
return 0;
int ret = 0;
char buf[128];
memset (buf, 0, sizeof buf);
if (read (fd, buf, sizeof buf) != -1)
{
sockaddr_in sin;
sin.sin_family = AF_INET;
sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",
&sin.sin_port,
secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3);
sin.sin_port = htons (sin.sin_port);
sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
*out = sin;
*outlen = sizeof sin;
ret = 1;
}
_close (fd);
return ret;
}
else
{
set_errno (EAFNOSUPPORT);
return 0;
}
}
/* exported as sendto: standards? */ /* exported as sendto: standards? */
extern "C" int extern "C" int
cygwin_sendto (int fd, cygwin_sendto (int fd, const void *buf, int len, unsigned int flags,
const void *buf, const struct sockaddr *to, int tolen)
int len,
unsigned int flags,
const struct sockaddr *to,
int tolen)
{ {
int res; int res;
wsock_event wsock_evt; fhandler_socket *fh = get (fd);
LPWSAOVERLAPPED ovr;
fhandler_socket *h = get (fd);
if ((len && __check_invalid_read_ptr_errno (buf, (unsigned) len)) if ((len && __check_invalid_read_ptr_errno (buf, (unsigned) len))
|| __check_null_invalid_struct_errno (to, tolen) || __check_null_invalid_struct_errno (to, tolen)
|| !h) || !fh)
res = -1; res = -1;
else else
{ res = fh->sendto (buf, len, flags, to, tolen);
sockaddr_in sin;
sigframe thisframe (mainthread);
if (get_inet_addr (to, tolen, &sin, &tolen) == 0)
return -1;
if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ()))
{
debug_printf ("Fallback to winsock 1 sendto call");
if ((res = sendto (h->get_socket (), (const char *) buf, len, flags,
(sockaddr *) &sin, tolen)) == SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
}
else
{
WSABUF wsabuf = { len, (char *) buf };
DWORD ret = 0;
if (WSASendTo (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags,
(sockaddr *) &sin, tolen, ovr, NULL) != SOCKET_ERROR)
res = ret;
else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
{
set_winsock_errno ();
res = -1;
}
else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1)
set_winsock_errno ();
}
}
syscall_printf ("%d = sendto (%d, %x, %x, %x)", res, fd, buf, len, flags); syscall_printf ("%d = sendto (%d, %x, %x, %x)", res, fd, buf, len, flags);
@ -664,53 +579,19 @@ cygwin_sendto (int fd,
/* exported as recvfrom: standards? */ /* exported as recvfrom: standards? */
extern "C" int extern "C" int
cygwin_recvfrom (int fd, cygwin_recvfrom (int fd, char *buf, int len, int flags, struct sockaddr *from,
char *buf, int *fromlen)
int len,
int flags,
struct sockaddr *from,
int *fromlen)
{ {
int res; int res;
wsock_event wsock_evt; fhandler_socket *fh = get (fd);
LPWSAOVERLAPPED ovr;
fhandler_socket *h = get (fd);
if (__check_null_invalid_struct_errno (buf, (unsigned) len) if (__check_null_invalid_struct_errno (buf, (unsigned) len)
|| check_null_invalid_struct_errno (fromlen) || check_null_invalid_struct_errno (fromlen)
|| (from && __check_null_invalid_struct_errno (from, (unsigned) *fromlen)) || (from && __check_null_invalid_struct_errno (from, (unsigned) *fromlen))
|| !h) || !fh)
res = -1; res = -1;
else else
{ res = fh->recvfrom (buf, len, flags, from, fromlen);
sigframe thisframe (mainthread);
if (h->is_nonblocking () ||!(ovr = wsock_evt.prepare ()))
{
debug_printf ("Fallback to winsock 1 recvfrom call");
if ((res = recvfrom (h->get_socket (), buf, len, flags, from, fromlen))
== SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
}
else
{
WSABUF wsabuf = { len, (char *) buf };
DWORD ret = 0;
if (WSARecvFrom (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags,
from, fromlen, ovr, NULL) != SOCKET_ERROR)
res = ret;
else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
{
set_winsock_errno ();
res = -1;
}
else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1)
set_winsock_errno ();
}
}
syscall_printf ("%d = recvfrom (%d, %x, %x, %x)", res, fd, buf, len, flags); syscall_printf ("%d = recvfrom (%d, %x, %x, %x)", res, fd, buf, len, flags);
@ -719,17 +600,14 @@ cygwin_recvfrom (int fd,
/* exported as setsockopt: standards? */ /* exported as setsockopt: standards? */
extern "C" int extern "C" int
cygwin_setsockopt (int fd, cygwin_setsockopt (int fd, int level, int optname, const void *optval,
int level, int optlen)
int optname,
const void *optval,
int optlen)
{ {
fhandler_socket *h = get (fd); fhandler_socket *fh = get (fd);
int res = -1; int res = -1;
const char *name = "error"; const char *name = "error";
if ((!optval || !__check_invalid_read_ptr_errno (optval, optlen)) && h) if ((!optval || !__check_invalid_read_ptr_errno (optval, optlen)) && fh)
{ {
/* For the following debug_printf */ /* For the following debug_printf */
switch (optname) switch (optname)
@ -766,8 +644,8 @@ cygwin_setsockopt (int fd,
break; break;
} }
res = setsockopt (h->get_socket (), level, optname, res = setsockopt (fh->get_socket (), level, optname,
(const char *) optval, optlen); (const char *) optval, optlen);
if (optlen == 4) if (optlen == 4)
syscall_printf ("setsockopt optval=%x", *(long *) optval); syscall_printf ("setsockopt optval=%x", *(long *) optval);
@ -783,18 +661,15 @@ cygwin_setsockopt (int fd,
/* exported as getsockopt: standards? */ /* exported as getsockopt: standards? */
extern "C" int extern "C" int
cygwin_getsockopt (int fd, cygwin_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
int level,
int optname,
void *optval,
int *optlen)
{ {
fhandler_socket *h = get (fd); fhandler_socket *fh = get (fd);
int res = -1; int res = -1;
const char *name = "error"; const char *name = "error";
if (!check_null_invalid_struct_errno (optlen) if (!check_null_invalid_struct_errno (optlen)
&& (!optval || !__check_null_invalid_struct_errno (optval, (unsigned) *optlen)) && (!optval
&& h) || !__check_null_invalid_struct_errno (optval, (unsigned) *optlen))
&& fh)
{ {
/* For the following debug_printf */ /* For the following debug_printf */
switch (optname) switch (optname)
@ -831,8 +706,8 @@ cygwin_getsockopt (int fd,
break; break;
} }
res = getsockopt (h->get_socket (), level, optname, res = getsockopt (fh->get_socket (), level, optname, (char *) optval,
(char *) optval, (int *) optlen); (int *) optlen);
if (optname == SO_ERROR) if (optname == SO_ERROR)
{ {
@ -851,78 +726,21 @@ cygwin_getsockopt (int fd,
/* exported as connect: standards? */ /* exported as connect: standards? */
extern "C" int extern "C" int
cygwin_connect (int fd, cygwin_connect (int fd, const struct sockaddr *name, int namelen)
const struct sockaddr *name,
int namelen)
{ {
int res; int res;
BOOL secret_check_failed = FALSE; fhandler_socket *fh = get (fd);
BOOL in_progress = FALSE;
fhandler_socket *sock = get (fd);
sockaddr_in sin;
int secret [4];
sigframe thisframe (mainthread);
if (__check_invalid_read_ptr_errno (name, namelen)) if (__check_invalid_read_ptr_errno (name, namelen))
return -1; return -1;
if (get_inet_addr (name, namelen, &sin, &namelen, secret) == 0) if (!fh)
return -1;
if (!sock)
res = -1; res = -1;
else else
{ res = fh->connect (name, namelen);
res = connect (sock->get_socket (), (sockaddr *) &sin, namelen);
if (res)
{
/* Special handling for connect to return the correct error code
when called on a non-blocking socket. */
if (sock->is_nonblocking ())
{
DWORD err = WSAGetLastError ();
if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
{
WSASetLastError (WSAEINPROGRESS);
in_progress = TRUE;
}
else if (err == WSAEINVAL)
WSASetLastError (WSAEISCONN);
}
set_winsock_errno ();
}
if (sock->get_addr_family () == AF_LOCAL &&
sock->get_socket_type () == SOCK_STREAM)
{
if (!res || in_progress)
{
if (!sock->create_secret_event (secret))
{
secret_check_failed = TRUE;
}
else if (in_progress)
sock->signal_secret_event ();
}
if (!secret_check_failed && !res) syscall_printf ("%d = connect (%d, %x, %x)", res, fd, name, namelen);
{
if (!sock->check_peer_secret_event (&sin, secret))
{
debug_printf ( "accept from unauthorized server" );
secret_check_failed = TRUE;
}
}
if (secret_check_failed)
{
sock->close_secret_event ();
if (res)
closesocket (res);
set_errno (ECONNREFUSED);
res = -1;
}
}
}
return res; return res;
} }
@ -1179,86 +997,11 @@ cygwin_accept (int fd, struct sockaddr *peer, int *len)
return -1; return -1;
int res = -1; int res = -1;
BOOL secret_check_failed = FALSE;
BOOL in_progress = FALSE;
sigframe thisframe (mainthread);
fhandler_socket *sock = get (fd); fhandler_socket *fh = get (fd);
if (sock) if (fh)
{ res = fh->accept (peer, len);
/* Allows NULL peer and len parameters. */
struct sockaddr_in peer_dummy;
int len_dummy;
if (!peer)
peer = (struct sockaddr *) &peer_dummy;
if (!len)
{
len_dummy = sizeof (struct sockaddr_in);
len = &len_dummy;
}
/* accept on NT fails if len < sizeof (sockaddr_in)
* some programs set len to
* sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain
*/
if (len && ((unsigned) *len < sizeof (struct sockaddr_in)))
*len = sizeof (struct sockaddr_in);
res = accept (sock->get_socket (), peer, len); // can't use a blocking call inside a lock
if ((SOCKET) res == (SOCKET) INVALID_SOCKET &&
WSAGetLastError () == WSAEWOULDBLOCK)
in_progress = TRUE;
if (sock->get_addr_family () == AF_LOCAL &&
sock->get_socket_type () == SOCK_STREAM)
{
if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress)
{
if (!sock->create_secret_event ())
secret_check_failed = TRUE;
else if (in_progress)
sock->signal_secret_event ();
}
if (!secret_check_failed &&
(SOCKET) res != (SOCKET) INVALID_SOCKET)
{
if (!sock->check_peer_secret_event ((struct sockaddr_in*) peer))
{
debug_printf ("connect from unauthorized client");
secret_check_failed = TRUE;
}
}
if (secret_check_failed)
{
sock->close_secret_event ();
if ((SOCKET) res != (SOCKET) INVALID_SOCKET)
closesocket (res);
set_errno (ECONNABORTED);
res = -1;
goto done;
}
}
cygheap_fdnew res_fd;
if (res_fd < 0)
/* FIXME: what is correct errno? */;
else if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
set_winsock_errno ();
else
{
fhandler_socket* res_fh = fdsock (res_fd, sock->get_name (), res);
if (sock->get_addr_family () == AF_LOCAL)
res_fh->set_sun_path (sock->get_sun_path ());
res_fh->set_addr_family (sock->get_addr_family ());
res_fh->set_socket_type (sock->get_socket_type ());
res = res_fd;
}
}
done:
syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len); syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len);
return res; return res;
} }
@ -1272,83 +1015,10 @@ cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen)
int res = -1; int res = -1;
fhandler_socket *sock = get (fd); fhandler_socket *fh = get (fd);
if (sock) if (fh)
{ res = fh->bind (my_addr, addrlen);
if (my_addr->sa_family == AF_LOCAL)
{
#define un_addr ((struct sockaddr_un *) my_addr)
struct sockaddr_in sin;
int len = sizeof sin;
int fd;
if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN)
{
set_errno (ENAMETOOLONG);
goto out;
}
sin.sin_family = AF_INET;
sin.sin_port = 0;
sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
if (bind (sock->get_socket (), (sockaddr *) &sin, len))
{
syscall_printf ("AF_LOCAL: bind failed %d", get_errno ());
set_winsock_errno ();
goto out;
}
if (getsockname (sock->get_socket (), (sockaddr *) &sin, &len))
{
syscall_printf ("AF_LOCAL: getsockname failed %d", get_errno ());
set_winsock_errno ();
goto out;
}
sin.sin_port = ntohs (sin.sin_port);
debug_printf ("AF_LOCAL: socket bound to port %u", sin.sin_port);
/* bind must fail if file system socket object already exists
so _open () is called with O_EXCL flag. */
fd = _open (un_addr->sun_path,
O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
0);
if (fd < 0)
{
if (get_errno () == EEXIST)
set_errno (EADDRINUSE);
goto out;
}
sock->set_connect_secret ();
char buf[sizeof (SOCKET_COOKIE) + 80];
__small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);
sock->get_connect_secret (strchr (buf, '\0'));
len = strlen (buf) + 1;
/* Note that the terminating nul is written. */
if (_write (fd, buf, len) != len)
{
save_errno here;
_close (fd);
_unlink (un_addr->sun_path);
}
else
{
_close (fd);
chmod (un_addr->sun_path,
(S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask);
sock->set_sun_path (un_addr->sun_path);
res = 0;
}
#undef un_addr
}
else if (bind (sock->get_socket (), my_addr, addrlen))
set_winsock_errno ();
else
res = 0;
}
out:
syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen); syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen);
return res; return res;
} }
@ -1363,36 +1033,10 @@ cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen)
int res = -1; int res = -1;
fhandler_socket *sock = get (fd); fhandler_socket *fh = get (fd);
if (sock) if (fh)
{ res = fh->getsockname (addr, namelen);
if (sock->get_addr_family () == AF_LOCAL)
{
struct sockaddr_un *sun = (struct sockaddr_un *) addr;
memset (sun, 0, *namelen);
sun->sun_family = AF_LOCAL;
if (!sock->get_sun_path ())
sun->sun_path[0] = '\0';
else
/* According to SUSv2 "If the actual length of the address is
greater than the length of the supplied sockaddr structure, the
stored address will be truncated." We play it save here so
that the path always has a trailing 0 even if it's truncated. */
strncpy (sun->sun_path, sock->get_sun_path (),
*namelen - sizeof *sun + sizeof sun->sun_path - 1);
*namelen = sizeof *sun - sizeof sun->sun_path
+ strlen (sun->sun_path) + 1;
res = 0;
}
else
{
res = getsockname (sock->get_socket (), addr, namelen);
if (res)
set_winsock_errno ();
}
}
syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen); syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen);
return res; return res;
} }
@ -1403,14 +1047,10 @@ cygwin_listen (int fd, int backlog)
{ {
int res = -1; int res = -1;
fhandler_socket *fh = get (fd);
if (fh)
res = fh->listen (backlog);
fhandler_socket *sock = get (fd);
if (sock)
{
res = listen (sock->get_socket (), backlog);
if (res)
set_winsock_errno ();
}
syscall_printf ("%d = listen (%d, %d)", res, fd, backlog); syscall_printf ("%d = listen (%d, %d)", res, fd, backlog);
return res; return res;
} }
@ -1422,27 +1062,10 @@ cygwin_shutdown (int fd, int how)
int res = -1; int res = -1;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
fhandler_socket *sock = get (fd); fhandler_socket *fh = get (fd);
if (sock) if (fh)
{ res = fh->shutdown (how);
res = shutdown (sock->get_socket (), how);
if (res)
set_winsock_errno ();
else
switch (how)
{
case SHUT_RD:
sock->set_shutdown_read ();
break;
case SHUT_WR:
sock->set_shutdown_write ();
break;
case SHUT_RDWR:
sock->set_shutdown_read ();
sock->set_shutdown_write ();
break;
}
}
syscall_printf ("%d = shutdown (%d, %d)", res, fd, how); syscall_printf ("%d = shutdown (%d, %d)", res, fd, how);
return res; return res;
} }
@ -1498,23 +1121,18 @@ cygwin_herror (const char *s)
extern "C" int extern "C" int
cygwin_getpeername (int fd, struct sockaddr *name, int *len) cygwin_getpeername (int fd, struct sockaddr *name, int *len)
{ {
int res; int res = -1;
if (check_null_invalid_struct_errno (len) if (check_null_invalid_struct_errno (len)
|| __check_null_invalid_struct_errno (name, (unsigned) *len)) || __check_null_invalid_struct_errno (name, (unsigned) *len))
return -1; return -1;
fhandler_socket *h = get (fd); fhandler_socket *fh = get (fd);
if (fh)
res = fh->getpeername (name, len);
if (!h) syscall_printf ("%d = getpeername %d", res, fh->get_socket ());
res = -1;
else
{
res = getpeername (h->get_socket (), name, len);
if (res)
set_winsock_errno ();
}
debug_printf ("%d = getpeername %d", res, h->get_socket ());
return res; return res;
} }
@ -2476,64 +2094,32 @@ endhostent (void)
/* exported as recvmsg: standards? */ /* exported as recvmsg: standards? */
extern "C" int extern "C" int
cygwin_recvmsg(int s, struct msghdr *msg, int flags) cygwin_recvmsg (int s, struct msghdr *msg, int flags)
{ {
int ret, nb; if (check_null_invalid_struct_errno (msg))
size_t tot = 0; return -1;
int i;
char *buf, *p;
struct iovec *iov = msg->msg_iov;
for(i = 0; i < msg->msg_iovlen; ++i) fhandler_socket *fh = get (s);
tot += iov[i].iov_len; if (!fh)
buf = (char *) malloc(tot); {
if (tot != 0 && buf == NULL) set_errno (EINVAL);
{ return -1;
errno = ENOMEM; }
return -1; return fh->recvmsg (msg, flags);
}
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);
memcpy (iov->iov_base, p, cnt);
p += cnt;
nb -= cnt;
++iov;
}
free(buf);
return ret;
} }
/* exported as sendmsg: standards? */ /* exported as sendmsg: standards? */
extern "C" int extern "C" int
cygwin_sendmsg(int s, const struct msghdr *msg, int flags) cygwin_sendmsg (int s, const struct msghdr *msg, int flags)
{ {
int ret; if (__check_invalid_read_ptr_errno (msg, sizeof msg))
size_t tot = 0; return -1;
int i;
char *buf, *p;
struct iovec *iov = msg->msg_iov;
for(i = 0; i < msg->msg_iovlen; ++i) fhandler_socket *fh = get (s);
tot += iov[i].iov_len; if (!fh)
buf = (char *) malloc(tot);
if (tot != 0 && buf == NULL)
{ {
errno = ENOMEM; set_errno (EINVAL);
return -1; return -1;
} }
p = buf; return fh->sendmsg (msg, flags);
for (i = 0; i < msg->msg_iovlen; ++i)
{
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;
} }