Add support for sockaddr_un
on Windows. (#6513)
* Windows: Fix warning about undefined if_indextoname() * Windows: Fix UNIXSocket on MINGW and make .pair more reliable * Windows: Use nonblock=true for read tests with scheduler * Windows: Move socket detection from File.socket? to File.stat Add S_IFSOCK to Windows and interpret reparse points accordingly. Enable tests that work now. * Windows: Use wide-char functions to UNIXSocket This fixes behaviour with non-ASCII characters. It also fixes deletion of temporary UNIXSocket.pair files. * Windows: Add UNIXSocket tests for specifics of Windows impl. * Windows: fix VC build due to missing _snwprintf Avoid usage of _snwprintf, since it fails linking ruby.dll like so: linking shared-library x64-vcruntime140-ruby320.dll x64-vcruntime140-ruby320.def : error LNK2001: unresolved external symbol snwprintf x64-vcruntime140-ruby320.def : error LNK2001: unresolved external symbol vsnwprintf_l whereas linking miniruby.exe succeeds. This patch uses snprintf on the UTF-8 string instead. Also remove branch GetWindowsDirectoryW, since it doesn't work. * Windows: Fix dangling symlink test failures Co-authored-by: Lars Kanis <kanis@comcard.de>
This commit is contained in:
parent
4e4b29b1a9
commit
ea8a7287e2
Notes:
git
2022-11-17 22:50:45 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
9
NEWS.md
9
NEWS.md
@ -103,7 +103,8 @@ Note that each entry is kept to a minimum, see links for details.
|
|||||||
Note: We're only listing outstanding class updates.
|
Note: We're only listing outstanding class updates.
|
||||||
|
|
||||||
* Fiber::Scheduler
|
* Fiber::Scheduler
|
||||||
* Introduce `Fiber::Scheduler#io_select` for non-blocking `IO.select`. [[Feature #19060]]
|
* Introduce `Fiber::Scheduler#io_select` for non-blocking `IO.select`.
|
||||||
|
[[Feature #19060]]
|
||||||
|
|
||||||
* IO
|
* IO
|
||||||
* Introduce `IO#timeout=` and `IO#timeout` which can cause
|
* Introduce `IO#timeout=` and `IO#timeout` which can cause
|
||||||
@ -115,6 +116,11 @@ Note: We're only listing outstanding class updates.
|
|||||||
STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
|
STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* UNIXSocket
|
||||||
|
* Add support for UNIXSocket on Windows. Emulate anonymous sockets. Add
|
||||||
|
support for `File.socket?` and `File::Stat#socket?` where possible.
|
||||||
|
[[Feature #19135]]
|
||||||
|
|
||||||
* Class
|
* Class
|
||||||
* `Class#attached_object`, which returns the object for which
|
* `Class#attached_object`, which returns the object for which
|
||||||
the receiver is the singleton class. Raises `TypeError` if the
|
the receiver is the singleton class. Raises `TypeError` if the
|
||||||
@ -417,3 +423,4 @@ The following deprecated APIs are removed.
|
|||||||
[Feature #19026]: https://bugs.ruby-lang.org/issues/19026
|
[Feature #19026]: https://bugs.ruby-lang.org/issues/19026
|
||||||
[Feature #19060]: https://bugs.ruby-lang.org/issues/19060
|
[Feature #19060]: https://bugs.ruby-lang.org/issues/19060
|
||||||
[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
|
[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
|
||||||
|
[Feature #19135]: https://bugs.ruby-lang.org/issues/19135
|
||||||
|
@ -1283,6 +1283,11 @@ dnl AC_HEADER_STDC has been checked in AC_USE_SYSTEM_EXTENSIONS
|
|||||||
AC_HEADER_STDBOOL
|
AC_HEADER_STDBOOL
|
||||||
AC_HEADER_SYS_WAIT
|
AC_HEADER_SYS_WAIT
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS([afunix.h], [], [],
|
||||||
|
[#ifdef _WIN32
|
||||||
|
# include <winsock2.h>
|
||||||
|
#endif
|
||||||
|
])
|
||||||
AC_CHECK_HEADERS(atomic.h)
|
AC_CHECK_HEADERS(atomic.h)
|
||||||
AC_CHECK_HEADERS(copyfile.h)
|
AC_CHECK_HEADERS(copyfile.h)
|
||||||
AC_CHECK_HEADERS(direct.h)
|
AC_CHECK_HEADERS(direct.h)
|
||||||
|
@ -316,6 +316,7 @@ end
|
|||||||
netpacket/packet.h
|
netpacket/packet.h
|
||||||
net/ethernet.h
|
net/ethernet.h
|
||||||
sys/un.h
|
sys/un.h
|
||||||
|
afunix.h
|
||||||
ifaddrs.h
|
ifaddrs.h
|
||||||
sys/ioctl.h
|
sys/ioctl.h
|
||||||
sys/sockio.h
|
sys/sockio.h
|
||||||
|
@ -209,7 +209,7 @@ rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from)
|
|||||||
else
|
else
|
||||||
return rb_assoc_new(str, Qnil);
|
return rb_assoc_new(str, Qnil);
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case RECV_UNIX:
|
case RECV_UNIX:
|
||||||
return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen));
|
return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen));
|
||||||
#endif
|
#endif
|
||||||
|
@ -197,7 +197,7 @@ class Addrinfo
|
|||||||
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
|
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
|
||||||
begin
|
begin
|
||||||
sock.ipv6only! if self.ipv6?
|
sock.ipv6only! if self.ipv6?
|
||||||
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
|
sock.setsockopt(:SOCKET, :REUSEADDR, 1) unless self.pfamily == Socket::PF_UNIX
|
||||||
sock.bind(self)
|
sock.bind(self)
|
||||||
sock.listen(backlog)
|
sock.listen(backlog)
|
||||||
rescue Exception
|
rescue Exception
|
||||||
|
@ -670,10 +670,10 @@ rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int
|
|||||||
{
|
{
|
||||||
#if defined(HAVE_IF_INDEXTONAME)
|
#if defined(HAVE_IF_INDEXTONAME)
|
||||||
char ifbuf[IFNAMSIZ];
|
char ifbuf[IFNAMSIZ];
|
||||||
if (if_indextoname(ifindex, ifbuf) == NULL)
|
if (if_indextoname(ifindex, ifbuf))
|
||||||
return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
|
|
||||||
else
|
|
||||||
return snprintf(buf, len, "%s%s", succ_prefix, ifbuf);
|
return snprintf(buf, len, "%s%s", succ_prefix, ifbuf);
|
||||||
|
else
|
||||||
|
return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
|
||||||
#else
|
#else
|
||||||
# ifndef IFNAMSIZ
|
# ifndef IFNAMSIZ
|
||||||
# define IFNAMSIZ (sizeof(unsigned int)*3+1)
|
# define IFNAMSIZ (sizeof(unsigned int)*3+1)
|
||||||
@ -1229,7 +1229,7 @@ sockopt_inspect(VALUE self)
|
|||||||
else
|
else
|
||||||
rb_str_catf(ret, " optname:%d", optname);
|
rb_str_catf(ret, " optname:%d", optname);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
else if (family == AF_UNIX) {
|
else if (family == AF_UNIX) {
|
||||||
rb_str_catf(ret, " level:%d", level);
|
rb_str_catf(ret, " level:%d", level);
|
||||||
|
|
||||||
@ -1393,7 +1393,7 @@ sockopt_inspect(VALUE self)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -644,7 +644,7 @@ rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
|
|||||||
return ary;
|
return ary;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
static long
|
static long
|
||||||
unixsocket_len(const struct sockaddr_un *su, socklen_t socklen)
|
unixsocket_len(const struct sockaddr_un *su, socklen_t socklen)
|
||||||
{
|
{
|
||||||
@ -1017,7 +1017,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
static void
|
static void
|
||||||
init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
|
init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
|
||||||
{
|
{
|
||||||
@ -1146,7 +1146,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */
|
case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */
|
||||||
{
|
{
|
||||||
VALUE path = rb_ary_entry(sockaddr_ary, 1);
|
VALUE path = rb_ary_entry(sockaddr_ary, 1);
|
||||||
@ -1286,7 +1286,7 @@ rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE r
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
{
|
{
|
||||||
struct sockaddr_un *addr = &sockaddr->un;
|
struct sockaddr_un *addr = &sockaddr->un;
|
||||||
@ -1622,7 +1622,7 @@ addrinfo_mdump(VALUE self)
|
|||||||
afamily = rb_id2str(id);
|
afamily = rb_id2str(id);
|
||||||
|
|
||||||
switch(afamily_int) {
|
switch(afamily_int) {
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
{
|
{
|
||||||
sockaddr = rb_str_new(rai->addr.un.sun_path, rai_unixsocket_len(rai));
|
sockaddr = rb_str_new(rai->addr.un.sun_path, rai_unixsocket_len(rai));
|
||||||
@ -1715,7 +1715,7 @@ addrinfo_mload(VALUE self, VALUE ary)
|
|||||||
|
|
||||||
v = rb_ary_entry(ary, 1);
|
v = rb_ary_entry(ary, 1);
|
||||||
switch(afamily) {
|
switch(afamily) {
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
{
|
{
|
||||||
struct sockaddr_un uaddr;
|
struct sockaddr_un uaddr;
|
||||||
@ -2343,7 +2343,7 @@ addrinfo_ipv6_to_ipv4(VALUE self)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* addrinfo.unix_path => path
|
* addrinfo.unix_path => path
|
||||||
@ -2491,7 +2491,7 @@ addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
|
|||||||
INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
|
INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
@ -2629,7 +2629,7 @@ rsock_init_addrinfo(void)
|
|||||||
rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
|
rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
|
||||||
rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
|
rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
|
||||||
rb_define_singleton_method(rb_cAddrinfo, "udp", addrinfo_s_udp, 2);
|
rb_define_singleton_method(rb_cAddrinfo, "udp", addrinfo_s_udp, 2);
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
rb_define_singleton_method(rb_cAddrinfo, "unix", addrinfo_s_unix, -1);
|
rb_define_singleton_method(rb_cAddrinfo, "unix", addrinfo_s_unix, -1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2670,7 +2670,7 @@ rsock_init_addrinfo(void)
|
|||||||
rb_define_method(rb_cAddrinfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0);
|
rb_define_method(rb_cAddrinfo, "ipv6_to_ipv4", addrinfo_ipv6_to_ipv4, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
rb_define_method(rb_cAddrinfo, "unix_path", addrinfo_unix_path, 0);
|
rb_define_method(rb_cAddrinfo, "unix_path", addrinfo_unix_path, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <ws2tcpip.h>
|
||||||
|
# include <iphlpapi.h>
|
||||||
# if defined(_MSC_VER)
|
# if defined(_MSC_VER)
|
||||||
# undef HAVE_TYPE_STRUCT_SOCKADDR_DL
|
# undef HAVE_TYPE_STRUCT_SOCKADDR_DL
|
||||||
# endif
|
# endif
|
||||||
@ -69,6 +72,11 @@
|
|||||||
# include <sys/un.h>
|
# include <sys/un.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_AFUNIX_H
|
||||||
|
// Windows doesn't have sys/un.h, but it does have afunix.h just to be special:
|
||||||
|
# include <afunix.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_FCNTL)
|
#if defined(HAVE_FCNTL)
|
||||||
# ifdef HAVE_SYS_SELECT_H
|
# ifdef HAVE_SYS_SELECT_H
|
||||||
# include <sys/select.h>
|
# include <sys/select.h>
|
||||||
@ -268,7 +276,7 @@ extern VALUE rb_cIPSocket;
|
|||||||
extern VALUE rb_cTCPSocket;
|
extern VALUE rb_cTCPSocket;
|
||||||
extern VALUE rb_cTCPServer;
|
extern VALUE rb_cTCPServer;
|
||||||
extern VALUE rb_cUDPSocket;
|
extern VALUE rb_cUDPSocket;
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
extern VALUE rb_cUNIXSocket;
|
extern VALUE rb_cUNIXSocket;
|
||||||
extern VALUE rb_cUNIXServer;
|
extern VALUE rb_cUNIXServer;
|
||||||
#endif
|
#endif
|
||||||
@ -336,7 +344,7 @@ VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len);
|
|||||||
|
|
||||||
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup);
|
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup);
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
VALUE rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len);
|
VALUE rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len);
|
||||||
VALUE rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len);
|
VALUE rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len);
|
||||||
socklen_t rsock_unix_sockaddr_len(VALUE path);
|
socklen_t rsock_unix_sockaddr_len(VALUE path);
|
||||||
|
@ -1383,7 +1383,7 @@ sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
|
|||||||
return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
|
return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
@ -1471,7 +1471,7 @@ sockaddr_len(struct sockaddr *addr)
|
|||||||
return (socklen_t)sizeof(struct sockaddr_in6);
|
return (socklen_t)sizeof(struct sockaddr_in6);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
return (socklen_t)sizeof(struct sockaddr_un);
|
return (socklen_t)sizeof(struct sockaddr_un);
|
||||||
#endif
|
#endif
|
||||||
@ -2020,7 +2020,7 @@ Init_socket(void)
|
|||||||
rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2);
|
rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2);
|
||||||
rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2);
|
rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2);
|
||||||
rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1);
|
rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1);
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1);
|
rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1);
|
||||||
rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1);
|
rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1);
|
||||||
rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1);
|
rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "rubysocket.h"
|
#include "rubysocket.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* UNIXServer.new(path) => unixserver
|
* UNIXServer.new(path) => unixserver
|
||||||
@ -101,7 +101,7 @@ unix_sysaccept(VALUE server)
|
|||||||
void
|
void
|
||||||
rsock_init_unixserver(void)
|
rsock_init_unixserver(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
/*
|
/*
|
||||||
* Document-class: UNIXServer < UNIXSocket
|
* Document-class: UNIXServer < UNIXSocket
|
||||||
*
|
*
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "rubysocket.h"
|
#include "rubysocket.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
struct unixsock_arg {
|
struct unixsock_arg {
|
||||||
struct sockaddr_un *sockaddr;
|
struct sockaddr_un *sockaddr;
|
||||||
socklen_t sockaddrlen;
|
socklen_t sockaddrlen;
|
||||||
@ -42,6 +42,10 @@ unixsock_path_value(VALUE path)
|
|||||||
return name; /* ignore encoding */
|
return name; /* ignore encoding */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* UNIXSocket requires UTF-8 per spec. */
|
||||||
|
path = rb_str_export_to_enc(path, rb_utf8_encoding());
|
||||||
#endif
|
#endif
|
||||||
return rb_get_path(path);
|
return rb_get_path(path);
|
||||||
}
|
}
|
||||||
@ -571,7 +575,7 @@ unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
|
|||||||
void
|
void
|
||||||
rsock_init_unixsocket(void)
|
rsock_init_unixsocket(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
/*
|
/*
|
||||||
* Document-class: UNIXSocket < BasicSocket
|
* Document-class: UNIXSocket < BasicSocket
|
||||||
*
|
*
|
||||||
|
3
file.c
3
file.c
@ -1765,8 +1765,8 @@ rb_file_socket_p(VALUE obj, VALUE fname)
|
|||||||
|
|
||||||
if (rb_stat(fname, &st) < 0) return Qfalse;
|
if (rb_stat(fname, &st) < 0) return Qfalse;
|
||||||
if (S_ISSOCK(st.st_mode)) return Qtrue;
|
if (S_ISSOCK(st.st_mode)) return Qtrue;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return Qfalse;
|
return Qfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5600,6 +5600,7 @@ rb_stat_init(VALUE obj, VALUE fname)
|
|||||||
if (STAT(StringValueCStr(fname), &st) == -1) {
|
if (STAT(StringValueCStr(fname), &st) == -1) {
|
||||||
rb_sys_fail_path(fname);
|
rb_sys_fail_path(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DATA_PTR(obj)) {
|
if (DATA_PTR(obj)) {
|
||||||
xfree(DATA_PTR(obj));
|
xfree(DATA_PTR(obj));
|
||||||
DATA_PTR(obj) = NULL;
|
DATA_PTR(obj) = NULL;
|
||||||
|
@ -18,11 +18,6 @@ RUBY_SYMBOL_EXPORT_BEGIN
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Definitions for NT port of Perl
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ok now we can include the normal include files.
|
* Ok now we can include the normal include files.
|
||||||
*/
|
*/
|
||||||
@ -392,6 +387,7 @@ scalb(double a, long b)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define S_IFLNK 0xa000
|
#define S_IFLNK 0xa000
|
||||||
|
#define S_IFSOCK 0xc000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* define this so we can do inplace editing
|
* define this so we can do inplace editing
|
||||||
|
@ -10,12 +10,6 @@ class TestFiberEnumerator < Test::Unit::TestCase
|
|||||||
|
|
||||||
i, o = UNIXSocket.pair
|
i, o = UNIXSocket.pair
|
||||||
|
|
||||||
unless i.nonblock? && o.nonblock?
|
|
||||||
i.close
|
|
||||||
o.close
|
|
||||||
omit "I/O is not non-blocking!"
|
|
||||||
end
|
|
||||||
|
|
||||||
message = String.new
|
message = String.new
|
||||||
|
|
||||||
thread = Thread.new do
|
thread = Thread.new do
|
||||||
|
@ -6,14 +6,12 @@ class TestFiberIO < Test::Unit::TestCase
|
|||||||
MESSAGE = "Hello World"
|
MESSAGE = "Hello World"
|
||||||
|
|
||||||
def test_read
|
def test_read
|
||||||
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
|
omit unless defined?(UNIXSocket)
|
||||||
|
|
||||||
i, o = UNIXSocket.pair
|
i, o = UNIXSocket.pair
|
||||||
|
if RUBY_PLATFORM=~/mswin|mingw/
|
||||||
unless i.nonblock? && o.nonblock?
|
i.nonblock = true
|
||||||
i.close
|
o.nonblock = true
|
||||||
o.close
|
|
||||||
omit "I/O is not non-blocking!"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
message = nil
|
message = nil
|
||||||
@ -46,6 +44,10 @@ class TestFiberIO < Test::Unit::TestCase
|
|||||||
16.times.map do
|
16.times.map do
|
||||||
Thread.new do
|
Thread.new do
|
||||||
i, o = UNIXSocket.pair
|
i, o = UNIXSocket.pair
|
||||||
|
if RUBY_PLATFORM=~/mswin|mingw/
|
||||||
|
i.nonblock = true
|
||||||
|
o.nonblock = true
|
||||||
|
end
|
||||||
|
|
||||||
scheduler = Scheduler.new
|
scheduler = Scheduler.new
|
||||||
Fiber.set_scheduler scheduler
|
Fiber.set_scheduler scheduler
|
||||||
@ -64,16 +66,11 @@ class TestFiberIO < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_epipe_on_read
|
def test_epipe_on_read
|
||||||
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
|
omit unless defined?(UNIXSocket)
|
||||||
|
omit "nonblock=true isn't properly supported on Windows" if RUBY_PLATFORM=~/mswin|mingw/
|
||||||
|
|
||||||
i, o = UNIXSocket.pair
|
i, o = UNIXSocket.pair
|
||||||
|
|
||||||
unless i.nonblock? && o.nonblock?
|
|
||||||
i.close
|
|
||||||
o.close
|
|
||||||
omit "I/O is not non-blocking!"
|
|
||||||
end
|
|
||||||
|
|
||||||
error = nil
|
error = nil
|
||||||
|
|
||||||
thread = Thread.new do
|
thread = Thread.new do
|
||||||
|
@ -472,10 +472,14 @@ class TestFileUtils < Test::Unit::TestCase
|
|||||||
else
|
else
|
||||||
def test_cp_r_socket
|
def test_cp_r_socket
|
||||||
pend "Skipping socket test on JRuby" if RUBY_ENGINE == 'jruby'
|
pend "Skipping socket test on JRuby" if RUBY_ENGINE == 'jruby'
|
||||||
|
|
||||||
Dir.mkdir('tmp/cpr_src')
|
Dir.mkdir('tmp/cpr_src')
|
||||||
UNIXServer.new('tmp/cpr_src/socket').close
|
UNIXServer.new('tmp/cpr_src/socket').close
|
||||||
cp_r 'tmp/cpr_src', 'tmp/cpr_dest'
|
cp_r 'tmp/cpr_src', 'tmp/cpr_dest'
|
||||||
assert_equal(true, File.socket?('tmp/cpr_dest/socket'))
|
assert_equal(true, File.socket?('tmp/cpr_dest/socket'))
|
||||||
|
rescue Errno::EINVAL => error
|
||||||
|
# On some platforms (windows) sockets cannot be copied by FileUtils.
|
||||||
|
omit error.message
|
||||||
end if defined?(UNIXServer)
|
end if defined?(UNIXServer)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -649,7 +649,7 @@ class TestFileExhaustive < Test::Unit::TestCase
|
|||||||
# ignore unsupporting filesystems
|
# ignore unsupporting filesystems
|
||||||
rescue Errno::EPERM
|
rescue Errno::EPERM
|
||||||
# Docker prohibits statx syscall by the default.
|
# Docker prohibits statx syscall by the default.
|
||||||
skip("statx(2) is prohibited by seccomp")
|
omit("statx(2) is prohibited by seccomp")
|
||||||
end
|
end
|
||||||
assert_raise(Errno::ENOENT) { File.birthtime(nofile) }
|
assert_raise(Errno::ENOENT) { File.birthtime(nofile) }
|
||||||
end if File.respond_to?(:birthtime)
|
end if File.respond_to?(:birthtime)
|
||||||
|
@ -900,6 +900,10 @@ class TestIO < Test::Unit::TestCase
|
|||||||
end if defined? UNIXSocket
|
end if defined? UNIXSocket
|
||||||
|
|
||||||
def test_copy_stream_socket4
|
def test_copy_stream_socket4
|
||||||
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
||||||
|
omit "pread(2) is not implemented."
|
||||||
|
end
|
||||||
|
|
||||||
with_bigsrc {|bigsrc, bigcontent|
|
with_bigsrc {|bigsrc, bigcontent|
|
||||||
File.open(bigsrc) {|f|
|
File.open(bigsrc) {|f|
|
||||||
assert_equal(0, f.pos)
|
assert_equal(0, f.pos)
|
||||||
@ -916,9 +920,13 @@ class TestIO < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end if defined? UNIXSocket
|
end
|
||||||
|
|
||||||
def test_copy_stream_socket5
|
def test_copy_stream_socket5
|
||||||
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
||||||
|
omit "pread(2) is not implemented."
|
||||||
|
end
|
||||||
|
|
||||||
with_bigsrc {|bigsrc, bigcontent|
|
with_bigsrc {|bigsrc, bigcontent|
|
||||||
File.open(bigsrc) {|f|
|
File.open(bigsrc) {|f|
|
||||||
assert_equal(bigcontent[0,100], f.read(100))
|
assert_equal(bigcontent[0,100], f.read(100))
|
||||||
@ -936,9 +944,13 @@ class TestIO < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end if defined? UNIXSocket
|
end
|
||||||
|
|
||||||
def test_copy_stream_socket6
|
def test_copy_stream_socket6
|
||||||
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
||||||
|
omit "pread(2) is not implemented."
|
||||||
|
end
|
||||||
|
|
||||||
mkcdtmpdir {
|
mkcdtmpdir {
|
||||||
megacontent = "abc" * 1234567
|
megacontent = "abc" * 1234567
|
||||||
File.open("megasrc", "w") {|f| f << megacontent }
|
File.open("megasrc", "w") {|f| f << megacontent }
|
||||||
@ -959,9 +971,13 @@ class TestIO < Test::Unit::TestCase
|
|||||||
assert_equal(megacontent, result)
|
assert_equal(megacontent, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end if defined? UNIXSocket
|
end
|
||||||
|
|
||||||
def test_copy_stream_socket7
|
def test_copy_stream_socket7
|
||||||
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
||||||
|
omit "pread(2) is not implemented."
|
||||||
|
end
|
||||||
|
|
||||||
GC.start
|
GC.start
|
||||||
mkcdtmpdir {
|
mkcdtmpdir {
|
||||||
megacontent = "abc" * 1234567
|
megacontent = "abc" * 1234567
|
||||||
@ -996,7 +1012,7 @@ class TestIO < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end if defined? UNIXSocket and IO.method_defined?("nonblock=")
|
end
|
||||||
|
|
||||||
def test_copy_stream_strio
|
def test_copy_stream_strio
|
||||||
src = StringIO.new("abcd")
|
src = StringIO.new("abcd")
|
||||||
|
@ -9,12 +9,6 @@ class TestIOTimeout < Test::Unit::TestCase
|
|||||||
begin
|
begin
|
||||||
i, o = UNIXSocket.pair
|
i, o = UNIXSocket.pair
|
||||||
|
|
||||||
unless i.nonblock? && o.nonblock?
|
|
||||||
i.close
|
|
||||||
o.close
|
|
||||||
omit "I/O is not non-blocking!"
|
|
||||||
end
|
|
||||||
|
|
||||||
yield i, o
|
yield i, o
|
||||||
ensure
|
ensure
|
||||||
i.close
|
i.close
|
||||||
|
@ -307,11 +307,13 @@ class TestSocketNonblock < Test::Unit::TestCase
|
|||||||
loop { s1.sendmsg_nonblock(buf) }
|
loop { s1.sendmsg_nonblock(buf) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue NotImplementedError, Errno::ENOSYS, Errno::EPROTONOSUPPORT
|
rescue NotImplementedError, Errno::ENOSYS, Errno::EPROTONOSUPPORT, Errno::EPROTOTYPE
|
||||||
omit "UNIXSocket.pair(:SEQPACKET) not implemented on this platform: #{$!}"
|
omit "UNIXSocket.pair(:SEQPACKET) not implemented on this platform: #{$!}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_sendmsg_nonblock_no_exception
|
def test_sendmsg_nonblock_no_exception
|
||||||
|
omit "AF_UNIX + SEQPACKET is not supported on windows" if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
|
|
||||||
buf = '*' * 4096
|
buf = '*' * 4096
|
||||||
UNIXSocket.pair(:SEQPACKET) do |s1, s2|
|
UNIXSocket.pair(:SEQPACKET) do |s1, s2|
|
||||||
n = 0
|
n = 0
|
||||||
|
@ -60,6 +60,8 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||||||
assert_not_equal s1.fileno, r.fileno
|
assert_not_equal s1.fileno, r.fileno
|
||||||
r.close
|
r.close
|
||||||
end
|
end
|
||||||
|
rescue NotImplementedError => error
|
||||||
|
omit error.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_fd_passing_n
|
def test_fd_passing_n
|
||||||
@ -334,62 +336,70 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_noname_path
|
def test_noname_path
|
||||||
s1, s2 = UNIXSocket.pair
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
assert_equal("", s1.path)
|
omit "unnamed pipe is emulated on windows"
|
||||||
assert_equal("", s2.path)
|
end
|
||||||
ensure
|
|
||||||
s1.close
|
UNIXSocket.pair do |s1, s2|
|
||||||
s2.close
|
assert_equal("", s1.path)
|
||||||
|
assert_equal("", s2.path)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_noname_addr
|
def test_noname_addr
|
||||||
s1, s2 = UNIXSocket.pair
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
assert_equal(["AF_UNIX", ""], s1.addr)
|
omit "unnamed pipe is emulated on windows"
|
||||||
assert_equal(["AF_UNIX", ""], s2.addr)
|
end
|
||||||
ensure
|
|
||||||
s1.close
|
UNIXSocket.pair do |s1, s2|
|
||||||
s2.close
|
assert_equal(["AF_UNIX", ""], s1.addr)
|
||||||
|
assert_equal(["AF_UNIX", ""], s2.addr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_noname_peeraddr
|
def test_noname_peeraddr
|
||||||
s1, s2 = UNIXSocket.pair
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
assert_equal(["AF_UNIX", ""], s1.peeraddr)
|
omit "unnamed pipe is emulated on windows"
|
||||||
assert_equal(["AF_UNIX", ""], s2.peeraddr)
|
end
|
||||||
ensure
|
|
||||||
s1.close
|
UNIXSocket.pair do |s1, s2|
|
||||||
s2.close
|
assert_equal(["AF_UNIX", ""], s1.peeraddr)
|
||||||
|
assert_equal(["AF_UNIX", ""], s2.peeraddr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_noname_unpack_sockaddr_un
|
def test_noname_unpack_sockaddr_un
|
||||||
s1, s2 = UNIXSocket.pair
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
n = nil
|
omit "unnamed pipe is emulated on windows"
|
||||||
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != ""
|
end
|
||||||
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != ""
|
|
||||||
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getsockname) != ""
|
UNIXSocket.pair do |s1, s2|
|
||||||
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getpeername) != ""
|
n = nil
|
||||||
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getpeername) != ""
|
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != ""
|
||||||
ensure
|
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != ""
|
||||||
s1.close
|
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getsockname) != ""
|
||||||
s2.close
|
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getpeername) != ""
|
||||||
|
assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getpeername) != ""
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_noname_recvfrom
|
def test_noname_recvfrom
|
||||||
s1, s2 = UNIXSocket.pair
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
s2.write("a")
|
omit "unnamed pipe is emulated on windows"
|
||||||
assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom(10))
|
end
|
||||||
ensure
|
|
||||||
s1.close
|
UNIXSocket.pair do |s1, s2|
|
||||||
s2.close
|
s2.write("a")
|
||||||
|
assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom(10))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_noname_recv_nonblock
|
def test_noname_recv_nonblock
|
||||||
s1, s2 = UNIXSocket.pair
|
UNIXSocket.pair do |s1, s2|
|
||||||
s2.write("a")
|
s2.write("a")
|
||||||
IO.select [s1]
|
IO.select [s1]
|
||||||
assert_equal("a", s1.recv_nonblock(10))
|
assert_equal("a", s1.recv_nonblock(10))
|
||||||
ensure
|
end
|
||||||
s1.close
|
|
||||||
s2.close
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_too_long_path
|
def test_too_long_path
|
||||||
@ -429,12 +439,18 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||||||
rv = s1.recv(100, 0, buf)
|
rv = s1.recv(100, 0, buf)
|
||||||
assert_equal buf.object_id, rv.object_id
|
assert_equal buf.object_id, rv.object_id
|
||||||
assert_equal "BBBBBB", rv
|
assert_equal "BBBBBB", rv
|
||||||
|
rescue Errno::EPROTOTYPE => error
|
||||||
|
omit error.message
|
||||||
ensure
|
ensure
|
||||||
s1.close if s1
|
s1.close if s1
|
||||||
s2.close if s2
|
s2.close if s2
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dgram_pair_sendrecvmsg_errno_set
|
def test_dgram_pair_sendrecvmsg_errno_set
|
||||||
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
|
omit("AF_UNIX + SOCK_DGRAM is not supported on windows")
|
||||||
|
end
|
||||||
|
|
||||||
s1, s2 = to_close = UNIXSocket.pair(Socket::SOCK_DGRAM)
|
s1, s2 = to_close = UNIXSocket.pair(Socket::SOCK_DGRAM)
|
||||||
pipe = IO.pipe
|
pipe = IO.pipe
|
||||||
to_close.concat(pipe)
|
to_close.concat(pipe)
|
||||||
@ -457,9 +473,17 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_epipe # [ruby-dev:34619]
|
def test_epipe # [ruby-dev:34619]
|
||||||
|
# This is a good example of why reporting the exact `errno` is a terrible
|
||||||
|
# idea for platform abstractions.
|
||||||
|
if RUBY_PLATFORM =~ /mswin|mingw/
|
||||||
|
error = Errno::ESHUTDOWN
|
||||||
|
else
|
||||||
|
error = Errno::EPIPE
|
||||||
|
end
|
||||||
|
|
||||||
UNIXSocket.pair {|s1, s2|
|
UNIXSocket.pair {|s1, s2|
|
||||||
s1.shutdown(Socket::SHUT_WR)
|
s1.shutdown(Socket::SHUT_WR)
|
||||||
assert_raise(Errno::EPIPE) { s1.write "a" }
|
assert_raise(error) { s1.write "a" }
|
||||||
assert_equal(nil, s2.read(1))
|
assert_equal(nil, s2.read(1))
|
||||||
s2.write "a"
|
s2.write "a"
|
||||||
assert_equal("a", s1.read(1))
|
assert_equal("a", s1.read(1))
|
||||||
@ -493,6 +517,45 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if /mingw|mswin/ =~ RUBY_PLATFORM
|
||||||
|
|
||||||
|
def test_unix_socket_with_encoding
|
||||||
|
Dir.mktmpdir do |tmpdir|
|
||||||
|
path = "#{tmpdir}/sockäöü".encode("cp850")
|
||||||
|
UNIXServer.open(path) do |serv|
|
||||||
|
assert File.socket?(path)
|
||||||
|
assert File.stat(path).socket?
|
||||||
|
assert File.lstat(path).socket?
|
||||||
|
assert_equal path.encode("utf-8"), serv.path
|
||||||
|
UNIXSocket.open(path) do |s1|
|
||||||
|
s2 = serv.accept
|
||||||
|
s2.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_windows_unix_socket_pair_with_umlaut
|
||||||
|
otmp = ENV['TMP']
|
||||||
|
ENV['TMP'] = File.join(Dir.tmpdir, "äöü€")
|
||||||
|
FileUtils.mkdir_p ENV['TMP']
|
||||||
|
|
||||||
|
s1, s2 = UNIXSocket.pair
|
||||||
|
assert !s1.path.empty?
|
||||||
|
assert !File.exist?(s1.path)
|
||||||
|
ensure
|
||||||
|
FileUtils.rm_rf ENV['TMP']
|
||||||
|
ENV['TMP'] = otmp
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_windows_unix_socket_pair_paths
|
||||||
|
s1, s2 = UNIXSocket.pair
|
||||||
|
assert !s1.path.empty?
|
||||||
|
assert s2.path.empty?
|
||||||
|
assert !File.exist?(s1.path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_initialize
|
def test_initialize
|
||||||
Dir.mktmpdir {|d|
|
Dir.mktmpdir {|d|
|
||||||
Socket.open(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) {|s|
|
Socket.open(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) {|s|
|
||||||
|
@ -629,6 +629,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
|
|||||||
#define HAVE_STDDEF_H 1
|
#define HAVE_STDDEF_H 1
|
||||||
#define HAVE_STRING_H 1
|
#define HAVE_STRING_H 1
|
||||||
#define HAVE_MEMORY_H 1
|
#define HAVE_MEMORY_H 1
|
||||||
|
!if $(MSC_VER) >= 1920
|
||||||
|
#define HAVE_AFUNIX_H 1
|
||||||
|
!endif
|
||||||
!if $(MSC_VER) >= 1400
|
!if $(MSC_VER) >= 1400
|
||||||
#define HAVE_LONG_LONG 1
|
#define HAVE_LONG_LONG 1
|
||||||
!else
|
!else
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
#ifndef RUBY_WIN32_FILE_H
|
#ifndef RUBY_WIN32_FILE_H
|
||||||
#define RUBY_WIN32_FILE_H
|
#define RUBY_WIN32_FILE_H
|
||||||
|
|
||||||
|
#ifndef IO_REPARSE_TAG_AF_UNIX
|
||||||
|
# define IO_REPARSE_TAG_AF_UNIX 0x80000023
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MINIMUM_REPARSE_BUFFER_PATH_LEN = 100
|
MINIMUM_REPARSE_BUFFER_PATH_LEN = 100
|
||||||
};
|
};
|
||||||
|
154
win32/win32.c
154
win32/win32.c
@ -49,6 +49,9 @@
|
|||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
#include <mswsock.h>
|
#include <mswsock.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_AFUNIX_H
|
||||||
|
# include <afunix.h>
|
||||||
|
#endif
|
||||||
#include "ruby/win32.h"
|
#include "ruby/win32.h"
|
||||||
#include "ruby/vm.h"
|
#include "ruby/vm.h"
|
||||||
#include "win32/dir.h"
|
#include "win32/dir.h"
|
||||||
@ -4018,15 +4021,93 @@ rb_w32_getservbyport(int port, const char *proto)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_AFUNIX_H
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
static size_t
|
||||||
|
socketpair_unix_path(struct sockaddr_un *sock_un)
|
||||||
|
{
|
||||||
|
SOCKET listener;
|
||||||
|
WCHAR wpath[sizeof(sock_un->sun_path)/sizeof(*sock_un->sun_path)] = L"";
|
||||||
|
|
||||||
|
/* AF_UNIX/SOCK_STREAM became available in Windows 10
|
||||||
|
* See https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows
|
||||||
|
*/
|
||||||
|
listener = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (listener == INVALID_SOCKET)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(sock_un, 0, sizeof(*sock_un));
|
||||||
|
sock_un->sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
/* Abstract sockets (filesystem-independent) don't work, contrary to
|
||||||
|
* the claims of the aforementioned blog post:
|
||||||
|
* https://github.com/microsoft/WSL/issues/4240#issuecomment-549663217
|
||||||
|
*
|
||||||
|
* So we must use a named path, and that comes with all the attendant
|
||||||
|
* problems of permissions and collisions. Trying various temporary
|
||||||
|
* directories and putting high-res time and PID in the filename.
|
||||||
|
*/
|
||||||
|
for (int try = 0; ; try++) {
|
||||||
|
LARGE_INTEGER ticks;
|
||||||
|
size_t path_len = 0;
|
||||||
|
const size_t maxpath = sizeof(sock_un->sun_path)/sizeof(*sock_un->sun_path);
|
||||||
|
|
||||||
|
switch (try) {
|
||||||
|
case 0:
|
||||||
|
/* user temp dir from TMP or TEMP env var, it ends with a backslash */
|
||||||
|
path_len = GetTempPathW(maxpath, wpath);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
wcsncpy(wpath, L"C:/Temp/", maxpath);
|
||||||
|
path_len = lstrlenW(wpath);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* Current directory */
|
||||||
|
path_len = 0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
closesocket(listener);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Windows UNIXSocket implementation expects UTF-8 instead of UTF16 */
|
||||||
|
path_len = WideCharToMultiByte(CP_UTF8, 0, wpath, path_len, sock_un->sun_path, maxpath, NULL, NULL);
|
||||||
|
QueryPerformanceCounter(&ticks);
|
||||||
|
path_len += snprintf(sock_un->sun_path + path_len,
|
||||||
|
maxpath - path_len,
|
||||||
|
"%lld-%ld.($)",
|
||||||
|
ticks.QuadPart,
|
||||||
|
GetCurrentProcessId());
|
||||||
|
|
||||||
|
/* Convert to UTF16 for DeleteFileW */
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, sock_un->sun_path, -1, wpath, sizeof(wpath)/sizeof(*wpath));
|
||||||
|
|
||||||
|
if (bind(listener, (struct sockaddr *)sock_un, sizeof(*sock_un)) != SOCKET_ERROR)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
closesocket(listener);
|
||||||
|
DeleteFileW(wpath);
|
||||||
|
return sizeof(*sock_un);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
static int
|
static int
|
||||||
socketpair_internal(int af, int type, int protocol, SOCKET *sv)
|
socketpair_internal(int af, int type, int protocol, SOCKET *sv)
|
||||||
{
|
{
|
||||||
SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
|
SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
|
||||||
struct sockaddr_in sock_in4;
|
struct sockaddr_in sock_in4;
|
||||||
|
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
struct sockaddr_in6 sock_in6;
|
struct sockaddr_in6 sock_in6;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_AFUNIX_H
|
||||||
|
struct sockaddr_un sock_un = {0, {0}};
|
||||||
|
WCHAR wpath[sizeof(sock_un.sun_path)/sizeof(*sock_un.sun_path)] = L"";
|
||||||
|
#endif
|
||||||
|
|
||||||
struct sockaddr *addr;
|
struct sockaddr *addr;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int len;
|
int len;
|
||||||
@ -4050,6 +4131,15 @@ socketpair_internal(int af, int type, int protocol, SOCKET *sv)
|
|||||||
addr = (struct sockaddr *)&sock_in6;
|
addr = (struct sockaddr *)&sock_in6;
|
||||||
len = sizeof(sock_in6);
|
len = sizeof(sock_in6);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_AFUNIX_H
|
||||||
|
case AF_UNIX:
|
||||||
|
addr = (struct sockaddr *)&sock_un;
|
||||||
|
len = socketpair_unix_path(&sock_un);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, sock_un.sun_path, -1, wpath, sizeof(wpath)/sizeof(*wpath));
|
||||||
|
if (len)
|
||||||
|
break;
|
||||||
|
/* fall through */
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
errno = EAFNOSUPPORT;
|
errno = EAFNOSUPPORT;
|
||||||
@ -4101,6 +4191,10 @@ socketpair_internal(int af, int type, int protocol, SOCKET *sv)
|
|||||||
}
|
}
|
||||||
if (svr != INVALID_SOCKET)
|
if (svr != INVALID_SOCKET)
|
||||||
closesocket(svr);
|
closesocket(svr);
|
||||||
|
#ifdef HAVE_AFUNIX_H
|
||||||
|
if (sock_un.sun_family == AF_UNIX)
|
||||||
|
DeleteFileW(wpath);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -5632,10 +5726,8 @@ fileattr_to_unixmode(DWORD attr, const WCHAR *path, unsigned mode)
|
|||||||
/* format is already set */
|
/* format is already set */
|
||||||
}
|
}
|
||||||
else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
if (rb_w32_reparse_symlink_p(path))
|
/* Only used by stat_by_find in the case the file can not be opened.
|
||||||
mode |= S_IFLNK | S_IEXEC;
|
* In this case we can't get more details. */
|
||||||
else
|
|
||||||
mode |= S_IFDIR | S_IEXEC;
|
|
||||||
}
|
}
|
||||||
else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
mode |= S_IFDIR | S_IEXEC;
|
mode |= S_IFDIR | S_IEXEC;
|
||||||
@ -5710,14 +5802,6 @@ stat_by_find(const WCHAR *path, struct stati128 *st)
|
|||||||
{
|
{
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
WIN32_FIND_DATAW wfd;
|
WIN32_FIND_DATAW wfd;
|
||||||
/* GetFileAttributesEx failed; check why. */
|
|
||||||
int e = GetLastError();
|
|
||||||
|
|
||||||
if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
|
|
||||||
|| (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
|
|
||||||
errno = map_errno(e);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
|
/* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
|
||||||
h = FindFirstFileW(path, &wfd);
|
h = FindFirstFileW(path, &wfd);
|
||||||
@ -5753,9 +5837,24 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||||||
DWORD flags = lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
|
DWORD flags = lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
|
||||||
HANDLE f;
|
HANDLE f;
|
||||||
WCHAR finalname[PATH_MAX];
|
WCHAR finalname[PATH_MAX];
|
||||||
|
int open_error;
|
||||||
|
|
||||||
memset(st, 0, sizeof(*st));
|
memset(st, 0, sizeof(*st));
|
||||||
f = open_special(path, 0, flags);
|
f = open_special(path, 0, flags);
|
||||||
|
open_error = GetLastError();
|
||||||
|
if (f == INVALID_HANDLE_VALUE && !lstat) {
|
||||||
|
/* Support stat (not only lstat) of UNIXSocket */
|
||||||
|
FILE_ATTRIBUTE_TAG_INFO attr_info;
|
||||||
|
DWORD e;
|
||||||
|
|
||||||
|
f = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
|
||||||
|
e = GetFileInformationByHandleEx( f, FileAttributeTagInfo,
|
||||||
|
&attr_info, sizeof(attr_info));
|
||||||
|
if (!e || attr_info.ReparseTag != IO_REPARSE_TAG_AF_UNIX) {
|
||||||
|
CloseHandle(f);
|
||||||
|
f = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (f != INVALID_HANDLE_VALUE) {
|
if (f != INVALID_HANDLE_VALUE) {
|
||||||
DWORD attr = stati128_handle(f, st);
|
DWORD attr = stati128_handle(f, st);
|
||||||
const DWORD len = get_final_path(f, finalname, numberof(finalname), 0);
|
const DWORD len = get_final_path(f, finalname, numberof(finalname), 0);
|
||||||
@ -5767,15 +5866,26 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||||||
case FILE_TYPE_PIPE:
|
case FILE_TYPE_PIPE:
|
||||||
mode = S_IFIFO;
|
mode = S_IFIFO;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
|
FILE_ATTRIBUTE_TAG_INFO attr_info;
|
||||||
|
DWORD e;
|
||||||
|
|
||||||
|
e = GetFileInformationByHandleEx( f, FileAttributeTagInfo,
|
||||||
|
&attr_info, sizeof(attr_info));
|
||||||
|
if (e && attr_info.ReparseTag == IO_REPARSE_TAG_AF_UNIX) {
|
||||||
|
st->st_size = 0;
|
||||||
|
mode |= S_IFSOCK;
|
||||||
|
} else if (rb_w32_reparse_symlink_p(path)) {
|
||||||
|
/* TODO: size in which encoding? */
|
||||||
|
st->st_size = 0;
|
||||||
|
mode |= S_IFLNK | S_IEXEC;
|
||||||
|
} else {
|
||||||
|
mode |= S_IFDIR | S_IEXEC;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(f);
|
CloseHandle(f);
|
||||||
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
|
||||||
/* TODO: size in which encoding? */
|
|
||||||
if (rb_w32_reparse_symlink_p(path))
|
|
||||||
st->st_size = 0;
|
|
||||||
else
|
|
||||||
attr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
|
||||||
}
|
|
||||||
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
if (check_valid_dir(path)) return -1;
|
if (check_valid_dir(path)) return -1;
|
||||||
}
|
}
|
||||||
@ -5788,6 +5898,12 @@ winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if ((open_error == ERROR_FILE_NOT_FOUND) || (open_error == ERROR_INVALID_NAME)
|
||||||
|
|| (open_error == ERROR_PATH_NOT_FOUND || (open_error == ERROR_BAD_NETPATH))) {
|
||||||
|
errno = map_errno(open_error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stat_by_find(path, st)) return -1;
|
if (stat_by_find(path, st)) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user