Skip to content

Commit

Permalink
Port Socket::Address to win32 (#10610)
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota authored Apr 24, 2021
1 parent 3e2c6d3 commit a7544b5
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ jobs:
cl /MT /c src\llvm\ext\llvm_ext.cc -I llvm\include /Fosrc\llvm\ext\llvm_ext.obj
- name: Link Crystal executable
run: |
Invoke-Expression "cl crystal.obj /Fecrystal-cross src\llvm\ext\llvm_ext.obj $(llvm\bin\llvm-config.exe --libs) libs\pcre.lib libs\gc.lib advapi32.lib libcmt.lib legacy_stdio_definitions.lib /F10000000"
Invoke-Expression "cl crystal.obj /Fecrystal-cross src\llvm\ext\llvm_ext.obj $(llvm\bin\llvm-config.exe --libs) libs\pcre.lib libs\gc.lib WS2_32.lib advapi32.lib libcmt.lib legacy_stdio_definitions.lib /F10000000"
- name: Re-build Crystal
run: |
Expand Down
117 changes: 62 additions & 55 deletions spec/std/socket/address_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "spec"
require "socket"
require "socket/address"
require "../../support/win32"

describe Socket::Address do
describe ".parse" do
Expand All @@ -18,7 +19,7 @@ describe Socket::Address do
address.should eq Socket::IPAddress.new("192.168.0.1", 8081)
end

it "parses UNIX" do
pending_win32 "parses UNIX" do
address = Socket::Address.parse "unix://socket.sock"
address.should eq Socket::UNIXAddress.new("socket.sock")
end
Expand Down Expand Up @@ -152,76 +153,78 @@ describe Socket::IPAddress do
end
end

describe Socket::UNIXAddress do
it "transforms into a C struct and back" do
path = "unix_address.sock"
{% unless flag?(:win32) %}
describe Socket::UNIXAddress do
it "transforms into a C struct and back" do
path = "unix_address.sock"

addr1 = Socket::UNIXAddress.new(path)
addr2 = Socket::UNIXAddress.from(addr1.to_unsafe, addr1.size)
addr1 = Socket::UNIXAddress.new(path)
addr2 = Socket::UNIXAddress.from(addr1.to_unsafe, addr1.size)

addr2.family.should eq(addr1.family)
addr2.path.should eq(addr1.path)
addr2.to_s.should eq(path)
end
addr2.family.should eq(addr1.family)
addr2.path.should eq(addr1.path)
addr2.to_s.should eq(path)
end

it "raises when path is too long" do
path = "unix_address-too-long-#{("a" * 2048)}.sock"
it "raises when path is too long" do
path = "unix_address-too-long-#{("a" * 2048)}.sock"

expect_raises(ArgumentError, "Path size exceeds the maximum size") do
Socket::UNIXAddress.new(path)
expect_raises(ArgumentError, "Path size exceeds the maximum size") do
Socket::UNIXAddress.new(path)
end
end
end

it "to_s" do
Socket::UNIXAddress.new("some_path").to_s.should eq("some_path")
end

it "#==" do
Socket::UNIXAddress.new("some_path").should eq Socket::UNIXAddress.new("some_path")
Socket::UNIXAddress.new("some_path").hash.should eq Socket::UNIXAddress.new("some_path").hash
it "to_s" do
Socket::UNIXAddress.new("some_path").to_s.should eq("some_path")
end

Socket::UNIXAddress.new("some_path").should_not eq Socket::UNIXAddress.new("other_path")
Socket::UNIXAddress.new("some_path").hash.should_not eq Socket::UNIXAddress.new("other_path").hash
end
it "#==" do
Socket::UNIXAddress.new("some_path").should eq Socket::UNIXAddress.new("some_path")
Socket::UNIXAddress.new("some_path").hash.should eq Socket::UNIXAddress.new("some_path").hash

describe ".parse" do
it "parses relative" do
address = Socket::UNIXAddress.parse "unix://foo.sock"
address.should eq Socket::UNIXAddress.new("foo.sock")
Socket::UNIXAddress.new("some_path").should_not eq Socket::UNIXAddress.new("other_path")
Socket::UNIXAddress.new("some_path").hash.should_not eq Socket::UNIXAddress.new("other_path").hash
end

it "parses relative subpath" do
address = Socket::UNIXAddress.parse "unix://foo/bar.sock"
address.should eq Socket::UNIXAddress.new("foo/bar.sock")
end
describe ".parse" do
it "parses relative" do
address = Socket::UNIXAddress.parse "unix://foo.sock"
address.should eq Socket::UNIXAddress.new("foo.sock")
end

it "parses relative dot" do
address = Socket::UNIXAddress.parse "unix://./bar.sock"
address.should eq Socket::UNIXAddress.new("./bar.sock")
end
it "parses relative subpath" do
address = Socket::UNIXAddress.parse "unix://foo/bar.sock"
address.should eq Socket::UNIXAddress.new("foo/bar.sock")
end

it "relative with" do
address = Socket::UNIXAddress.parse "unix://foo:21/bar.sock"
address.should eq Socket::UNIXAddress.new("foo:21/bar.sock")
end
it "parses relative dot" do
address = Socket::UNIXAddress.parse "unix://./bar.sock"
address.should eq Socket::UNIXAddress.new("./bar.sock")
end

it "parses absolute" do
address = Socket::UNIXAddress.parse "unix:///foo.sock"
address.should eq Socket::UNIXAddress.new("/foo.sock")
end
it "relative with" do
address = Socket::UNIXAddress.parse "unix://foo:21/bar.sock"
address.should eq Socket::UNIXAddress.new("foo:21/bar.sock")
end

it "ignores params" do
address = Socket::UNIXAddress.parse "unix:///foo.sock?bar=baz"
address.should eq Socket::UNIXAddress.new("/foo.sock")
end
it "parses absolute" do
address = Socket::UNIXAddress.parse "unix:///foo.sock"
address.should eq Socket::UNIXAddress.new("/foo.sock")
end

it "fails with missing path" do
expect_raises(Socket::Error, "Invalid UNIX address: missing path") do
Socket::UNIXAddress.parse "unix://?foo=bar"
it "ignores params" do
address = Socket::UNIXAddress.parse "unix:///foo.sock?bar=baz"
address.should eq Socket::UNIXAddress.new("/foo.sock")
end

it "fails with missing path" do
expect_raises(Socket::Error, "Invalid UNIX address: missing path") do
Socket::UNIXAddress.parse "unix://?foo=bar"
end
end
end
end
end
{% end %}

describe Socket do
# Tests from libc-test:
Expand Down Expand Up @@ -273,7 +276,11 @@ describe Socket do
Socket.ip?("1:2:3:4:5:6:7:8::").should be_false
Socket.ip?("1:2:3:4:5:6:7::9").should be_false
Socket.ip?("::1:2:3:4:5:6").should be_true
Socket.ip?("::1:2:3:4:5:6:7").should be_true
{% if flag?(:win32) %}
Socket.ip?("::1:2:3:4:5:6:7").should be_false
{% else %}
Socket.ip?("::1:2:3:4:5:6:7").should be_true
{% end %}
Socket.ip?("::1:2:3:4:5:6:7:8").should be_false
Socket.ip?("a:b::c:d:e:f").should be_true
Socket.ip?("ffff:c0a8:5e4").should be_false
Expand Down
2 changes: 1 addition & 1 deletion spec/win32_std_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ require "./std/semantic_version_spec.cr"
require "./std/set_spec.cr"
# require "./std/signal_spec.cr" (failed codegen)
require "./std/slice_spec.cr"
# require "./std/socket/address_spec.cr" (failed codegen)
require "./std/socket/address_spec.cr"
# require "./std/socket/addrinfo_spec.cr" (failed codegen)
# require "./std/socket/socket_spec.cr" (failed codegen)
# require "./std/socket/tcp_server_spec.cr" (failed codegen)
Expand Down
8 changes: 8 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/afunix.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
lib LibC
alias AddressFamily = UShort

struct SockaddrUn
sun_family : AddressFamily
sun_path : Char[108]
end
end
86 changes: 47 additions & 39 deletions src/lib_c/x86_64-windows-msvc/c/errno.cr
Original file line number Diff line number Diff line change
@@ -1,44 +1,52 @@
lib LibC
# source https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-doserrno-sys-errlist-and-sys-nerr
EPERM = 1
ENOENT = 2
ESRCH = 3
EINTR = 4
EIO = 5
ENXIO = 6
E2BIG = 7
ENOEXEC = 8
EBADF = 9
ECHILD = 10
EAGAIN = 11
ENOMEM = 12
EACCES = 13
EFAULT = 14
EBUSY = 16
EEXIST = 17
EXDEV = 18
ENODEV = 19
ENOTDIR = 20
EISDIR = 21
EINVAL = 22
ENFILE = 23
EMFILE = 24
ENOTTY = 25
EFBIG = 27
ENOSPC = 28
ESPIPE = 29
EROFS = 30
EMLINK = 31
EPIPE = 32
EDOM = 33
ERANGE = 34
EDEADLK = 36
ENAMETOOLONG = 38
ENOLCK = 39
ENOSYS = 40
ENOTEMPTY = 41
EILSEQ = 42
STRUNCATE = 80
EPERM = 1
ENOENT = 2
ESRCH = 3
EINTR = 4
EIO = 5
ENXIO = 6
E2BIG = 7
ENOEXEC = 8
EBADF = 9
ECHILD = 10
EAGAIN = 11
ENOMEM = 12
EACCES = 13
EFAULT = 14
EBUSY = 16
EEXIST = 17
EXDEV = 18
ENODEV = 19
ENOTDIR = 20
EISDIR = 21
EINVAL = 22
ENFILE = 23
EMFILE = 24
ENOTTY = 25
EFBIG = 27
ENOSPC = 28
ESPIPE = 29
EROFS = 30
EMLINK = 31
EPIPE = 32
EDOM = 33
ERANGE = 34
EDEADLK = 36
ENAMETOOLONG = 38
ENOLCK = 39
ENOSYS = 40
ENOTEMPTY = 41
EILSEQ = 42
STRUNCATE = 80
EADDRINUSE = 100
EALREADY = 103
ECONNABORTED = 106
ECONNREFUSED = 107
ECONNRESET = 108
EINPROGRESS = 112
EISCONN = 113
ENOPROTOOPT = 123

alias ErrnoT = Int
end
10 changes: 10 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/in6addr.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
lib LibC
struct In6Addr
u : In6AddrU
end

union In6AddrU
byte : Char[16]
word : WORD[8]
end
end
21 changes: 21 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/winsock2.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require "./ws2def"

@[Link("WS2_32")]
lib LibC
AF_UNSPEC = 0
AF_UNIX = 1
AF_INET = 2
AF_IPX = 6
AF_APPLETALK = 16
AF_NETBIOS = 17
AF_INET6 = 23
AF_IRDA = 26
AF_BTH = 32

struct InAddr
s_addr : UInt32
end

fun htons(hostshort : UShort) : UShort
fun ntohs(netshort : UShort) : UShort
end
14 changes: 14 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/ws2def.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
lib LibC
IPPROTO_IP = 0
IPPROTO_ICMP = 1
IPPROTO_IGMP = 2
IPPROTO_TCP = 6
IPPROTO_UDP = 17
IPPROTO_ICMPV6 = 58
IPPROTO_RAW = 255

struct Sockaddr
sa_family : UInt8
sa_data : Char[14]
end
end
18 changes: 18 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/ws2ipdef.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require "./in6addr"

lib LibC
struct SockaddrIn6
sin6_family : Short
sin6_port : UShort
sin6_flowinfo : ULong
sin6_addr : In6Addr
sin6_scope_id : ULong
end

struct SockaddrIn
sin_family : Short
sin_port : UShort
sin_addr : InAddr
sin_zero : StaticArray(CHAR, 8)
end
end
7 changes: 7 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/ws2tcpip.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require "./winsock2"
require "./ws2ipdef"

lib LibC
fun inet_ntop(family : Int, pAddr : Void*, pStringBuf : Char*, stringBufSize : SizeT) : Char*
fun inet_pton(family : Int, pszAddrString : Char*, pAddrBuf : Void*) : Int
end
Loading

0 comments on commit a7544b5

Please sign in to comment.