mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-15 13:39:26 +08:00
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.
This commit is contained in:
parent
451ec9bb13
commit
24ac223828
@ -1186,6 +1186,7 @@ class fhandler_socket_unix : public fhandler_socket
|
|||||||
HANDLE create_pipe (bool single_instance);
|
HANDLE create_pipe (bool single_instance);
|
||||||
HANDLE create_pipe_instance ();
|
HANDLE create_pipe_instance ();
|
||||||
NTSTATUS open_pipe (HANDLE &ph, PUNICODE_STRING pipe_name);
|
NTSTATUS open_pipe (HANDLE &ph, PUNICODE_STRING pipe_name);
|
||||||
|
int wait_open_pipe (HANDLE &ph, PUNICODE_STRING pipe_name);
|
||||||
void xchg_sock_info ();
|
void 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);
|
||||||
|
@ -1479,6 +1479,81 @@ out:
|
|||||||
return error;
|
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
|
int
|
||||||
fhandler_socket_unix::socket (int af, int type, int protocol, int flags)
|
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;
|
__leave;
|
||||||
}
|
}
|
||||||
status = open_pipe (ph, &pipe_name);
|
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);
|
__seterrno_from_nt_status (status);
|
||||||
__leave;
|
__leave;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user