Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2018-02-23 22:59:21 +0300
committerCorinna Vinschen <corinna@vinschen.de>2018-02-23 23:00:43 +0300
commit7f7532fafb0e9787bc9c789f14e9344b8da16244 (patch)
treec05b59ace7c6f4c0895269aea45002e3375da178
parent5acadbe8afda9ccb97829b9a8f5813464519fcae (diff)
Cygwin: Create empty fhandler_socket_unix
* Make distinct from AF_LOCAL for testing purposes. This will have to be reverted as soon as fhandler_socket_unix goes life. * Move saw_reuseaddr flag back to fhandler_socket status Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
-rw-r--r--winsup/cygwin/Makefile.in1
-rw-r--r--winsup/cygwin/devices.cc3
-rw-r--r--winsup/cygwin/devices.h3
-rw-r--r--winsup/cygwin/devices.in3
-rw-r--r--winsup/cygwin/dtable.cc3
-rw-r--r--winsup/cygwin/fhandler.h102
-rw-r--r--winsup/cygwin/fhandler_socket_inet.cc8
-rw-r--r--winsup/cygwin/fhandler_socket_unix.cc671
-rw-r--r--winsup/cygwin/include/cygwin/socket.h6
-rw-r--r--winsup/cygwin/net.cc6
-rw-r--r--winsup/cygwin/select.cc45
11 files changed, 832 insertions, 19 deletions
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 75ec29707..ac22cfba8 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -298,6 +298,7 @@ DLL_OFILES:= \
fhandler_socket.o \
fhandler_socket_inet.o \
fhandler_socket_local.o \
+ fhandler_socket_unix.o \
fhandler_tape.o \
fhandler_termios.o \
fhandler_tty.o \
diff --git a/winsup/cygwin/devices.cc b/winsup/cygwin/devices.cc
index 8ba199dd9..963069bd7 100644
--- a/winsup/cygwin/devices.cc
+++ b/winsup/cygwin/devices.cc
@@ -126,6 +126,9 @@ const _device dev_socket_storage =
const _device dev_af_inet_storage =
{"", {FH_INET}, "", exists_internal};
+const _device dev_af_unix_storage =
+ {"", {FH_UNIX}, "", exists_internal};
+
const _device dev_af_local_storage =
{"", {FH_LOCAL}, "", exists_internal};
diff --git a/winsup/cygwin/devices.h b/winsup/cygwin/devices.h
index 87e033040..3b6730002 100644
--- a/winsup/cygwin/devices.h
+++ b/winsup/cygwin/devices.h
@@ -244,6 +244,7 @@ enum fh_devices
DEV_SOCK_MAJOR = 30,
FH_SOCKET = FHDEV (DEV_SOCK_MAJOR, 0),
FH_INET = FHDEV (DEV_SOCK_MAJOR, 36),
+ FH_UNIX = FHDEV (DEV_SOCK_MAJOR, 42),
FH_LOCAL = FHDEV (DEV_SOCK_MAJOR, 120),
FH_NADA = FHDEV (0, 0),
@@ -397,6 +398,8 @@ extern const _device dev_af_inet_storage;
#define af_inet_dev ((device *) &dev_af_inet_storage)
extern const _device dev_af_local_storage;
#define af_local_dev ((device *) &dev_af_local_storage)
+extern const _device dev_af_unix_storage;
+#define af_unix_dev ((device *) &dev_af_unix_storage)
extern const _device dev_piper_storage;
#define piper_dev ((device *) &dev_piper_storage)
diff --git a/winsup/cygwin/devices.in b/winsup/cygwin/devices.in
index c0108b817..ed99b440c 100644
--- a/winsup/cygwin/devices.in
+++ b/winsup/cygwin/devices.in
@@ -122,6 +122,9 @@ const _device dev_socket_storage =
const _device dev_af_inet_storage =
{"", {FH_INET}, "", exists_internal};
+const _device dev_af_unix_storage =
+ {"", {FH_UNIX}, "", exists_internal};
+
const _device dev_af_local_storage =
{"", {FH_LOCAL}, "", exists_internal};
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index ae0315cd3..5a263f5a1 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -520,6 +520,9 @@ fh_alloc (path_conv& pc)
case FH_LOCAL:
fh = cnew (fhandler_socket_local);
break;
+ case FH_UNIX:
+ fh = cnew (fhandler_socket_unix);
+ break;
case FH_FS:
fh = cnew (fhandler_disk_file);
break;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 3816110a0..863cd312f 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -521,17 +521,19 @@ class fhandler_socket: public fhandler_base
unsigned async_io : 1; /* async I/O */
unsigned saw_shutdown_read : 1; /* Socket saw a SHUT_RD */
unsigned saw_shutdown_write : 1; /* Socket saw a SHUT_WR */
+ unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */
unsigned connect_state : 3;
public:
status_flags () :
async_io (0), saw_shutdown_read (0), saw_shutdown_write (0),
- connect_state (unconnected)
+ saw_reuseaddr (0), connect_state (unconnected)
{}
} status;
public:
IMPLEMENT_STATUS_FLAG (bool, async_io)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write)
+ IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr)
IMPLEMENT_STATUS_FLAG (conn_state, connect_state)
public:
@@ -640,16 +642,6 @@ class fhandler_socket_wsock: public fhandler_socket
#endif
protected:
- struct status_flags
- {
- unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */
- public:
- status_flags () : saw_reuseaddr (0) {}
- } status;
- public:
- IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr)
-
- protected:
virtual ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg) = 0;
ssize_t send_internal (struct _WSAMSG *wsamsg, int flags);
@@ -819,6 +811,94 @@ class fhandler_socket_local: public fhandler_socket_wsock
}
};
+class fhandler_socket_unix : public fhandler_socket
+{
+ protected:
+ char *sun_path;
+ char *peer_sun_path;
+ void set_sun_path (const char *path);
+ char *get_sun_path () {return sun_path;}
+ void set_peer_sun_path (const char *path);
+ char *get_peer_sun_path () {return peer_sun_path;}
+ void set_cred ();
+
+ protected:
+ pid_t sec_pid;
+ uid_t sec_uid;
+ gid_t sec_gid;
+ pid_t sec_peer_pid;
+ uid_t sec_peer_uid;
+ gid_t sec_peer_gid;
+
+ public:
+ fhandler_socket_unix ();
+ ~fhandler_socket_unix ();
+
+ int dup (fhandler_base *child, int);
+
+ int socket (int af, int type, int protocol, int flags);
+ int socketpair (int af, int type, int protocol, int flags,
+ fhandler_socket_unix *fh_out);
+ int bind (const struct sockaddr *name, int namelen);
+ int listen (int backlog);
+ int accept4 (struct sockaddr *peer, int *len, int flags);
+ int connect (const struct sockaddr *name, int namelen);
+ int getsockname (struct sockaddr *name, int *namelen);
+ int getpeername (struct sockaddr *name, int *namelen);
+ int shutdown (int how);
+ int close ();
+ int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid);
+ ssize_t recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen);
+ ssize_t recvmsg (struct msghdr *msg, int flags);
+ void __reg3 read (void *ptr, size_t& len);
+ ssize_t __stdcall readv (const struct iovec *, int iovcnt,
+ ssize_t tot = -1);
+
+ ssize_t sendto (const void *ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen);
+ ssize_t sendmsg (const struct msghdr *msg, int flags);
+ ssize_t __stdcall write (const void *ptr, size_t len);
+ ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ int setsockopt (int level, int optname, const void *optval,
+ __socklen_t optlen);
+ int getsockopt (int level, int optname, const void *optval,
+ __socklen_t *optlen);
+
+ virtual int ioctl (unsigned int cmd, void *);
+ virtual int fcntl (int cmd, intptr_t);
+
+ int __reg2 fstat (struct stat *buf);
+ int __reg2 fstatvfs (struct statvfs *buf);
+ int __reg1 fchmod (mode_t newmode);
+ int __reg2 fchown (uid_t newuid, gid_t newgid);
+ int __reg3 facl (int, int, struct acl *);
+ int __reg2 link (const char *);
+
+ /* select.cc */
+ select_record *select_read (select_stuff *);
+ select_record *select_write (select_stuff *);
+ select_record *select_except (select_stuff *);
+
+ /* from here on: CLONING */
+ fhandler_socket_unix (void *) {}
+
+ void copyto (fhandler_base *x)
+ {
+ x->pc.free_strings ();
+ *reinterpret_cast<fhandler_socket_unix *> (x) = *this;
+ x->reset (this);
+ }
+
+ fhandler_socket_unix *clone (cygheap_types malloc_type = HEAP_FHANDLER)
+ {
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_socket_unix));
+ fhandler_socket_unix *fh = new (ptr) fhandler_socket_unix (ptr);
+ copyto (fh);
+ return fh;
+ }
+};
+
class fhandler_base_overlapped: public fhandler_base
{
static HANDLE asio_done;
diff --git a/winsup/cygwin/fhandler_socket_inet.cc b/winsup/cygwin/fhandler_socket_inet.cc
index 0668c1063..aa3ead7ae 100644
--- a/winsup/cygwin/fhandler_socket_inet.cc
+++ b/winsup/cygwin/fhandler_socket_inet.cc
@@ -211,8 +211,7 @@ fhandler_socket_wsock::fhandler_socket_wsock () :
wsock_events (NULL),
wsock_mtx (NULL),
wsock_evt (NULL),
- prot_info_ptr (NULL),
- status ()
+ prot_info_ptr (NULL)
{
need_fork_fixup (true);
}
@@ -1429,8 +1428,6 @@ fhandler_socket_inet::sendto (const void *in_ptr, size_t len, int flags,
ssize_t
fhandler_socket_inet::sendmsg (const struct msghdr *msg, int flags)
{
- /* TODO: Descriptor passing on AF_LOCAL sockets. */
-
struct sockaddr_storage sst;
int len = 0;
@@ -1449,8 +1446,7 @@ fhandler_socket_inet::sendmsg (const struct msghdr *msg, int flags)
}
/* Disappointing but true: Even if WSASendMsg is supported, it's only
supported for datagram and raw sockets. */
- DWORD controllen = (DWORD) (get_socket_type () == SOCK_STREAM
- || get_addr_family () == AF_LOCAL
+ DWORD controllen = (DWORD) ((get_socket_type () == SOCK_STREAM)
? 0 : msg->msg_controllen);
WSAMSG wsamsg = { msg->msg_name ? (struct sockaddr *) &sst : NULL, len,
wsabuf, (DWORD) msg->msg_iovlen,
diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc
new file mode 100644
index 000000000..21d2ad62d
--- /dev/null
+++ b/winsup/cygwin/fhandler_socket_unix.cc
@@ -0,0 +1,671 @@
+/* fhandler_socket_unix.cc.
+
+ See fhandler.h for a description of the fhandler classes.
+
+ 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 "winsup.h"
+#include <ntsecapi.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <asm/byteorder.h>
+#include "cygwin/version.h"
+#include "perprocess.h"
+#include "shared_info.h"
+#include "sigproc.h"
+#include "wininfo.h"
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/statvfs.h>
+#include <cygwin/acl.h>
+#include "cygtls.h"
+#include <sys/un.h>
+#include "ntdll.h"
+#include "miscfuncs.h"
+#include "tls_pbuf.h"
+
+extern "C" {
+ int sscanf (const char *, const char *, ...);
+} /* End of "C" section */
+
+#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
+#define EVENT_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE)
+
+#define LOCK_EVENTS \
+ if (wsock_mtx && \
+ WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \
+ {
+
+#define UNLOCK_EVENTS \
+ ReleaseMutex (wsock_mtx); \
+ }
+
+static inline mode_t
+adjust_socket_file_mode (mode_t mode)
+{
+ /* Kludge: Don't allow to remove read bit on socket files for
+ user/group/other, if the accompanying write bit is set. It would
+ be nice to have exact permissions on a socket file, but it's
+ necessary that somebody able to access the socket can always read
+ the contents of the socket file to avoid spurious "permission
+ denied" messages. */
+ return mode | ((mode & (S_IWUSR | S_IWGRP | S_IWOTH)) << 1);
+}
+
+/* cygwin internal: map sockaddr into internet domain address */
+static int __unused
+get_inet_addr_unix (const struct sockaddr *in, int inlen,
+ struct sockaddr_storage *out, int *outlen,
+ int *type = NULL)
+{
+ /* Check for abstract socket. */
+ if (inlen >= (int) sizeof (in->sa_family) + 7
+ && in->sa_data[0] == '\0' && in->sa_data[1] == 'd'
+ && in->sa_data[6] == '\0')
+ {
+ /* TODO */
+ return 0;
+ }
+
+ path_conv pc (in->sa_data, PC_SYM_FOLLOW);
+ if (pc.error)
+ {
+ set_errno (pc.error);
+ return -1;
+ }
+ if (!pc.exists ())
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+ /* Do NOT test for the file being a socket file here. The socket file
+ creation is not an atomic operation, so there is a chance that socket
+ files which are just in the process of being created are recognized
+ as non-socket files. To work around this problem we now create the
+ file with all sharing disabled. If the below NtOpenFile fails
+ with STATUS_SHARING_VIOLATION we know that the file already exists,
+ but the creating process isn't finished yet. So we yield and try
+ again, until we can either open the file successfully, or some error
+ other than STATUS_SHARING_VIOLATION occurs.
+ Since we now don't know if the file is actually a socket file, we
+ perform this check here explicitely. */
+ NTSTATUS status;
+ HANDLE fh;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+
+ pc.get_object_attr (attr, sec_none_nih);
+ do
+ {
+ status = NtOpenFile (&fh, GENERIC_READ | SYNCHRONIZE, &attr, &io,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_NON_DIRECTORY_FILE);
+ if (status == STATUS_SHARING_VIOLATION)
+ {
+ /* While we hope that the sharing violation is only temporary, we
+ also could easily get stuck here, waiting for a file in use by
+ some greedy Win32 application. Therefore we should never wait
+ endlessly without checking for signals and thread cancel event. */
+ pthread_testcancel ();
+ if (cygwait (NULL, cw_nowait, cw_sig_eintr) == WAIT_SIGNALED
+ && !_my_tls.call_signal_handler ())
+ {
+ set_errno (EINTR);
+ return -1;
+ }
+ yield ();
+ }
+ else if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ }
+ while (status == STATUS_SHARING_VIOLATION);
+ /* Now test for the SYSTEM bit. */
+ FILE_BASIC_INFORMATION fbi;
+ status = NtQueryInformationFile (fh, &io, &fbi, sizeof fbi,
+ FileBasicInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ if (!(fbi.FileAttributes & FILE_ATTRIBUTE_SYSTEM))
+ {
+ NtClose (fh);
+ set_errno (EBADF);
+ return -1;
+ }
+ /* Eventually check the content and fetch the required information. */
+ char buf[128];
+ memset (buf, 0, sizeof buf);
+ status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, 128, NULL, NULL);
+ NtClose (fh);
+ if (NT_SUCCESS (status))
+ {
+#if 0 /* TODO */
+ struct sockaddr_in sin;
+ char ctype;
+ sin.sin_family = AF_INET;
+ if (strncmp (buf, SOCKET_COOKIE, strlen (SOCKET_COOKIE)))
+ {
+ set_errno (EBADF);
+ return -1;
+ }
+ sscanf (buf + strlen (SOCKET_COOKIE), "%hu %c", &sin.sin_port, &ctype);
+ sin.sin_port = htons (sin.sin_port);
+ sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ memcpy (out, &sin, sizeof sin);
+ *outlen = sizeof sin;
+ if (type)
+ *type = (ctype == 's' ? SOCK_STREAM :
+ ctype == 'd' ? SOCK_DGRAM
+ : 0);
+#endif
+ return 0;
+ }
+ __seterrno_from_nt_status (status);
+ return -1;
+}
+
+fhandler_socket_unix::fhandler_socket_unix () :
+ sun_path (NULL),
+ peer_sun_path (NULL)
+{
+ set_cred ();
+}
+
+fhandler_socket_unix::~fhandler_socket_unix ()
+{
+ if (sun_path)
+ cfree (sun_path);
+ if (peer_sun_path)
+ cfree (peer_sun_path);
+}
+
+void
+fhandler_socket_unix::set_sun_path (const char *path)
+{
+ sun_path = path ? cstrdup (path) : NULL;
+}
+
+void
+fhandler_socket_unix::set_peer_sun_path (const char *path)
+{
+ peer_sun_path = path ? cstrdup (path) : NULL;
+}
+
+void
+fhandler_socket_unix::set_cred ()
+{
+ sec_pid = getpid ();
+ sec_uid = geteuid32 ();
+ sec_gid = getegid32 ();
+ sec_peer_pid = (pid_t) 0;
+ sec_peer_uid = (uid_t) -1;
+ sec_peer_gid = (gid_t) -1;
+}
+
+int
+fhandler_socket_unix::dup (fhandler_base *child, int flags)
+{
+ fhandler_socket_unix *fhs = (fhandler_socket_unix *) child;
+ fhs->set_sun_path (get_sun_path ());
+ fhs->set_peer_sun_path (get_peer_sun_path ());
+ return fhandler_socket::dup (child, flags);
+}
+
+int
+fhandler_socket_unix::socket (int af, int type, int protocol, int flags)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags,
+ fhandler_socket_unix *fh_out)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::bind (const struct sockaddr *name, int namelen)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::listen (int backlog)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::accept4 (struct sockaddr *peer, int *len, int flags)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::connect (const struct sockaddr *name, int namelen)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::getsockname (struct sockaddr *name, int *namelen)
+{
+ struct sockaddr_un sun;
+
+ sun.sun_family = AF_UNIX;
+ sun.sun_path[0] = '\0';
+ if (get_sun_path ())
+ strncat (sun.sun_path, get_sun_path (), UNIX_PATH_MAX - 1);
+ memcpy (name, &sun, MIN (*namelen, (int) SUN_LEN (&sun) + 1));
+ *namelen = (int) SUN_LEN (&sun) + (get_sun_path () ? 1 : 0);
+ return 0;
+}
+
+int
+fhandler_socket_unix::getpeername (struct sockaddr *name, int *namelen)
+{
+ struct sockaddr_un sun;
+ memset (&sun, 0, sizeof sun);
+ sun.sun_family = AF_UNIX;
+ sun.sun_path[0] = '\0';
+ if (get_peer_sun_path ())
+ strncat (sun.sun_path, get_peer_sun_path (), UNIX_PATH_MAX - 1);
+ memcpy (name, &sun, MIN (*namelen, (int) SUN_LEN (&sun) + 1));
+ *namelen = (int) SUN_LEN (&sun) + (get_peer_sun_path () ? 1 : 0);
+ return 0;
+}
+
+int
+fhandler_socket_unix::shutdown (int how)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::close ()
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid)
+{
+ if (get_socket_type () != SOCK_STREAM)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ if (connect_state () != connected)
+ {
+ set_errno (ENOTCONN);
+ return -1;
+ }
+
+ __try
+ {
+ if (pid)
+ *pid = sec_peer_pid;
+ if (euid)
+ *euid = sec_peer_uid;
+ if (egid)
+ *egid = sec_peer_gid;
+ return 0;
+ }
+ __except (EFAULT) {}
+ __endtry
+ return -1;
+}
+
+ssize_t
+fhandler_socket_unix::recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+ssize_t
+fhandler_socket_unix::recvmsg (struct msghdr *msg, int flags)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+void __reg3
+fhandler_socket_unix::read (void *ptr, size_t& len)
+{
+ set_errno (EAFNOSUPPORT);
+ len = 0;
+}
+
+ssize_t __stdcall
+fhandler_socket_unix::readv (const struct iovec *, int iovcnt, ssize_t tot)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+ssize_t
+fhandler_socket_unix::sendto (const void *in_ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+ssize_t
+fhandler_socket_unix::sendmsg (const struct msghdr *msg, int flags)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+ssize_t __stdcall
+fhandler_socket_unix::write (const void *ptr, size_t len)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+ssize_t __stdcall
+fhandler_socket_unix::writev (const struct iovec *, int iovcnt, ssize_t tot)
+{
+ set_errno (EAFNOSUPPORT);
+ return -1;
+}
+
+int
+fhandler_socket_unix::setsockopt (int level, int optname, const void *optval,
+ socklen_t optlen)
+{
+ /* Preprocessing setsockopt. */
+ switch (level)
+ {
+ case SOL_SOCKET:
+ switch (optname)
+ {
+ case SO_PASSCRED:
+ break;
+
+ case SO_REUSEADDR:
+ saw_reuseaddr (*(int *) optval);
+ break;
+
+ case SO_RCVBUF:
+ rmem (*(int *) optval);
+ break;
+
+ case SO_SNDBUF:
+ wmem (*(int *) optval);
+ break;
+
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ if (optlen < (socklen_t) sizeof (struct timeval))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ if (!timeval_to_ms ((struct timeval *) optval,
+ (optname == SO_RCVTIMEO) ? rcvtimeo ()
+ : sndtimeo ()))
+ {
+ set_errno (EDOM);
+ return -1;
+ }
+ break;
+
+ default:
+ /* AF_UNIX sockets simply ignore all other SOL_SOCKET options. */
+ break;
+ }
+ break;
+
+ default:
+ set_errno (ENOPROTOOPT);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+fhandler_socket_unix::getsockopt (int level, int optname, const void *optval,
+ socklen_t *optlen)
+{
+ /* Preprocessing getsockopt.*/
+ switch (level)
+ {
+ case SOL_SOCKET:
+ switch (optname)
+ {
+ case SO_ERROR:
+ {
+ int *e = (int *) optval;
+ *e = 0;
+ break;
+ }
+
+ case SO_PASSCRED:
+ break;
+
+ case SO_PEERCRED:
+ {
+ struct ucred *cred = (struct ucred *) optval;
+
+ if (*optlen < (socklen_t) sizeof *cred)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ int ret = getpeereid (&cred->pid, &cred->uid, &cred->gid);
+ if (!ret)
+ *optlen = (socklen_t) sizeof *cred;
+ return ret;
+ }
+
+ case SO_REUSEADDR:
+ {
+ unsigned int *reuseaddr = (unsigned int *) optval;
+
+ if (*optlen < (socklen_t) sizeof *reuseaddr)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ *reuseaddr = saw_reuseaddr();
+ *optlen = (socklen_t) sizeof *reuseaddr;
+ break;
+ }
+
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ {
+ struct timeval *time_out = (struct timeval *) optval;
+
+ if (*optlen < (socklen_t) sizeof *time_out)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ DWORD ms = (optname == SO_RCVTIMEO) ? rcvtimeo () : sndtimeo ();
+ if (ms == 0 || ms == INFINITE)
+ {
+ time_out->tv_sec = 0;
+ time_out->tv_usec = 0;
+ }
+ else
+ {
+ time_out->tv_sec = ms / MSPERSEC;
+ time_out->tv_usec = ((ms % MSPERSEC) * USPERSEC) / MSPERSEC;
+ }
+ *optlen = (socklen_t) sizeof *time_out;
+ break;
+ }
+
+ case SO_TYPE:
+ {
+ unsigned int *type = (unsigned int *) optval;
+ *type = get_socket_type ();
+ *optlen = (socklen_t) sizeof *type;
+ break;
+ }
+
+ /* AF_UNIX sockets simply ignore all other SOL_SOCKET options. */
+
+ case SO_LINGER:
+ {
+ struct linger *linger = (struct linger *) optval;
+ memset (linger, 0, sizeof *linger);
+ *optlen = (socklen_t) sizeof *linger;
+ break;
+ }
+
+ default:
+ {
+ unsigned int *val = (unsigned int *) optval;
+ *val = 0;
+ *optlen = (socklen_t) sizeof *val;
+ break;
+ }
+ }
+ break;
+
+ default:
+ set_errno (ENOPROTOOPT);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+fhandler_socket_unix::ioctl (unsigned int cmd, void *p)
+{
+ int ret;
+
+ switch (cmd)
+ {
+ case FIOASYNC:
+#ifdef __x86_64__
+ case _IOW('f', 125, int):
+#endif
+ break;
+ case FIONREAD:
+#ifdef __x86_64__
+ case _IOR('f', 127, int):
+#endif
+ case FIONBIO:
+ case SIOCATMARK:
+ break;
+ default:
+ ret = fhandler_socket::ioctl (cmd, p);
+ break;
+ }
+ return ret;
+}
+
+int
+fhandler_socket_unix::fcntl (int cmd, intptr_t arg)
+{
+ int ret;
+
+ switch (cmd)
+ {
+ case F_SETOWN:
+ break;
+ case F_GETOWN:
+ break;
+ default:
+ ret = fhandler_socket::fcntl (cmd, arg);
+ break;
+ }
+ return ret;
+}
+
+int __reg2
+fhandler_socket_unix::fstat (struct stat *buf)
+{
+ int ret;
+
+ if (!get_sun_path () || get_sun_path ()[0] == '\0')
+ return fhandler_socket::fstat (buf);
+ ret = fhandler_base::fstat_fs (buf);
+ if (!ret)
+ {
+ buf->st_mode = (buf->st_mode & ~S_IFMT) | S_IFSOCK;
+ buf->st_size = 0;
+ }
+ return ret;
+}
+
+int __reg2
+fhandler_socket_unix::fstatvfs (struct statvfs *sfs)
+{
+ if (!get_sun_path () || get_sun_path ()[0] == '\0')
+ return fhandler_socket::fstatvfs (sfs);
+ fhandler_disk_file fh (pc);
+ fh.get_device () = FH_FS;
+ return fh.fstatvfs (sfs);
+}
+
+int
+fhandler_socket_unix::fchmod (mode_t newmode)
+{
+ if (!get_sun_path () || get_sun_path ()[0] == '\0')
+ return fhandler_socket::fchmod (newmode);
+ fhandler_disk_file fh (pc);
+ fh.get_device () = FH_FS;
+ return fh.fchmod (S_IFSOCK | adjust_socket_file_mode (newmode));
+}
+
+int
+fhandler_socket_unix::fchown (uid_t uid, gid_t gid)
+{
+ if (!get_sun_path () || get_sun_path ()[0] == '\0')
+ return fhandler_socket::fchown (uid, gid);
+ fhandler_disk_file fh (pc);
+ return fh.fchown (uid, gid);
+}
+
+int
+fhandler_socket_unix::facl (int cmd, int nentries, aclent_t *aclbufp)
+{
+ if (!get_sun_path () || get_sun_path ()[0] == '\0')
+ return fhandler_socket::facl (cmd, nentries, aclbufp);
+ fhandler_disk_file fh (pc);
+ return fh.facl (cmd, nentries, aclbufp);
+}
+
+int
+fhandler_socket_unix::link (const char *newpath)
+{
+ if (!get_sun_path () || get_sun_path ()[0] == '\0')
+ return fhandler_socket::link (newpath);
+ fhandler_disk_file fh (pc);
+ return fh.link (newpath);
+}
diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h
index b1ab5c28c..15e132738 100644
--- a/winsup/cygwin/include/cygwin/socket.h
+++ b/winsup/cygwin/include/cygwin/socket.h
@@ -138,7 +138,13 @@ struct OLD_msghdr
* Address families.
*/
#define AF_UNSPEC 0 /* unspecified */
+/* FIXME: This is for testing only, while developing the new
+ fhandler_socket_unix class. */
+#ifdef __INSIDE_CYGWIN__
+#define AF_UNIX 31
+#else
#define AF_UNIX 1 /* local to host (pipes, portals) */
+#endif
#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
#define AF_IMPLINK 3 /* arpanet imp addresses */
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index fe6576dc9..89945c5a1 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -516,6 +516,7 @@ cygwin_socket (int af, int type, int protocol)
switch (af)
{
case AF_LOCAL:
+ case AF_UNIX:
if (type != SOCK_STREAM && type != SOCK_DGRAM)
{
set_errno (EINVAL);
@@ -526,7 +527,7 @@ cygwin_socket (int af, int type, int protocol)
set_errno (EPROTONOSUPPORT);
goto done;
}
- dev = af_local_dev;
+ dev = (af == AF_LOCAL) ? af_local_dev : af_unix_dev;
break;
case AF_INET:
case AF_INET6:
@@ -2312,6 +2313,7 @@ socketpair (int af, int type, int protocol, int *sb)
switch (af)
{
case AF_LOCAL:
+ case AF_UNIX:
if (type != SOCK_STREAM && type != SOCK_DGRAM)
{
set_errno (EINVAL);
@@ -2322,7 +2324,7 @@ socketpair (int af, int type, int protocol, int *sb)
set_errno (EPROTONOSUPPORT);
goto done;
}
- dev = af_local_dev;
+ dev = (af == AF_LOCAL) ? af_local_dev : af_unix_dev;
break;
default:
set_errno (EAFNOSUPPORT);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 023bec048..e489fcfca 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1602,6 +1602,51 @@ fhandler_socket_wsock::select_except (select_stuff *ss)
return s;
}
+select_record *
+fhandler_socket_unix::select_read (select_stuff *ss)
+{
+ select_record *s = ss->start.next;
+ if (!s->startup)
+ {
+ s->startup = no_startup;
+ s->verify = verify_ok;
+ }
+ s->h = get_io_handle_cyg ();
+ s->read_selected = true;
+ s->read_ready = true;
+ return s;
+}
+
+select_record *
+fhandler_socket_unix::select_write (select_stuff *ss)
+{
+ select_record *s = ss->start.next;
+ if (!s->startup)
+ {
+ s->startup = no_startup;
+ s->verify = verify_ok;
+ }
+ s->h = get_handle ();
+ s->write_selected = true;
+ s->write_ready = true;
+ return s;
+}
+
+select_record *
+fhandler_socket_unix::select_except (select_stuff *ss)
+{
+ select_record *s = ss->start.next;
+ if (!s->startup)
+ {
+ s->startup = no_startup;
+ s->verify = verify_ok;
+ }
+ s->h = NULL;
+ s->except_selected = true;
+ s->except_ready = false;
+ return s;
+}
+
static int
peek_windows (select_record *me, bool)
{