This is the mail archive of the
cygwin-cvs@cygwin.com
mailing list for the Cygwin project.
[newlib-cygwin] Cygwin: fhandler_socket_unix: implement socket, bind, and close
- From: Corinna Vinschen <corinna at sourceware dot org>
- To: cygwin-cvs at sourceware dot org
- Date: 2 Mar 2018 17:18:28 -0000
- Subject: [newlib-cygwin] Cygwin: fhandler_socket_unix: implement socket, bind, and close
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=97b7aaaeb7fb8055b48318468652eaeec3a428e2
commit 97b7aaaeb7fb8055b48318468652eaeec3a428e2
Author: Corinna Vinschen <corinna@vinschen.de>
Date: Fri Mar 2 18:14:11 2018 +0100
Cygwin: fhandler_socket_unix: implement socket, bind, and close
...plus lots of helper functions. Add comment to explain how everything
works. This comment will be improved while implementing the yet missing
parts.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diff:
---
winsup/cygwin/fhandler.h | 18 ++
winsup/cygwin/fhandler_socket_unix.cc | 563 ++++++++++++++++++++++++++++------
2 files changed, 493 insertions(+), 88 deletions(-)
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index cfd93d2..ec9294a 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -848,6 +848,24 @@ class sun_name_t
class fhandler_socket_unix : public fhandler_socket
{
protected:
+ HANDLE file; /* Either NT symlink or reparse point */
+
+ HANDLE create_abstract_link (const sun_name_t *sun,
+ PUNICODE_STRING pipe_name);
+ HANDLE create_reparse_point (const sun_name_t *sun,
+ PUNICODE_STRING pipe_name);
+ HANDLE create_file (const sun_name_t *sun);
+ int open_abstract_link (sun_name_t *sun, PUNICODE_STRING pipe_name);
+ int open_reparse_point (sun_name_t *sun, PUNICODE_STRING pipe_name);
+ int open_file (sun_name_t *sun, int &type, PUNICODE_STRING pipe_name);
+ HANDLE autobind (sun_name_t *sun);
+ wchar_t get_type_char ();
+ void gen_pipe_name ();
+ void set_wait_state (DWORD wait_state);
+ HANDLE create_pipe ();
+ HANDLE create_pipe_instance ();
+
+ protected:
sun_name_t *sun_path;
sun_name_t *peer_sun_path;
sun_name_t *get_sun_path () {return sun_path;}
diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc
index ee43b1f..359593c 100644
--- a/winsup/cygwin/fhandler_socket_unix.cc
+++ b/winsup/cygwin/fhandler_socket_unix.cc
@@ -21,19 +21,47 @@
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
+#include "cygheap.h"
#include "hires.h"
#include "shared_info.h"
#include "ntdll.h"
#include "miscfuncs.h"
#include "tls_pbuf.h"
+/*
+ Abstract socket:
+ An abstract socket is represented by a symlink in the native
+ NT namespace, within the Cygin subdir in BasedNamedObjects.
+ So it's globally available but only exists as long as at least on
+ descriptor on the socket is open, as desired.
+
+ The name of the symlink is: "af-unix-<sun_path>"
+
+ <sun_path> is the transposed sun_path string, including the leading
+ NUL. The transposition is simplified in that it uses every byte
+ in the valid sun_path name as is, no extra multibyte conversion.
+ The content of the symlink is the name of the underlying pipe.
+
+ Named socket:
+
+ A named socket is represented by a reparse point with a Cygwin-specific
+ tag and GUID. The GenericReparseBuffer content is the name of the
+ underlying pipe.
+
+ Pipe:
+
+ The pipe is named \\.\pipe\cygwin-<installation_key>-unix-[sd]-<uniq_id>
+
+ - <installation_key> is the 8 byte hex Cygwin installation key
+ - [sd] is s for SOCK_STREAM, d for SOCK_DGRAM
+ - <uniq_id> is an 8 byte hex unique number
+
+ Note: We use MAX_PATH here for convenience where sufficient. It's
+ big enough to hold sun_path's as well as pipe names so we don't have
+ to use tmp_pathbuf as often.
+*/
-/* 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)
GUID __cygwin_socket_guid = {
.Data1 = 0xefc1714d,
.Data2 = 0x7b19,
@@ -42,120 +70,441 @@ GUID __cygwin_socket_guid = {
};
HANDLE
+fhandler_socket_unix::create_abstract_link (const sun_name_t *sun,
+ PUNICODE_STRING pipe_name)
{
- /* 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')
+ WCHAR name[MAX_PATH];
+ OBJECT_ATTRIBUTES attr;
+ NTSTATUS status;
+ UNICODE_STRING uname;
+ HANDLE fh = NULL;
+
+ PWCHAR p = wcpcpy (name, L"af-unix-");
+ /* NUL bytes have no special meaning in an abstract socket name, so
+ we assume iso-8859-1 for simplicity and transpose the string.
+ transform_chars_af_unix is doing just that. */
+ transform_chars_af_unix (p, sun->un.sun_path, sun->un_len);
+ RtlInitUnicodeString (&uname, name);
+ InitializeObjectAttributes (&attr, &uname, OBJ_CASE_INSENSITIVE,
+ get_shared_parent_dir (), NULL);
+ /* Fill symlink with name of pipe */
+ status = NtCreateSymbolicLinkObject (&fh, SYMBOLIC_LINK_ALL_ACCESS,
+ &attr, pipe_name);
+ if (!NT_SUCCESS (status))
{
- /* TODO */
- return 0;
+ if (status == STATUS_OBJECT_NAME_EXISTS
+ || status == STATUS_OBJECT_NAME_COLLISION)
+ set_errno (EADDRINUSE);
+ else
+ __seterrno_from_nt_status (status);
}
+ return fh;
+}
+
+struct rep_pipe_name_t
+{
+ USHORT Length;
+ WCHAR PipeName[1];
+};
+
+HANDLE
+fhandler_socket_unix::create_reparse_point (const sun_name_t *sun,
+ PUNICODE_STRING pipe_name)
+{
+ ULONG access;
+ HANDLE old_trans = NULL, trans = NULL;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE fh = NULL;
+ PREPARSE_GUID_DATA_BUFFER rp;
+ rep_pipe_name_t *rep_pipe_name;
- path_conv pc (in->sa_data, PC_SYM_FOLLOW);
+ const DWORD data_len = sizeof (*rep_pipe_name) + pipe_name->Length;
+
+ path_conv pc (sun->un.sun_path, PC_SYM_FOLLOW);
if (pc.error)
{
set_errno (pc.error);
- return -1;
+ return NULL;
}
- if (!pc.exists ())
+ if (pc.exists ())
{
- set_errno (ENOENT);
+ set_errno (EADDRINUSE);
+ return NULL;
+ }
+ /* We will overwrite the DACL after the call to NtCreateFile. This
+ requires READ_CONTROL and WRITE_DAC access, otherwise get_file_sd
+ and set_file_sd both have to open the file again.
+ FIXME: On remote NTFS shares open sometimes fails because even the
+ creator of the file doesn't have the right to change the DACL.
+ I don't know what setting that is or how to recognize such a share,
+ so for now we don't request WRITE_DAC on remote drives. */
+ access = DELETE | FILE_GENERIC_WRITE;
+ if (!pc.isremote ())
+ access |= READ_CONTROL | WRITE_DAC | WRITE_OWNER;
+ if ((pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
+ start_transaction (old_trans, trans);
+
+retry_after_transaction_error:
+ status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE,
+ pc.get_object_attr (attr, sec_none_nih), &io,
+ NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_NON_DIRECTORY_FILE
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_OPEN_REPARSE_POINT,
+ NULL, 0);
+ if (NT_TRANSACTIONAL_ERROR (status) && trans)
+ {
+ stop_transaction (status, old_trans, trans);
+ goto retry_after_transaction_error;
+ }
+
+ if (!NT_SUCCESS (status))
+ {
+ if (io.Information == FILE_EXISTS)
+ set_errno (EADDRINUSE);
+ else
+ __seterrno_from_nt_status (status);
+ goto out;
+ }
+ rp = (PREPARSE_GUID_DATA_BUFFER)
+ alloca (REPARSE_GUID_DATA_BUFFER_HEADER_SIZE + data_len);
+ rp->ReparseTag = IO_REPARSE_TAG_CYGUNIX;
+ rp->ReparseDataLength = data_len;
+ rp->Reserved = 0;
+ memcpy (&rp->ReparseGuid, CYGWIN_SOCKET_GUID, sizeof (GUID));
+ rep_pipe_name = (rep_pipe_name_t *) rp->GenericReparseBuffer.DataBuffer;
+ rep_pipe_name->Length = pipe_name->Length;
+ memcpy (rep_pipe_name->PipeName, pipe_name->Buffer, pipe_name->Length);
+ rep_pipe_name->PipeName[pipe_name->Length / sizeof (WCHAR)] = L'\0';
+ status = NtFsControlFile (fh, NULL, NULL, NULL, &io,
+ FSCTL_SET_REPARSE_POINT, rp,
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE
+ + rp->ReparseDataLength, NULL, 0);
+ if (NT_SUCCESS (status))
+ {
+ set_created_file_access (fh, pc, S_IRUSR | S_IWUSR
+ | S_IRGRP | S_IWGRP
+ | S_IROTH | S_IWOTH);
+ NtClose (fh);
+ /* We don't have to keep the file open, but the caller needs to
+ get a value != NULL to know the file creation went fine. */
+ fh = INVALID_HANDLE_VALUE;
+ }
+ else if (!trans)
+ {
+ FILE_DISPOSITION_INFORMATION fdi = { TRUE };
+
+ __seterrno_from_nt_status (status);
+ status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
+ FileDispositionInformation);
+ if (!NT_SUCCESS (status))
+ debug_printf ("Setting delete dispostion failed, status = %y",
+ status);
+ NtClose (fh);
+ fh = NULL;
+ }
+
+out:
+ if (trans)
+ stop_transaction (status, old_trans, trans);
+ return fh;
+}
+
+HANDLE
+fhandler_socket_unix::create_file (const sun_name_t *sun)
+{
+ if (sun->un_len <= (socklen_t) sizeof (sa_family_t)
+ || (sun->un_len == 3 && sun->un.sun_path[0] == '\0')
+ || sun->un_len > (socklen_t) sizeof sun->un)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ if (sun->un.sun_path[0] == '\0')
+ return create_abstract_link (sun, pc.get_nt_native_path ());
+ return create_reparse_point (sun, pc.get_nt_native_path ());
+}
+
+int
+fhandler_socket_unix::open_abstract_link (sun_name_t *sun,
+ PUNICODE_STRING pipe_name)
+{
+ WCHAR name[MAX_PATH];
+ OBJECT_ATTRIBUTES attr;
+ NTSTATUS status;
+ UNICODE_STRING uname;
+ HANDLE fh;
+
+ PWCHAR p = wcpcpy (name, L"af-unix-");
+ p = transform_chars_af_unix (p, sun->un.sun_path, sun->un_len);
+ *p = L'\0';
+ RtlInitUnicodeString (&uname, name);
+ InitializeObjectAttributes (&attr, &uname, OBJ_CASE_INSENSITIVE,
+ get_shared_parent_dir (), NULL);
+ status = NtOpenSymbolicLinkObject (&fh, SYMBOLIC_LINK_QUERY, &attr);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
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. */
+ if (pipe_name)
+ status = NtQuerySymbolicLinkObject (fh, pipe_name, NULL);
+ NtClose (fh);
+ if (pipe_name)
+ {
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ /* Enforce NUL-terminated pipe name. */
+ pipe_name->Buffer[pipe_name->Length / sizeof (WCHAR)] = L'\0';
+ }
+ return 0;
+}
+
+int
+fhandler_socket_unix::open_reparse_point (sun_name_t *sun,
+ PUNICODE_STRING pipe_name)
+{
+ /* TODO: Open reparse point and fetch type and pipe name */
NTSTATUS status;
HANDLE fh;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
+ PREPARSE_GUID_DATA_BUFFER rp;
+ tmp_pathbuf tp;
+ path_conv pc (sun->un.sun_path, PC_SYM_FOLLOW);
+ if (pc.error)
+ {
+ set_errno (pc.error);
+ return -1;
+ }
+ if (!pc.exists ())
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
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_NON_DIRECTORY_FILE
| FILE_OPEN_FOR_BACKUP_INTENT
- | FILE_NON_DIRECTORY_FILE);
+ | FILE_OPEN_REPARSE_POINT);
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 ();
- }
+ {
+ /* 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;
- }
+ {
+ __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);
+ rp = (PREPARSE_GUID_DATA_BUFFER) tp.c_get ();
+ status = NtFsControlFile (fh, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
+ NULL, 0, rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
NtClose (fh);
- if (NT_SUCCESS (status))
+ if (rp->ReparseTag == IO_REPARSE_TAG_CYGUNIX
+ && memcmp (CYGWIN_SOCKET_GUID, &rp->ReparseGuid, sizeof (GUID)) == 0)
{
-#if 0 /* TODO */
- struct sockaddr_in sin;
- char ctype;
- sin.sin_family = AF_INET;
- if (strncmp (buf, SOCKET_COOKIE, strlen (SOCKET_COOKIE)))
+ if (pipe_name)
{
- set_errno (EBADF);
- return -1;
+ rep_pipe_name_t *rep_pipe_name = (rep_pipe_name_t *)
+ rp->GenericReparseBuffer.DataBuffer;
+ pipe_name->Length = rep_pipe_name->Length;
+ /* pipe name in reparse point is NUL-terminated */
+ memcpy (pipe_name->Buffer, rep_pipe_name->PipeName,
+ rep_pipe_name->Length + sizeof (WCHAR));
}
- 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;
}
+int
+fhandler_socket_unix::open_file (sun_name_t *sun, int &type,
+ PUNICODE_STRING pipe_name)
+{
+ int ret = -1;
+
+ if (sun->un_len <= (socklen_t) sizeof (sa_family_t)
+ || (sun->un_len == 3 && sun->un.sun_path[0] == '\0')
+ || sun->un_len > (socklen_t) sizeof sun->un)
+ set_errno (EINVAL);
+ else if (sun->un.sun_path[0] == '\0')
+ ret = open_abstract_link (sun, pipe_name);
+ else
+ ret = open_reparse_point (sun, pipe_name);
+ if (!ret)
+ switch (pipe_name->Buffer[38])
+ {
+ case 'd':
+ type = SOCK_DGRAM;
+ break;
+ case 's':
+ type = SOCK_STREAM;
+ break;
+ default:
+ set_errno (EINVAL);
+ ret = -1;
+ break;
+ }
+ return ret;
+}
+
+HANDLE
+fhandler_socket_unix::autobind (sun_name_t* sun)
+{
+ uint32_t id;
+ HANDLE fh;
+
+ do
+ {
+ /* Use only 5 hex digits (up to 2^20 sockets) for Linux compat */
+ set_unique_id ();
+ id = get_unique_id () & 0xfffff;
+ sun->un.sun_path[0] = '\0';
+ sun->un_len = sizeof (sa_family_t)
+ + 1 /* leading NUL */
+ + __small_sprintf (sun->un.sun_path + 1, "%5X", id);
+ }
+ while ((fh = create_abstract_link (sun, pc.get_nt_native_path ())) == NULL);
+ return fh;
+}
+
+wchar_t
+fhandler_socket_unix::get_type_char ()
+{
+ switch (get_socket_type ())
+ {
+ case SOCK_STREAM:
+ return 's';
+ case SOCK_DGRAM:
+ return 'd';
+ default:
+ return '?';
+ }
+}
+
+void
+fhandler_socket_unix::gen_pipe_name ()
+{
+ WCHAR pipe_name_buf[MAX_PATH];
+ UNICODE_STRING pipe_name;
+
+ __small_swprintf (pipe_name_buf,
+ L"\\Device\\NamedPipe\\cygwin-%S-unix-%C-%016_X",
+ &cygheap->installation_key,
+ get_type_char (),
+ get_plain_ino ());
+ RtlInitUnicodeString (&pipe_name, pipe_name_buf);
+ pc.set_nt_native_path (&pipe_name);
+}
+
+void
+fhandler_socket_unix::set_wait_state (DWORD wait_state)
+{
+ if (get_handle ())
+ {
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ FILE_PIPE_INFORMATION fpi;
+
+ fpi.ReadMode = FILE_PIPE_MESSAGE_MODE;
+ fpi.CompletionMode = wait_state;
+ status = NtSetInformationFile (get_handle (), &io, &fpi, sizeof fpi,
+ FilePipeInformation);
+ if (!NT_SUCCESS (status))
+ system_printf ("NtSetInformationFile(FilePipeInformation): %y", status);
+ }
+}
+
+HANDLE
+fhandler_socket_unix::create_pipe ()
+{
+ NTSTATUS status;
+ HANDLE ph;
+ ACCESS_MASK access;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ ULONG sharing;
+ ULONG nonblocking;
+ ULONG max_instances;
+ LARGE_INTEGER timeout;
+
+ access = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
+ sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ InitializeObjectAttributes (&attr, pc.get_nt_native_path (), OBJ_INHERIT,
+ NULL, NULL);
+ nonblocking = is_nonblocking () ? FILE_PIPE_COMPLETE_OPERATION
+ : FILE_PIPE_QUEUE_OPERATION;
+ max_instances = (get_socket_type () == SOCK_DGRAM) ? 1 : -1;
+ timeout.QuadPart = -500000;
+ status = NtCreateNamedPipeFile (&ph, access, &attr, &io, sharing,
+ FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_PIPE_MESSAGE_TYPE,
+ FILE_PIPE_MESSAGE_MODE,
+ nonblocking, max_instances,
+ PREFERRED_IO_BLKSIZE, PREFERRED_IO_BLKSIZE,
+ &timeout);
+ if (!NT_SUCCESS (status))
+ system_printf ("NtCreateNamedPipeFile: %y", status);
+ return ph;
+}
+
+HANDLE
+fhandler_socket_unix::create_pipe_instance ()
+{
+ NTSTATUS status;
+ HANDLE ph;
+ ACCESS_MASK access;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ ULONG sharing;
+ ULONG nonblocking;
+ ULONG max_instances;
+ LARGE_INTEGER timeout;
+
+ access = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
+ sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ InitializeObjectAttributes (&attr, pc.get_nt_native_path (), OBJ_INHERIT,
+ NULL, NULL);
+ nonblocking = is_nonblocking () ? FILE_PIPE_COMPLETE_OPERATION
+ : FILE_PIPE_QUEUE_OPERATION;
+ max_instances = (get_socket_type () == SOCK_DGRAM) ? 1 : -1;
+ timeout.QuadPart = -500000;
+ status = NtCreateNamedPipeFile (&ph, access, &attr, &io, sharing,
+ FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_PIPE_MESSAGE_TYPE,
+ FILE_PIPE_MESSAGE_MODE,
+ nonblocking, max_instances,
+ PREFERRED_IO_BLKSIZE, PREFERRED_IO_BLKSIZE,
+ &timeout);
+ if (!NT_SUCCESS (status))
+ system_printf ("NtCreateNamedPipeFile: %y", status);
+ return ph;
+}
+
fhandler_socket_unix::fhandler_socket_unix () :
sun_path (NULL),
peer_sun_path (NULL)
@@ -218,8 +567,16 @@ fhandler_socket_unix::socket (int af, int type, int protocol, int flags)
set_errno (EPROTONOSUPPORT);
return -1;
}
- set_errno (EAFNOSUPPORT);
- return -1;
+ set_addr_family (af);
+ set_socket_type (type);
+ if (flags & SOCK_NONBLOCK)
+ set_nonblocking (true);
+ if (flags & SOCK_CLOEXEC)
+ set_close_on_exec (true);
+ set_io_handle (NULL);
+ set_unique_id ();
+ set_ino (get_unique_id ());
+ return 0;
}
int
@@ -243,7 +600,34 @@ fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags,
int
fhandler_socket_unix::bind (const struct sockaddr *name, int namelen)
{
- set_errno (EAFNOSUPPORT);
+ __try
+ {
+ sun_name_t sun (name, namelen);
+ bool unnamed = (sun.un_len == sizeof sun.un.sun_family);
+ HANDLE pipe = NULL;
+
+ if (get_handle ())
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ gen_pipe_name ();
+ pipe = create_pipe ();
+ if (pipe)
+ {
+ file = unnamed ? autobind (&sun) : create_file (&sun);
+ if (!file)
+ {
+ NtClose (pipe);
+ __leave;
+ }
+ set_io_handle (pipe);
+ set_sun_path (&sun);
+ return 0;
+ }
+ }
+ __except (EFAULT) {}
+ __endtry
return -1;
}
@@ -312,8 +696,11 @@ fhandler_socket_unix::shutdown (int how)
int
fhandler_socket_unix::close ()
{
- set_errno (EAFNOSUPPORT);
- return -1;
+ if (get_handle ())
+ NtClose (get_handle ());
+ if (file && file != INVALID_HANDLE_VALUE)
+ NtClose (file);
+ return 0;
}
int