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:
authorKen Brown <kbrown@cornell.edu>2021-04-01 18:06:24 +0300
committerKen Brown <kbrown@cornell.edu>2021-04-01 18:06:24 +0300
commit24ac223828eaca1acdce4a926ef0b5dd7124f24f (patch)
treed5a49e2309a7aa0c3e4314fe7c8214403c671c4e
parent451ec9bb130666b94a5b597ba6eb7cc758f4e1e2 (diff)
Cygwin: AF_UNIX: sendmsg: wait for a pipe instance in the datagram case
When trying to connect to the pipe created by the remote socket, open_pipe might fail if there are no pipe instances available. This can happen if there has been a previous connection to the same pipe. The server end of the pipe won't be available again until it disconnects the previous connection. (This is done in recvmsg.) Introduce and use a new method fhandler_socket_unix::wait_open_pipe that waits (in the blocking case) for an instance to become available.
-rw-r--r--winsup/cygwin/fhandler.h1
-rw-r--r--winsup/cygwin/fhandler_socket_unix.cc87
2 files changed, 87 insertions, 1 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index e474203eb..932f535e8 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1186,6 +1186,7 @@ class fhandler_socket_unix : public fhandler_socket
HANDLE create_pipe (bool single_instance);
HANDLE create_pipe_instance ();
NTSTATUS open_pipe (HANDLE &ph, PUNICODE_STRING pipe_name);
+ int wait_open_pipe (HANDLE &ph, PUNICODE_STRING pipe_name);
void xchg_sock_info ();
int wait_pipe (PUNICODE_STRING pipe_name);
int connect_pipe (PUNICODE_STRING pipe_name);
diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc
index 1a0a7e7ba..dc71a8d2a 100644
--- a/winsup/cygwin/fhandler_socket_unix.cc
+++ b/winsup/cygwin/fhandler_socket_unix.cc
@@ -1479,6 +1479,81 @@ out:
return error;
}
+/* A variant of wait_pipe_thread, called by sendmsg in datagram case.
+ Wait for a pipe instance to become available and connect to it. */
+int
+fhandler_socket_unix::wait_open_pipe (HANDLE &ph, PUNICODE_STRING pipe_name)
+{
+ HANDLE npfsh;
+ HANDLE evt;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ ULONG pwbuf_size;
+ PFILE_PIPE_WAIT_FOR_BUFFER pwbuf;
+ int ret = -1;
+
+ status = npfs_handle (npfsh);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto out;
+ }
+ if (!(evt = create_event ()))
+ goto out;
+ pwbuf_size = offsetof (FILE_PIPE_WAIT_FOR_BUFFER, Name) + pipe_name->Length;
+ pwbuf = (PFILE_PIPE_WAIT_FOR_BUFFER) alloca (pwbuf_size);
+ pwbuf->NameLength = pipe_name->Length;
+ pwbuf->TimeoutSpecified = FALSE;
+ memcpy (pwbuf->Name, pipe_name->Buffer, pipe_name->Length);
+ retry:
+ status = NtFsControlFile (npfsh, evt, NULL, NULL, &io, FSCTL_PIPE_WAIT,
+ pwbuf, pwbuf_size, NULL, 0);
+ if (status == STATUS_PENDING)
+ {
+ switch (cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr))
+ {
+ case WAIT_OBJECT_0:
+ status = io.Status;
+ break;
+ case WAIT_CANCELED:
+ pthread::static_cancel_self ();
+ /*NOTREACHED*/
+ case WAIT_SIGNALED:
+ set_errno (EINTR);
+ break;
+ default:
+ break;
+ }
+ }
+ switch (status)
+ {
+ case STATUS_SUCCESS:
+ status = open_pipe (ph, pipe_name);
+ if (NT_SUCCESS (status))
+ ret = 0;
+ else if (STATUS_PIPE_NO_INSTANCE_AVAILABLE (status))
+ /* Someone else grabbed the pipe instance. */
+ goto retry;
+ else
+ __seterrno_from_nt_status (status);
+ break;
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ set_errno (EADDRNOTAVAIL);
+ break;
+ case STATUS_INSUFFICIENT_RESOURCES:
+ set_errno (ENOBUFS);
+ break;
+ case STATUS_INVALID_DEVICE_REQUEST:
+ default:
+ set_errno (EIO);
+ break;
+ }
+ out:
+ if (evt)
+ NtClose (evt);
+ return ret;
+}
+
int
fhandler_socket_unix::socket (int af, int type, int protocol, int flags)
{
@@ -3106,7 +3181,17 @@ fhandler_socket_unix::sendmsg (const struct msghdr *msg, int flags)
__leave;
}
status = open_pipe (ph, &pipe_name);
- if (!NT_SUCCESS (status))
+ if (STATUS_PIPE_NO_INSTANCE_AVAILABLE (status))
+ {
+ if (is_nonblocking () || flags & MSG_DONTWAIT)
+ {
+ set_errno (EAGAIN);
+ __leave;
+ }
+ if (wait_open_pipe (ph, &pipe_name) < 0)
+ __leave;
+ }
+ else if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
__leave;