Cygwin: AF_UNIX: Redesign various aspects
* Change set_socket_type/get_socket_type to virtual methods * Move various variables into af_unix_shmem_t * Change sun_name_t to match new usage pattern * Move shut_state definition and add a name for the 0 value * Allow marking packet as administrative packet. This allows filtering out info packets exchange between peers and tweak data accordingly. * Rename send_my_name to send_sock_info and send credentials if not called from bind (so the socket was already connected) * Handle SO_PASSCRED in setsockopt/getsockopt * Add input size checking to setsockopt/getsockopt * Use NT functions where appropriate Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
a366a8fc42
commit
4fe086c84f
|
@ -579,8 +579,8 @@ class fhandler_socket: public fhandler_base
|
||||||
|
|
||||||
void set_addr_family (int af) {addr_family = af;}
|
void set_addr_family (int af) {addr_family = af;}
|
||||||
int get_addr_family () {return addr_family;}
|
int get_addr_family () {return addr_family;}
|
||||||
void set_socket_type (int st) { type = st;}
|
virtual void set_socket_type (int st) { type = st;}
|
||||||
int get_socket_type () {return type;}
|
virtual int get_socket_type () {return type;}
|
||||||
|
|
||||||
/* select.cc */
|
/* select.cc */
|
||||||
virtual select_record *select_read (select_stuff *) = 0;
|
virtual select_record *select_read (select_stuff *) = 0;
|
||||||
|
@ -851,6 +851,14 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Internal representation of shutdown states */
|
||||||
|
enum shut_state {
|
||||||
|
_SHUT_NONE = 0,
|
||||||
|
_SHUT_RECV = 1,
|
||||||
|
_SHUT_SEND = 2,
|
||||||
|
_SHUT_MASK = 3
|
||||||
|
};
|
||||||
|
|
||||||
class sun_name_t
|
class sun_name_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -861,19 +869,10 @@ class sun_name_t
|
||||||
/* Allows 108 bytes sun_path plus trailing NUL */
|
/* Allows 108 bytes sun_path plus trailing NUL */
|
||||||
char _nul[sizeof (struct sockaddr_un) + 1];
|
char _nul[sizeof (struct sockaddr_un) + 1];
|
||||||
};
|
};
|
||||||
sun_name_t ();
|
sun_name_t () { set (NULL, 0); }
|
||||||
sun_name_t (const struct sockaddr *name, __socklen_t namelen);
|
sun_name_t (const struct sockaddr *name, __socklen_t namelen)
|
||||||
|
{ set ((const struct sockaddr_un *) name, namelen); }
|
||||||
void *operator new (size_t) __attribute__ ((nothrow))
|
void set (const struct sockaddr_un *name, __socklen_t namelen);
|
||||||
{ return cmalloc_abort (HEAP_FHANDLER, sizeof (sun_name_t)); }
|
|
||||||
void operator delete (void *p) {cfree (p);}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Internal representation of shutdown states */
|
|
||||||
enum shut_state {
|
|
||||||
_SHUT_READ = 1,
|
|
||||||
_SHUT_WRITE = 2,
|
|
||||||
_SHUT_RW = 3
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For each AF_UNIX socket, we need to maintain socket-wide data,
|
/* For each AF_UNIX socket, we need to maintain socket-wide data,
|
||||||
|
@ -893,7 +892,13 @@ class af_unix_shmem_t
|
||||||
LONG _binding_state; /* bind_state */
|
LONG _binding_state; /* bind_state */
|
||||||
LONG _shutdown; /* shut_state */
|
LONG _shutdown; /* shut_state */
|
||||||
LONG _so_error; /* SO_ERROR */
|
LONG _so_error; /* SO_ERROR */
|
||||||
|
LONG _so_passcred; /* SO_PASSCRED */
|
||||||
LONG _reuseaddr; /* dummy */
|
LONG _reuseaddr; /* dummy */
|
||||||
|
int _type; /* socket type */
|
||||||
|
sun_name_t _sun_path;
|
||||||
|
sun_name_t _peer_sun_path;
|
||||||
|
struct ucred _sock_cred; /* filled at listen time */
|
||||||
|
struct ucred _peer_cred; /* filled at connect time */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void bind_lock () { _bind_lock.lock (); }
|
void bind_lock () { _bind_lock.lock (); }
|
||||||
|
@ -917,13 +922,31 @@ class af_unix_shmem_t
|
||||||
{ return (int) InterlockedExchange (&_shutdown, shut); }
|
{ return (int) InterlockedExchange (&_shutdown, shut); }
|
||||||
int shutdown () const { return (int) _shutdown; }
|
int shutdown () const { return (int) _shutdown; }
|
||||||
|
|
||||||
int so_error (int err)
|
int so_error (int err) { return (int) InterlockedExchange (&_so_error, err); }
|
||||||
{ return (int) InterlockedExchange (&_so_error, err); }
|
|
||||||
int so_error () const { return _so_error; }
|
int so_error () const { return _so_error; }
|
||||||
|
|
||||||
|
bool so_passcred (bool pc)
|
||||||
|
{ return (bool) InterlockedExchange (&_so_passcred, pc); }
|
||||||
|
bool so_passcred () const { return _so_passcred; }
|
||||||
|
|
||||||
int reuseaddr (int val)
|
int reuseaddr (int val)
|
||||||
{ return (int) InterlockedExchange (&_reuseaddr, val); }
|
{ return (int) InterlockedExchange (&_reuseaddr, val); }
|
||||||
int reuseaddr () const { return _reuseaddr; }
|
int reuseaddr () const { return _reuseaddr; }
|
||||||
|
|
||||||
|
void set_socket_type (int val) { _type = val; }
|
||||||
|
int get_socket_type () const { return _type; }
|
||||||
|
|
||||||
|
void sun_path (struct sockaddr_un *un, __socklen_t unlen)
|
||||||
|
{ _sun_path.set (un, unlen); }
|
||||||
|
void peer_sun_path (struct sockaddr_un *un, __socklen_t unlen)
|
||||||
|
{ _peer_sun_path.set (un, unlen); }
|
||||||
|
sun_name_t *sun_path () {return &_sun_path;}
|
||||||
|
sun_name_t *peer_sun_path () {return &_peer_sun_path;}
|
||||||
|
|
||||||
|
void sock_cred (struct ucred *uc) { _sock_cred = *uc; }
|
||||||
|
struct ucred *sock_cred () { return &_sock_cred; }
|
||||||
|
void peer_cred (struct ucred *uc) { _peer_cred = *uc; }
|
||||||
|
struct ucred *peer_cred () { return &_peer_cred; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class fhandler_socket_unix : public fhandler_socket
|
class fhandler_socket_unix : public fhandler_socket
|
||||||
|
@ -938,9 +961,6 @@ class fhandler_socket_unix : public fhandler_socket
|
||||||
HANDLE connect_wait_thr;
|
HANDLE connect_wait_thr;
|
||||||
HANDLE cwt_termination_evt;
|
HANDLE cwt_termination_evt;
|
||||||
PVOID cwt_param;
|
PVOID cwt_param;
|
||||||
sun_name_t *sun_path;
|
|
||||||
sun_name_t *peer_sun_path;
|
|
||||||
struct ucred peer_cred;
|
|
||||||
|
|
||||||
void bind_lock () { shmem->bind_lock (); }
|
void bind_lock () { shmem->bind_lock (); }
|
||||||
void bind_unlock () { shmem->bind_unlock (); }
|
void bind_unlock () { shmem->bind_unlock (); }
|
||||||
|
@ -960,8 +980,12 @@ class fhandler_socket_unix : public fhandler_socket
|
||||||
int saw_shutdown () const { return shmem->shutdown (); }
|
int saw_shutdown () const { return shmem->shutdown (); }
|
||||||
int so_error (int err) { return shmem->so_error (err); }
|
int so_error (int err) { return shmem->so_error (err); }
|
||||||
int so_error () const { return shmem->so_error (); }
|
int so_error () const { return shmem->so_error (); }
|
||||||
|
bool so_passcred (bool pc) { return shmem->so_passcred (pc); }
|
||||||
|
bool so_passcred () const { return shmem->so_passcred (); }
|
||||||
int reuseaddr (int err) { return shmem->reuseaddr (err); }
|
int reuseaddr (int err) { return shmem->reuseaddr (err); }
|
||||||
int reuseaddr () const { return shmem->reuseaddr (); }
|
int reuseaddr () const { return shmem->reuseaddr (); }
|
||||||
|
void set_socket_type (int val) { shmem->set_socket_type (val); }
|
||||||
|
int get_socket_type () const { return shmem->get_socket_type (); }
|
||||||
|
|
||||||
int create_shmem ();
|
int create_shmem ();
|
||||||
int reopen_shmem ();
|
int reopen_shmem ();
|
||||||
|
@ -977,26 +1001,37 @@ class fhandler_socket_unix : public fhandler_socket
|
||||||
HANDLE autobind (sun_name_t *sun);
|
HANDLE autobind (sun_name_t *sun);
|
||||||
wchar_t get_type_char ();
|
wchar_t get_type_char ();
|
||||||
void set_pipe_non_blocking (bool nonblocking);
|
void set_pipe_non_blocking (bool nonblocking);
|
||||||
int send_my_name ();
|
int send_sock_info (bool from_bind);
|
||||||
int recv_peer_name ();
|
int grab_admin_pkg ();
|
||||||
|
int recv_peer_info ();
|
||||||
static NTSTATUS npfs_handle (HANDLE &nph);
|
static NTSTATUS npfs_handle (HANDLE &nph);
|
||||||
HANDLE create_pipe (bool single_instance);
|
HANDLE create_pipe (bool single_instance);
|
||||||
HANDLE create_pipe_instance ();
|
HANDLE create_pipe_instance ();
|
||||||
NTSTATUS open_pipe (PUNICODE_STRING pipe_name, bool send_name);
|
NTSTATUS open_pipe (PUNICODE_STRING pipe_name, bool xchg_sock_info);
|
||||||
int wait_pipe (PUNICODE_STRING pipe_name);
|
int wait_pipe (PUNICODE_STRING pipe_name);
|
||||||
int connect_pipe (PUNICODE_STRING pipe_name);
|
int connect_pipe (PUNICODE_STRING pipe_name);
|
||||||
int listen_pipe ();
|
int listen_pipe ();
|
||||||
|
ULONG peek_pipe (PFILE_PIPE_PEEK_BUFFER pbuf, ULONG psize, HANDLE evt);
|
||||||
int disconnect_pipe (HANDLE ph);
|
int disconnect_pipe (HANDLE ph);
|
||||||
sun_name_t *get_sun_path () {return sun_path;}
|
/* The NULL pointer check is required for FS methods like fstat. When
|
||||||
sun_name_t *get_peer_sun_path () {return peer_sun_path;}
|
called via stat or lstat, there's no shared memory, just a path in pc. */
|
||||||
void set_sun_path (struct sockaddr_un *un, __socklen_t unlen);
|
sun_name_t *sun_path () {return shmem ? shmem->sun_path () : NULL;}
|
||||||
void set_sun_path (sun_name_t *snt)
|
sun_name_t *peer_sun_path () {return shmem->peer_sun_path ();}
|
||||||
{ snt ? set_sun_path (&snt->un, snt->un_len) : set_sun_path (NULL, 0); }
|
void sun_path (struct sockaddr_un *un, __socklen_t unlen)
|
||||||
void set_peer_sun_path (struct sockaddr_un *un, __socklen_t unlen);
|
{ shmem->sun_path (un, unlen); }
|
||||||
void set_peer_sun_path (sun_name_t *snt)
|
void sun_path (sun_name_t *snt)
|
||||||
{ snt ? set_peer_sun_path (&snt->un, snt->un_len)
|
{ snt ? sun_path (&snt->un, snt->un_len) : sun_path (NULL, 0); }
|
||||||
: set_peer_sun_path (NULL, 0); }
|
void peer_sun_path (struct sockaddr_un *un, __socklen_t unlen)
|
||||||
|
{ shmem->peer_sun_path (un, unlen); }
|
||||||
|
void peer_sun_path (sun_name_t *snt)
|
||||||
|
{ snt ? peer_sun_path (&snt->un, snt->un_len)
|
||||||
|
: peer_sun_path (NULL, 0); }
|
||||||
|
void init_cred ();
|
||||||
void set_cred ();
|
void set_cred ();
|
||||||
|
void sock_cred (struct ucred *uc) { shmem->sock_cred (uc); }
|
||||||
|
struct ucred *sock_cred () { return shmem->sock_cred (); }
|
||||||
|
void peer_cred (struct ucred *uc) { shmem->peer_cred (uc); }
|
||||||
|
struct ucred *peer_cred () { return shmem->peer_cred (); }
|
||||||
void fixup_after_fork (HANDLE parent);
|
void fixup_after_fork (HANDLE parent);
|
||||||
void fixup_after_exec ();
|
void fixup_after_exec ();
|
||||||
void set_close_on_exec (bool val);
|
void set_close_on_exec (bool val);
|
||||||
|
|
|
@ -58,8 +58,8 @@
|
||||||
- <uniq_id> is an 8 byte hex unique number
|
- <uniq_id> is an 8 byte hex unique number
|
||||||
|
|
||||||
Note: We use MAX_PATH below for convenience where sufficient. It's
|
Note: We use MAX_PATH below for convenience where sufficient. It's
|
||||||
big enough to hold sun_paths as well as pipe names so we don't have
|
big enough to hold sun_paths as well as pipe names as well as packet
|
||||||
to use tmp_pathbuf as often.
|
headers etc., so we don't have to use tmp_pathbuf as often.
|
||||||
|
|
||||||
Every packet sent to a peer is a combination of the socket name of the
|
Every packet sent to a peer is a combination of the socket name of the
|
||||||
local socket, the ancillary data, and the actual user data. The data
|
local socket, the ancillary data, and the actual user data. The data
|
||||||
|
@ -78,18 +78,17 @@ class af_unix_pkt_hdr_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint16_t pckt_len; /* size of packet including header */
|
uint16_t pckt_len; /* size of packet including header */
|
||||||
uint8_t shut_info; /* shutdown info. SHUT_RD means
|
bool admin_pkg : 1; /* admin packets are marked as such */
|
||||||
SHUT_RD on the local side, so the
|
shut_state shut_info : 2; /* _SHUT_RECV /_SHUT_SEND. */
|
||||||
peer must not send further packets,
|
|
||||||
vice versa for SHUT_WR. SHUT_RDWR
|
|
||||||
is followed by closing the pipe
|
|
||||||
handle. */
|
|
||||||
uint8_t name_len; /* size of name, a sockaddr_un */
|
uint8_t name_len; /* size of name, a sockaddr_un */
|
||||||
uint16_t cmsg_len; /* size of ancillary data block */
|
uint16_t cmsg_len; /* size of ancillary data block */
|
||||||
uint16_t data_len; /* size of user data */
|
uint16_t data_len; /* size of user data */
|
||||||
|
|
||||||
void init (uint8_t s, uint8_t n, uint16_t c, uint16_t d)
|
af_unix_pkt_hdr_t (bool a, shut_state s, uint8_t n, uint16_t c, uint16_t d)
|
||||||
|
{ init (a, s, n, c, d); }
|
||||||
|
void init (bool a, shut_state s, uint8_t n, uint16_t c, uint16_t d)
|
||||||
{
|
{
|
||||||
|
admin_pkg = a;
|
||||||
shut_info = s;
|
shut_info = s;
|
||||||
name_len = n;
|
name_len = n;
|
||||||
cmsg_len = c;
|
cmsg_len = c;
|
||||||
|
@ -116,7 +115,7 @@ class af_unix_pkt_hdr_t
|
||||||
#define AF_UNIX_PKT_CMSG(phdr) \
|
#define AF_UNIX_PKT_CMSG(phdr) \
|
||||||
({ \
|
({ \
|
||||||
af_unix_pkt_hdr_t *_p = phdr; \
|
af_unix_pkt_hdr_t *_p = phdr; \
|
||||||
(void *)(((PBYTE)(_p)) + AF_UNIX_PKT_OFFSETOF_CMSG (_p)); \
|
(struct cmsghdr *)(((PBYTE)(_p)) + AF_UNIX_PKT_OFFSETOF_CMSG (_p)); \
|
||||||
})
|
})
|
||||||
#define AF_UNIX_PKT_DATA(phdr) \
|
#define AF_UNIX_PKT_DATA(phdr) \
|
||||||
({ \
|
({ \
|
||||||
|
@ -157,21 +156,16 @@ GUID __cygwin_socket_guid = {
|
||||||
/* Default timeout value of connect: 20 secs, as on Linux. */
|
/* Default timeout value of connect: 20 secs, as on Linux. */
|
||||||
#define AF_UNIX_CONNECT_TIMEOUT (-20 * NS100PERSEC)
|
#define AF_UNIX_CONNECT_TIMEOUT (-20 * NS100PERSEC)
|
||||||
|
|
||||||
sun_name_t::sun_name_t ()
|
void
|
||||||
{
|
sun_name_t::set (const struct sockaddr_un *name, socklen_t namelen)
|
||||||
un_len = sizeof (sa_family_t);
|
|
||||||
un.sun_family = AF_UNIX;
|
|
||||||
_nul[sizeof (struct sockaddr_un)] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
sun_name_t::sun_name_t (const struct sockaddr *name, socklen_t namelen)
|
|
||||||
{
|
{
|
||||||
if (namelen < 0)
|
if (namelen < 0)
|
||||||
namelen = 0;
|
namelen = 0;
|
||||||
un_len = namelen < (__socklen_t) sizeof un ? namelen : sizeof un;
|
un_len = namelen < (__socklen_t) sizeof un ? namelen : sizeof un;
|
||||||
if (name)
|
un.sun_family = AF_UNIX;
|
||||||
|
if (name && un_len)
|
||||||
memcpy (&un, name, un_len);
|
memcpy (&un, name, un_len);
|
||||||
_nul[sizeof (struct sockaddr_un)] = '\0';
|
_nul[un_len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static HANDLE
|
static HANDLE
|
||||||
|
@ -618,24 +612,49 @@ fhandler_socket_unix::set_pipe_non_blocking (bool nonblocking)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apart from being called from bind(), from_bind indicates that the caller
|
||||||
|
already locked state_lock, so send_sock_info doesn't lock, only unlocks
|
||||||
|
state_lock. */
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::send_my_name ()
|
fhandler_socket_unix::send_sock_info (bool from_bind)
|
||||||
{
|
{
|
||||||
sun_name_t *sun;
|
sun_name_t *sun;
|
||||||
size_t name_len = 0;
|
size_t plen;
|
||||||
|
size_t clen = 0;
|
||||||
af_unix_pkt_hdr_t *packet;
|
af_unix_pkt_hdr_t *packet;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
bind_lock ();
|
if (!from_bind)
|
||||||
sun = get_sun_path ();
|
{
|
||||||
name_len = sun ? sun->un_len : 0;
|
state_lock ();
|
||||||
packet = (af_unix_pkt_hdr_t *) alloca (sizeof *packet + name_len);
|
/* When called from connect, initialize credentials. accept4 already
|
||||||
|
did it (copied from listening socket). */
|
||||||
|
if (sock_cred ()->pid == 0)
|
||||||
|
set_cred ();
|
||||||
|
}
|
||||||
|
sun = sun_path ();
|
||||||
|
plen = sizeof *packet + sun->un_len;
|
||||||
|
/* When called from connect/accept4, send SCM_CREDENTIALS, too. */
|
||||||
|
if (!from_bind)
|
||||||
|
{
|
||||||
|
clen = CMSG_SPACE (sizeof (struct ucred));
|
||||||
|
plen += clen;
|
||||||
|
}
|
||||||
|
packet = (af_unix_pkt_hdr_t *) alloca (plen);
|
||||||
|
packet->init (true, _SHUT_NONE, sun->un_len, clen, 0);
|
||||||
if (sun)
|
if (sun)
|
||||||
memcpy (AF_UNIX_PKT_NAME (packet), &sun->un, name_len);
|
memcpy (AF_UNIX_PKT_NAME (packet), &sun->un, sun->un_len);
|
||||||
bind_unlock ();
|
if (!from_bind)
|
||||||
|
{
|
||||||
|
struct cmsghdr *cmsg = AF_UNIX_PKT_CMSG (packet);
|
||||||
|
cmsg->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsg->cmsg_type = SCM_CREDENTIALS;
|
||||||
|
cmsg->cmsg_len = CMSG_LEN (sizeof (struct ucred));
|
||||||
|
memcpy (CMSG_DATA(cmsg), sock_cred (), sizeof (struct ucred));
|
||||||
|
}
|
||||||
|
|
||||||
packet->init (0, name_len, 0, 0);
|
state_unlock ();
|
||||||
|
|
||||||
/* The theory: Fire and forget. */
|
/* The theory: Fire and forget. */
|
||||||
io_lock ();
|
io_lock ();
|
||||||
|
@ -652,10 +671,79 @@ fhandler_socket_unix::send_my_name ()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns an error code. Locking is not required, user space doesn't know
|
/* Checks if the next packet in the pipe is an administrative packet.
|
||||||
about this socket yet. */
|
If so, it reads it from the pipe, handles it. Returns an error code. */
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::recv_peer_name ()
|
fhandler_socket_unix::grab_admin_pkg ()
|
||||||
|
{
|
||||||
|
HANDLE evt;
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
/* MAX_PATH is more than sufficient for admin packets. */
|
||||||
|
PFILE_PIPE_PEEK_BUFFER pbuf = (PFILE_PIPE_PEEK_BUFFER) alloca (MAX_PATH);
|
||||||
|
if (!(evt = create_event ()))
|
||||||
|
return 0;
|
||||||
|
io_lock ();
|
||||||
|
ULONG ret_len = peek_pipe (pbuf, MAX_PATH, evt);
|
||||||
|
if (pbuf->NumberOfMessages == 0 || ret_len < sizeof (af_unix_pkt_hdr_t))
|
||||||
|
{
|
||||||
|
io_unlock ();
|
||||||
|
NtClose (evt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
af_unix_pkt_hdr_t *packet = (af_unix_pkt_hdr_t *) pbuf->Data;
|
||||||
|
if (!packet->admin_pkg)
|
||||||
|
io_unlock ();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet = (af_unix_pkt_hdr_t *) pbuf;
|
||||||
|
status = NtReadFile (get_handle (), evt, NULL, NULL, &io, packet,
|
||||||
|
MAX_PATH, NULL, NULL);
|
||||||
|
if (status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
/* Very short-lived */
|
||||||
|
status = NtWaitForSingleObject (evt, FALSE, NULL);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
status = io.Status;
|
||||||
|
}
|
||||||
|
io_unlock ();
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
state_lock ();
|
||||||
|
if (packet->shut_info)
|
||||||
|
{
|
||||||
|
/* Peer's shutdown sends the SHUT flags as used by the peer.
|
||||||
|
They have to be reversed for our side. */
|
||||||
|
int shut_info = saw_shutdown ();
|
||||||
|
if (packet->shut_info & _SHUT_RECV)
|
||||||
|
shut_info |= _SHUT_SEND;
|
||||||
|
if (packet->shut_info & _SHUT_SEND)
|
||||||
|
shut_info |= _SHUT_RECV;
|
||||||
|
saw_shutdown (shut_info);
|
||||||
|
/* FIXME: anything else here? */
|
||||||
|
}
|
||||||
|
if (packet->name_len > 0)
|
||||||
|
peer_sun_path (AF_UNIX_PKT_NAME (packet), packet->name_len);
|
||||||
|
if (packet->cmsg_len > 0)
|
||||||
|
{
|
||||||
|
struct cmsghdr *cmsg = (struct cmsghdr *)
|
||||||
|
alloca (packet->cmsg_len);
|
||||||
|
memcpy (cmsg, AF_UNIX_PKT_CMSG (packet), packet->cmsg_len);
|
||||||
|
if (cmsg->cmsg_level == SOL_SOCKET
|
||||||
|
&& cmsg->cmsg_type == SCM_CREDENTIALS)
|
||||||
|
peer_cred ((struct ucred *) CMSG_DATA(cmsg));
|
||||||
|
}
|
||||||
|
state_unlock ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NtClose (evt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns an error code. Locking is not required when called from accept4,
|
||||||
|
user space doesn't know about this socket yet. */
|
||||||
|
int
|
||||||
|
fhandler_socket_unix::recv_peer_info ()
|
||||||
{
|
{
|
||||||
HANDLE evt;
|
HANDLE evt;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
@ -667,7 +755,7 @@ fhandler_socket_unix::recv_peer_name ()
|
||||||
|
|
||||||
if (!(evt = create_event ()))
|
if (!(evt = create_event ()))
|
||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
len = sizeof *packet + sizeof *un;
|
len = sizeof *packet + sizeof *un + CMSG_SPACE (sizeof (struct ucred));
|
||||||
packet = (af_unix_pkt_hdr_t *) alloca (len);
|
packet = (af_unix_pkt_hdr_t *) alloca (len);
|
||||||
set_pipe_non_blocking (false);
|
set_pipe_non_blocking (false);
|
||||||
status = NtReadFile (get_handle (), evt, NULL, NULL, &io, packet, len,
|
status = NtReadFile (get_handle (), evt, NULL, NULL, &io, packet, len,
|
||||||
|
@ -695,11 +783,23 @@ fhandler_socket_unix::recv_peer_name ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
set_pipe_non_blocking (is_nonblocking ());
|
||||||
|
NtClose (evt);
|
||||||
if (!NT_SUCCESS (status) && ret == 0)
|
if (!NT_SUCCESS (status) && ret == 0)
|
||||||
ret = geterrno_from_nt_status (status);
|
ret = geterrno_from_nt_status (status);
|
||||||
if (ret == 0 && packet->name_len > 0)
|
if (ret == 0)
|
||||||
set_peer_sun_path (AF_UNIX_PKT_NAME (packet), packet->name_len);
|
{
|
||||||
set_pipe_non_blocking (is_nonblocking ());
|
if (packet->name_len > 0)
|
||||||
|
peer_sun_path (AF_UNIX_PKT_NAME (packet), packet->name_len);
|
||||||
|
if (packet->cmsg_len > 0)
|
||||||
|
{
|
||||||
|
struct cmsghdr *cmsg = (struct cmsghdr *) alloca (packet->cmsg_len);
|
||||||
|
memcpy (cmsg, AF_UNIX_PKT_CMSG (packet), packet->cmsg_len);
|
||||||
|
if (cmsg->cmsg_level == SOL_SOCKET
|
||||||
|
&& cmsg->cmsg_type == SCM_CREDENTIALS)
|
||||||
|
peer_cred ((struct ucred *) CMSG_DATA(cmsg));
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,7 +918,7 @@ fhandler_socket_unix::create_pipe_instance ()
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
fhandler_socket_unix::open_pipe (PUNICODE_STRING pipe_name, bool send_name)
|
fhandler_socket_unix::open_pipe (PUNICODE_STRING pipe_name, bool xchg_sock_info)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
HANDLE npfsh;
|
HANDLE npfsh;
|
||||||
|
@ -838,8 +938,8 @@ fhandler_socket_unix::open_pipe (PUNICODE_STRING pipe_name, bool send_name)
|
||||||
if (NT_SUCCESS (status))
|
if (NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
set_io_handle (ph);
|
set_io_handle (ph);
|
||||||
if (send_name)
|
if (xchg_sock_info)
|
||||||
send_my_name ();
|
send_sock_info (false);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -902,13 +1002,13 @@ fhandler_socket_unix::wait_pipe (PUNICODE_STRING pipe_name)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetEvent (cwt_termination_evt);
|
SetEvent (cwt_termination_evt);
|
||||||
WaitForSingleObject (connect_wait_thr, INFINITE);
|
NtWaitForSingleObject (connect_wait_thr, FALSE, NULL);
|
||||||
GetExitCodeThread (connect_wait_thr, &err);
|
GetExitCodeThread (connect_wait_thr, &err);
|
||||||
waitret = WAIT_SIGNALED;
|
waitret = WAIT_SIGNALED;
|
||||||
}
|
}
|
||||||
thr = InterlockedExchangePointer (&connect_wait_thr, NULL);
|
thr = InterlockedExchangePointer (&connect_wait_thr, NULL);
|
||||||
if (thr)
|
if (thr)
|
||||||
CloseHandle (thr);
|
NtClose (thr);
|
||||||
param = InterlockedExchangePointer (&cwt_param, NULL);
|
param = InterlockedExchangePointer (&cwt_param, NULL);
|
||||||
if (param)
|
if (param)
|
||||||
cfree (param);
|
cfree (param);
|
||||||
|
@ -988,6 +1088,27 @@ fhandler_socket_unix::listen_pipe ()
|
||||||
return (status == STATUS_PIPE_CONNECTED) ? 0 : -1;
|
return (status == STATUS_PIPE_CONNECTED) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
fhandler_socket_unix::peek_pipe (PFILE_PIPE_PEEK_BUFFER pbuf, ULONG psize,
|
||||||
|
HANDLE evt)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
|
status = NtFsControlFile (get_handle (), evt, NULL, NULL, &io,
|
||||||
|
FSCTL_PIPE_PEEK, NULL, 0, pbuf, psize);
|
||||||
|
if (status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
/* Very short-lived */
|
||||||
|
status = NtWaitForSingleObject (evt ?: get_handle (), FALSE, NULL);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
status = io.Status;
|
||||||
|
}
|
||||||
|
return NT_SUCCESS (status) ? (io.Information
|
||||||
|
- offsetof (FILE_PIPE_PEEK_BUFFER, Data))
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::disconnect_pipe (HANDLE ph)
|
fhandler_socket_unix::disconnect_pipe (HANDLE ph)
|
||||||
{
|
{
|
||||||
|
@ -998,7 +1119,7 @@ fhandler_socket_unix::disconnect_pipe (HANDLE ph)
|
||||||
NULL, 0, NULL, 0);
|
NULL, 0, NULL, 0);
|
||||||
/* Short-lived. Don't use cygwait. We don't want to be interrupted. */
|
/* Short-lived. Don't use cygwait. We don't want to be interrupted. */
|
||||||
if (status == STATUS_PENDING
|
if (status == STATUS_PENDING
|
||||||
&& WaitForSingleObject (ph, INFINITE) == WAIT_OBJECT_0)
|
&& NtWaitForSingleObject (ph, FALSE, NULL) == WAIT_OBJECT_0)
|
||||||
status = io.Status;
|
status = io.Status;
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
|
@ -1009,32 +1130,22 @@ fhandler_socket_unix::disconnect_pipe (HANDLE ph)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fhandler_socket_unix::set_sun_path (struct sockaddr_un *un, socklen_t unlen)
|
fhandler_socket_unix::init_cred ()
|
||||||
{
|
{
|
||||||
if (peer_sun_path)
|
struct ucred *scred = shmem->sock_cred ();
|
||||||
delete peer_sun_path;
|
struct ucred *pcred = shmem->peer_cred ();
|
||||||
if (!un)
|
scred->pid = pcred->pid = (pid_t) 0;
|
||||||
sun_path = NULL;
|
scred->uid = pcred->uid = (uid_t) -1;
|
||||||
sun_path = new sun_name_t ((const struct sockaddr *) un, unlen);
|
scred->gid = pcred->gid = (gid_t) -1;
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fhandler_socket_unix::set_peer_sun_path (struct sockaddr_un *un,
|
|
||||||
socklen_t unlen)
|
|
||||||
{
|
|
||||||
if (peer_sun_path)
|
|
||||||
delete peer_sun_path;
|
|
||||||
if (!un)
|
|
||||||
peer_sun_path = NULL;
|
|
||||||
peer_sun_path = new sun_name_t ((const struct sockaddr *) un, unlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fhandler_socket_unix::set_cred ()
|
fhandler_socket_unix::set_cred ()
|
||||||
{
|
{
|
||||||
peer_cred.pid = (pid_t) 0;
|
struct ucred *scred = shmem->sock_cred ();
|
||||||
peer_cred.uid = (uid_t) -1;
|
scred->pid = myself->pid;
|
||||||
peer_cred.gid = (gid_t) -1;
|
scred->uid = myself->uid;
|
||||||
|
scred->gid = myself->gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== public methods ========================= */
|
/* ========================== public methods ========================= */
|
||||||
|
@ -1074,15 +1185,10 @@ fhandler_socket_unix::set_close_on_exec (bool val)
|
||||||
|
|
||||||
fhandler_socket_unix::fhandler_socket_unix ()
|
fhandler_socket_unix::fhandler_socket_unix ()
|
||||||
{
|
{
|
||||||
set_cred ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fhandler_socket_unix::~fhandler_socket_unix ()
|
fhandler_socket_unix::~fhandler_socket_unix ()
|
||||||
{
|
{
|
||||||
if (sun_path)
|
|
||||||
delete sun_path;
|
|
||||||
if (peer_sun_path)
|
|
||||||
delete peer_sun_path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1094,6 +1200,12 @@ fhandler_socket_unix::dup (fhandler_base *child, int flags)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fhandler_socket_unix *fhs = (fhandler_socket_unix *) child;
|
fhandler_socket_unix *fhs = (fhandler_socket_unix *) child;
|
||||||
|
if (reopen_shmem () < 0)
|
||||||
|
{
|
||||||
|
__seterrno ();
|
||||||
|
fhs->close ();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE
|
if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE
|
||||||
&& !DuplicateHandle (GetCurrentProcess (), backing_file_handle,
|
&& !DuplicateHandle (GetCurrentProcess (), backing_file_handle,
|
||||||
GetCurrentProcess (), &fhs->backing_file_handle,
|
GetCurrentProcess (), &fhs->backing_file_handle,
|
||||||
|
@ -1111,14 +1223,8 @@ fhandler_socket_unix::dup (fhandler_base *child, int flags)
|
||||||
fhs->close ();
|
fhs->close ();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (reopen_shmem () < 0)
|
fhs->sun_path (sun_path ());
|
||||||
{
|
fhs->peer_sun_path (peer_sun_path ());
|
||||||
__seterrno ();
|
|
||||||
fhs->close ();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fhs->set_sun_path (get_sun_path ());
|
|
||||||
fhs->set_peer_sun_path (get_peer_sun_path ());
|
|
||||||
fhs->connect_wait_thr = NULL;
|
fhs->connect_wait_thr = NULL;
|
||||||
fhs->cwt_termination_evt = NULL;
|
fhs->cwt_termination_evt = NULL;
|
||||||
fhs->cwt_param = NULL;
|
fhs->cwt_param = NULL;
|
||||||
|
@ -1250,12 +1356,13 @@ fhandler_socket_unix::socket (int af, int type, int protocol, int flags)
|
||||||
return -1;
|
return -1;
|
||||||
rmem (262144);
|
rmem (262144);
|
||||||
wmem (262144);
|
wmem (262144);
|
||||||
set_addr_family (af);
|
set_addr_family (AF_UNIX);
|
||||||
set_socket_type (type);
|
set_socket_type (type);
|
||||||
if (flags & SOCK_NONBLOCK)
|
if (flags & SOCK_NONBLOCK)
|
||||||
set_nonblocking (true);
|
set_nonblocking (true);
|
||||||
if (flags & SOCK_CLOEXEC)
|
if (flags & SOCK_CLOEXEC)
|
||||||
set_close_on_exec (true);
|
set_close_on_exec (true);
|
||||||
|
init_cred ();
|
||||||
set_io_handle (NULL);
|
set_io_handle (NULL);
|
||||||
set_unique_id ();
|
set_unique_id ();
|
||||||
set_ino (get_unique_id ());
|
set_ino (get_unique_id ());
|
||||||
|
@ -1281,46 +1388,36 @@ fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (create_shmem () < 0)
|
||||||
|
return -1;
|
||||||
|
if (fh->create_shmem () < 0)
|
||||||
|
goto fh_shmem_failed;
|
||||||
/* socket() on both sockets */
|
/* socket() on both sockets */
|
||||||
rmem (262144);
|
rmem (262144);
|
||||||
fh->rmem (262144);
|
fh->rmem (262144);
|
||||||
wmem (262144);
|
wmem (262144);
|
||||||
fh->wmem (262144);
|
fh->wmem (262144);
|
||||||
set_addr_family (af);
|
set_addr_family (AF_UNIX);
|
||||||
fh->set_addr_family (af);
|
fh->set_addr_family (AF_UNIX);
|
||||||
set_socket_type (type);
|
set_socket_type (type);
|
||||||
fh->set_socket_type (type);
|
fh->set_socket_type (type);
|
||||||
|
set_cred ();
|
||||||
|
fh->set_cred ();
|
||||||
set_unique_id ();
|
set_unique_id ();
|
||||||
set_ino (get_unique_id ());
|
set_ino (get_unique_id ());
|
||||||
/* bind/listen 1st socket */
|
/* bind/listen 1st socket */
|
||||||
gen_pipe_name ();
|
gen_pipe_name ();
|
||||||
pipe = create_pipe (true);
|
pipe = create_pipe (true);
|
||||||
if (!pipe)
|
if (!pipe)
|
||||||
return -1;
|
goto create_pipe_failed;
|
||||||
set_io_handle (pipe);
|
set_io_handle (pipe);
|
||||||
set_sun_path (&sun);
|
sun_path (&sun);
|
||||||
fh->set_peer_sun_path (&sun);
|
fh->peer_sun_path (&sun);
|
||||||
if (create_shmem () < 0)
|
|
||||||
{
|
|
||||||
NtClose (pipe);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
binding_state (bound);
|
|
||||||
connect_state (listener);
|
connect_state (listener);
|
||||||
/* connect 2nd socket */
|
/* connect 2nd socket, even for DGRAM. There's no difference as far
|
||||||
if (type != SOCK_DGRAM
|
as socketpairs are concerned. */
|
||||||
&& fh->open_pipe (pc.get_nt_native_path (), false) < 0)
|
if (fh->open_pipe (pc.get_nt_native_path (), false) < 0)
|
||||||
{
|
goto fh_open_pipe_failed;
|
||||||
NtClose (shmem_handle);
|
|
||||||
NtClose (pipe);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (fh->create_shmem () < 0)
|
|
||||||
{
|
|
||||||
NtClose (fh->get_handle ());
|
|
||||||
NtClose (shmem_handle);
|
|
||||||
NtClose (pipe);
|
|
||||||
}
|
|
||||||
fh->connect_state (connected);
|
fh->connect_state (connected);
|
||||||
if (flags & SOCK_NONBLOCK)
|
if (flags & SOCK_NONBLOCK)
|
||||||
{
|
{
|
||||||
|
@ -1333,6 +1430,16 @@ fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags,
|
||||||
fh->set_close_on_exec (true);
|
fh->set_close_on_exec (true);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fh_open_pipe_failed:
|
||||||
|
NtClose (pipe);
|
||||||
|
create_pipe_failed:
|
||||||
|
NtUnmapViewOfSection (GetCurrentProcess (), fh->shmem);
|
||||||
|
NtClose (fh->shmem_handle);
|
||||||
|
fh_shmem_failed:
|
||||||
|
NtUnmapViewOfSection (GetCurrentProcess (), shmem);
|
||||||
|
NtClose (shmem_handle);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bind creates the backing file, generates the pipe name and sets
|
/* Bind creates the backing file, generates the pipe name and sets
|
||||||
|
@ -1385,10 +1492,14 @@ fhandler_socket_unix::bind (const struct sockaddr *name, int namelen)
|
||||||
binding_state (unbound);
|
binding_state (unbound);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_sun_path (&sun);
|
state_lock ();
|
||||||
/* If we're already connected, send name to peer. */
|
sun_path (&sun);
|
||||||
|
/* If we're already connected, send socket info to peer. In this case
|
||||||
|
send_sock_info calls state_unlock */
|
||||||
if (connect_state () == connected)
|
if (connect_state () == connected)
|
||||||
send_my_name ();
|
send_sock_info (true);
|
||||||
|
else
|
||||||
|
state_unlock ();
|
||||||
binding_state (bound);
|
binding_state (bound);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1426,6 +1537,9 @@ fhandler_socket_unix::listen (int backlog)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_io_handle (pipe);
|
set_io_handle (pipe);
|
||||||
|
state_lock ();
|
||||||
|
set_cred ();
|
||||||
|
state_unlock ();
|
||||||
connect_state (listener);
|
connect_state (listener);
|
||||||
conn_unlock ();
|
conn_unlock ();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1473,7 +1587,7 @@ fhandler_socket_unix::accept4 (struct sockaddr *peer, int *len, int flags)
|
||||||
if (sock->create_shmem () < 0)
|
if (sock->create_shmem () < 0)
|
||||||
goto create_shmem_failed;
|
goto create_shmem_failed;
|
||||||
|
|
||||||
sock->set_addr_family (get_addr_family ());
|
sock->set_addr_family (AF_UNIX);
|
||||||
sock->set_socket_type (get_socket_type ());
|
sock->set_socket_type (get_socket_type ());
|
||||||
if (flags & SOCK_NONBLOCK)
|
if (flags & SOCK_NONBLOCK)
|
||||||
sock->set_nonblocking (true);
|
sock->set_nonblocking (true);
|
||||||
|
@ -1486,15 +1600,20 @@ fhandler_socket_unix::accept4 (struct sockaddr *peer, int *len, int flags)
|
||||||
sock->binding_state (binding_state ());
|
sock->binding_state (binding_state ());
|
||||||
sock->set_io_handle (accepted);
|
sock->set_io_handle (accepted);
|
||||||
|
|
||||||
sock->set_sun_path (get_sun_path ());
|
sock->sun_path (sun_path ());
|
||||||
error = sock->recv_peer_name ();
|
sock->sock_cred (sock_cred ());
|
||||||
|
/* Send this socket info to connecting socket. */
|
||||||
|
sock->send_sock_info (false);
|
||||||
|
/* Fetch the packet sent by send_sock_info called by
|
||||||
|
connecting peer. */
|
||||||
|
error = sock->recv_peer_info ();
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
if (peer)
|
if (peer)
|
||||||
{
|
{
|
||||||
sun_name_t *sun = sock->get_peer_sun_path ();
|
sun_name_t *sun = sock->peer_sun_path ();
|
||||||
if (sun)
|
if (sun)
|
||||||
{
|
{
|
||||||
memcpy (peer, &sun->un,
|
memcpy (peer, &sun->un,
|
||||||
|
@ -1591,14 +1710,14 @@ fhandler_socket_unix::connect (const struct sockaddr *name, int namelen)
|
||||||
connect_state (unconnected);
|
connect_state (unconnected);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_peer_sun_path (&sun);
|
peer_sun_path (&sun);
|
||||||
if (get_socket_type () != SOCK_DGRAM)
|
if (get_socket_type () != SOCK_DGRAM)
|
||||||
{
|
{
|
||||||
if (connect_pipe (&pipe_name) < 0)
|
if (connect_pipe (&pipe_name) < 0)
|
||||||
{
|
{
|
||||||
if (get_errno () != EINPROGRESS)
|
if (get_errno () != EINPROGRESS)
|
||||||
{
|
{
|
||||||
set_peer_sun_path (NULL);
|
peer_sun_path (NULL);
|
||||||
connect_state (connect_failed);
|
connect_state (connect_failed);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1611,36 +1730,60 @@ fhandler_socket_unix::connect (const struct sockaddr *name, int namelen)
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::getsockname (struct sockaddr *name, int *namelen)
|
fhandler_socket_unix::getsockname (struct sockaddr *name, int *namelen)
|
||||||
{
|
{
|
||||||
sun_name_t sun;
|
sun_name_t *sun = sun_path ();
|
||||||
|
|
||||||
if (get_sun_path ())
|
memcpy (name, sun, MIN (*namelen, sun->un_len));
|
||||||
memcpy (&sun, &get_sun_path ()->un, get_sun_path ()->un_len);
|
*namelen = sun->un_len;
|
||||||
else
|
|
||||||
sun.un_len = 0;
|
|
||||||
memcpy (name, &sun, MIN (*namelen, sun.un_len));
|
|
||||||
*namelen = sun.un_len;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::getpeername (struct sockaddr *name, int *namelen)
|
fhandler_socket_unix::getpeername (struct sockaddr *name, int *namelen)
|
||||||
{
|
{
|
||||||
sun_name_t sun;
|
sun_name_t *sun = peer_sun_path ();
|
||||||
|
memcpy (name, sun, MIN (*namelen, sun->un_len));
|
||||||
if (get_peer_sun_path ())
|
*namelen = sun->un_len;
|
||||||
memcpy (&sun, &get_peer_sun_path ()->un, get_peer_sun_path ()->un_len);
|
|
||||||
else
|
|
||||||
sun.un_len = 0;
|
|
||||||
memcpy (name, &sun, MIN (*namelen, sun.un_len));
|
|
||||||
*namelen = sun.un_len;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::shutdown (int how)
|
fhandler_socket_unix::shutdown (int how)
|
||||||
{
|
{
|
||||||
set_errno (EAFNOSUPPORT);
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
return -1;
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
|
if (how < SHUT_RD || how > SHUT_RDWR)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Convert SHUT_RD/SHUT_WR/SHUT_RDWR to _SHUT_RECV/_SHUT_SEND bits. */
|
||||||
|
++how;
|
||||||
|
state_lock ();
|
||||||
|
int old_shutdown_mask = saw_shutdown ();
|
||||||
|
int new_shutdown_mask = old_shutdown_mask | how;
|
||||||
|
if (new_shutdown_mask != old_shutdown_mask)
|
||||||
|
saw_shutdown (new_shutdown_mask);
|
||||||
|
state_unlock ();
|
||||||
|
if (new_shutdown_mask != old_shutdown_mask)
|
||||||
|
{
|
||||||
|
/* Send shutdown info to peer. Note that it's not necessarily fatal
|
||||||
|
if the info isn't sent here. The info will be reproduced by any
|
||||||
|
followup package sent to the peer. */
|
||||||
|
af_unix_pkt_hdr_t packet (true, (shut_state) new_shutdown_mask, 0, 0, 0);
|
||||||
|
io_lock ();
|
||||||
|
set_pipe_non_blocking (true);
|
||||||
|
status = NtWriteFile (get_handle (), NULL, NULL, NULL, &io, &packet,
|
||||||
|
packet.pckt_len, NULL, NULL);
|
||||||
|
set_pipe_non_blocking (is_nonblocking ());
|
||||||
|
io_unlock ();
|
||||||
|
}
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
debug_printf ("Couldn't send shutdown info: NtWriteFile: %y", status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1652,24 +1795,25 @@ fhandler_socket_unix::close ()
|
||||||
{
|
{
|
||||||
if (evt)
|
if (evt)
|
||||||
SetEvent (evt);
|
SetEvent (evt);
|
||||||
WaitForSingleObject (thr, INFINITE);
|
NtWaitForSingleObject (thr, FALSE, NULL);
|
||||||
CloseHandle (thr);
|
NtClose (thr);
|
||||||
}
|
}
|
||||||
if (evt)
|
if (evt)
|
||||||
NtClose (evt);
|
NtClose (evt);
|
||||||
PVOID param = InterlockedExchangePointer (&cwt_param, NULL);
|
PVOID param = InterlockedExchangePointer (&cwt_param, NULL);
|
||||||
if (param)
|
if (param)
|
||||||
cfree (param);
|
cfree (param);
|
||||||
|
HANDLE hdl = InterlockedExchangePointer (&get_handle (), NULL);
|
||||||
|
if (hdl)
|
||||||
|
NtClose (hdl);
|
||||||
|
if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE)
|
||||||
|
NtClose (backing_file_handle);
|
||||||
HANDLE shm = InterlockedExchangePointer (&shmem_handle, NULL);
|
HANDLE shm = InterlockedExchangePointer (&shmem_handle, NULL);
|
||||||
if (shm)
|
if (shm)
|
||||||
NtClose (shm);
|
NtClose (shm);
|
||||||
param = InterlockedExchangePointer ((PVOID *) &shmem, NULL);
|
param = InterlockedExchangePointer ((PVOID *) &shmem, NULL);
|
||||||
if (param)
|
if (param)
|
||||||
NtUnmapViewOfSection (GetCurrentProcess (), param);
|
NtUnmapViewOfSection (GetCurrentProcess (), param);
|
||||||
if (get_handle ())
|
|
||||||
NtClose (get_handle ());
|
|
||||||
if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE)
|
|
||||||
NtClose (backing_file_handle);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1683,7 +1827,6 @@ fhandler_socket_unix::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid)
|
||||||
set_errno (EINVAL);
|
set_errno (EINVAL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
conn_lock ();
|
|
||||||
if (connect_state () != connected)
|
if (connect_state () != connected)
|
||||||
set_errno (ENOTCONN);
|
set_errno (ENOTCONN);
|
||||||
else
|
else
|
||||||
|
@ -1691,19 +1834,19 @@ fhandler_socket_unix::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid)
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
state_lock ();
|
state_lock ();
|
||||||
|
struct ucred *pcred = peer_cred ();
|
||||||
if (pid)
|
if (pid)
|
||||||
*pid = peer_cred.pid;
|
*pid = pcred->pid;
|
||||||
if (euid)
|
if (euid)
|
||||||
*euid = peer_cred.uid;
|
*euid = pcred->uid;
|
||||||
if (egid)
|
if (egid)
|
||||||
*egid = peer_cred.gid;
|
*egid = pcred->gid;
|
||||||
state_unlock ();
|
state_unlock ();
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
__except (EFAULT) {}
|
__except (EFAULT) {}
|
||||||
__endtry
|
__endtry
|
||||||
}
|
}
|
||||||
conn_unlock ();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1844,17 +1987,60 @@ fhandler_socket_unix::setsockopt (int level, int optname, const void *optval,
|
||||||
switch (optname)
|
switch (optname)
|
||||||
{
|
{
|
||||||
case SO_PASSCRED:
|
case SO_PASSCRED:
|
||||||
|
if (optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool val;
|
||||||
|
val = !!*(int *) optval;
|
||||||
|
/* Using bind_lock here to make sure the autobind below is
|
||||||
|
covered. This is the only place to set so_passcred anyway. */
|
||||||
|
bind_lock ();
|
||||||
|
if (val && binding_state () == unbound)
|
||||||
|
{
|
||||||
|
sun_name_t sun;
|
||||||
|
|
||||||
|
binding_state (bind_pending);
|
||||||
|
backing_file_handle = autobind (&sun);
|
||||||
|
if (!backing_file_handle)
|
||||||
|
{
|
||||||
|
binding_state (unbound);
|
||||||
|
bind_unlock ();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sun_path (&sun);
|
||||||
|
binding_state (bound);
|
||||||
|
}
|
||||||
|
so_passcred (val);
|
||||||
|
bind_unlock ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SO_REUSEADDR:
|
case SO_REUSEADDR:
|
||||||
reuseaddr (*(int *) optval);
|
if (optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
reuseaddr (!!*(int *) optval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SO_RCVBUF:
|
case SO_RCVBUF:
|
||||||
|
if (optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
rmem (*(int *) optval);
|
rmem (*(int *) optval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SO_SNDBUF:
|
case SO_SNDBUF:
|
||||||
|
if (optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
wmem (*(int *) optval);
|
wmem (*(int *) optval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1900,6 +2086,12 @@ fhandler_socket_unix::getsockopt (int level, int optname, const void *optval,
|
||||||
{
|
{
|
||||||
case SO_ERROR:
|
case SO_ERROR:
|
||||||
{
|
{
|
||||||
|
if (*optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int *e = (int *) optval;
|
int *e = (int *) optval;
|
||||||
LONG err;
|
LONG err;
|
||||||
|
|
||||||
|
@ -1909,7 +2101,17 @@ fhandler_socket_unix::getsockopt (int level, int optname, const void *optval,
|
||||||
}
|
}
|
||||||
|
|
||||||
case SO_PASSCRED:
|
case SO_PASSCRED:
|
||||||
break;
|
{
|
||||||
|
if (*optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *e = (int *) optval;
|
||||||
|
*e = so_passcred ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SO_PEERCRED:
|
case SO_PEERCRED:
|
||||||
{
|
{
|
||||||
|
@ -1977,6 +2179,11 @@ fhandler_socket_unix::getsockopt (int level, int optname, const void *optval,
|
||||||
|
|
||||||
case SO_TYPE:
|
case SO_TYPE:
|
||||||
{
|
{
|
||||||
|
if (*optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
unsigned int *type = (unsigned int *) optval;
|
unsigned int *type = (unsigned int *) optval;
|
||||||
*type = get_socket_type ();
|
*type = get_socket_type ();
|
||||||
*optlen = (socklen_t) sizeof *type;
|
*optlen = (socklen_t) sizeof *type;
|
||||||
|
@ -1987,6 +2194,11 @@ fhandler_socket_unix::getsockopt (int level, int optname, const void *optval,
|
||||||
|
|
||||||
case SO_LINGER:
|
case SO_LINGER:
|
||||||
{
|
{
|
||||||
|
if (*optlen < (socklen_t) sizeof (struct linger))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
struct linger *linger = (struct linger *) optval;
|
struct linger *linger = (struct linger *) optval;
|
||||||
memset (linger, 0, sizeof *linger);
|
memset (linger, 0, sizeof *linger);
|
||||||
*optlen = (socklen_t) sizeof *linger;
|
*optlen = (socklen_t) sizeof *linger;
|
||||||
|
@ -1995,6 +2207,11 @@ fhandler_socket_unix::getsockopt (int level, int optname, const void *optval,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
if (*optlen < (socklen_t) sizeof (int))
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
unsigned int *val = (unsigned int *) optval;
|
unsigned int *val = (unsigned int *) optval;
|
||||||
*val = 0;
|
*val = 0;
|
||||||
*optlen = (socklen_t) sizeof *val;
|
*optlen = (socklen_t) sizeof *val;
|
||||||
|
@ -2083,9 +2300,9 @@ fhandler_socket_unix::fstat (struct stat *buf)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!get_sun_path ()
|
if (sun_path ()
|
||||||
|| get_sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
&& (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
||||||
|| get_sun_path ()->un.sun_path[0] == '\0')
|
|| sun_path ()->un.sun_path[0] == '\0'))
|
||||||
return fhandler_socket::fstat (buf);
|
return fhandler_socket::fstat (buf);
|
||||||
ret = fhandler_base::fstat_fs (buf);
|
ret = fhandler_base::fstat_fs (buf);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -2099,9 +2316,9 @@ fhandler_socket_unix::fstat (struct stat *buf)
|
||||||
int __reg2
|
int __reg2
|
||||||
fhandler_socket_unix::fstatvfs (struct statvfs *sfs)
|
fhandler_socket_unix::fstatvfs (struct statvfs *sfs)
|
||||||
{
|
{
|
||||||
if (!get_sun_path ()
|
if (sun_path ()
|
||||||
|| get_sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
&& (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
||||||
|| get_sun_path ()->un.sun_path[0] == '\0')
|
|| sun_path ()->un.sun_path[0] == '\0'))
|
||||||
return fhandler_socket::fstatvfs (sfs);
|
return fhandler_socket::fstatvfs (sfs);
|
||||||
fhandler_disk_file fh (pc);
|
fhandler_disk_file fh (pc);
|
||||||
fh.get_device () = FH_FS;
|
fh.get_device () = FH_FS;
|
||||||
|
@ -2111,9 +2328,9 @@ fhandler_socket_unix::fstatvfs (struct statvfs *sfs)
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::fchmod (mode_t newmode)
|
fhandler_socket_unix::fchmod (mode_t newmode)
|
||||||
{
|
{
|
||||||
if (!get_sun_path ()
|
if (sun_path ()
|
||||||
|| get_sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
&& (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
||||||
|| get_sun_path ()->un.sun_path[0] == '\0')
|
|| sun_path ()->un.sun_path[0] == '\0'))
|
||||||
return fhandler_socket::fchmod (newmode);
|
return fhandler_socket::fchmod (newmode);
|
||||||
fhandler_disk_file fh (pc);
|
fhandler_disk_file fh (pc);
|
||||||
fh.get_device () = FH_FS;
|
fh.get_device () = FH_FS;
|
||||||
|
@ -2130,9 +2347,9 @@ fhandler_socket_unix::fchmod (mode_t newmode)
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::fchown (uid_t uid, gid_t gid)
|
fhandler_socket_unix::fchown (uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
if (!get_sun_path ()
|
if (sun_path ()
|
||||||
|| get_sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
&& (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
||||||
|| get_sun_path ()->un.sun_path[0] == '\0')
|
|| sun_path ()->un.sun_path[0] == '\0'))
|
||||||
return fhandler_socket::fchown (uid, gid);
|
return fhandler_socket::fchown (uid, gid);
|
||||||
fhandler_disk_file fh (pc);
|
fhandler_disk_file fh (pc);
|
||||||
return fh.fchown (uid, gid);
|
return fh.fchown (uid, gid);
|
||||||
|
@ -2141,9 +2358,9 @@ fhandler_socket_unix::fchown (uid_t uid, gid_t gid)
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::facl (int cmd, int nentries, aclent_t *aclbufp)
|
fhandler_socket_unix::facl (int cmd, int nentries, aclent_t *aclbufp)
|
||||||
{
|
{
|
||||||
if (!get_sun_path ()
|
if (sun_path ()
|
||||||
|| get_sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
&& (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
||||||
|| get_sun_path ()->un.sun_path[0] == '\0')
|
|| sun_path ()->un.sun_path[0] == '\0'))
|
||||||
return fhandler_socket::facl (cmd, nentries, aclbufp);
|
return fhandler_socket::facl (cmd, nentries, aclbufp);
|
||||||
fhandler_disk_file fh (pc);
|
fhandler_disk_file fh (pc);
|
||||||
return fh.facl (cmd, nentries, aclbufp);
|
return fh.facl (cmd, nentries, aclbufp);
|
||||||
|
@ -2152,9 +2369,9 @@ fhandler_socket_unix::facl (int cmd, int nentries, aclent_t *aclbufp)
|
||||||
int
|
int
|
||||||
fhandler_socket_unix::link (const char *newpath)
|
fhandler_socket_unix::link (const char *newpath)
|
||||||
{
|
{
|
||||||
if (!get_sun_path ()
|
if (sun_path ()
|
||||||
|| get_sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
&& (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
|
||||||
|| get_sun_path ()->un.sun_path[0] == '\0')
|
|| sun_path ()->un.sun_path[0] == '\0'))
|
||||||
return fhandler_socket::link (newpath);
|
return fhandler_socket::link (newpath);
|
||||||
fhandler_disk_file fh (pc);
|
fhandler_disk_file fh (pc);
|
||||||
return fh.link (newpath);
|
return fh.link (newpath);
|
||||||
|
|
Loading…
Reference in New Issue