From 7f7532fafb0e9787bc9c789f14e9344b8da16244 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 23 Feb 2018 20:59:21 +0100 Subject: [PATCH] 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 --- winsup/cygwin/Makefile.in | 1 + winsup/cygwin/devices.cc | 3 + winsup/cygwin/devices.h | 3 + winsup/cygwin/devices.in | 3 + winsup/cygwin/dtable.cc | 3 + winsup/cygwin/fhandler.h | 102 +++- winsup/cygwin/fhandler_socket_inet.cc | 8 +- winsup/cygwin/fhandler_socket_unix.cc | 671 ++++++++++++++++++++++++++ winsup/cygwin/include/cygwin/socket.h | 6 + winsup/cygwin/net.cc | 6 +- winsup/cygwin/select.cc | 45 ++ 11 files changed, 832 insertions(+), 19 deletions(-) create mode 100644 winsup/cygwin/fhandler_socket_unix.cc 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: @@ -639,16 +641,6 @@ class fhandler_socket_wsock: public fhandler_socket SOCKET get_socket () { return (SOCKET) get_handle(); } #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 (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 +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include +#include "cygwin/version.h" +#include "perprocess.h" +#include "shared_info.h" +#include "sigproc.h" +#include "wininfo.h" +#include +#include +#include +#include +#include "cygtls.h" +#include +#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) {