Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Socket for Windows (WIP) #9544

Closed
2 changes: 1 addition & 1 deletion .github/workflows/win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,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 objs\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 objs\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 ws2_32.lib /F10000000"

- name: Re-build Crystal
run: |
Expand Down
4 changes: 3 additions & 1 deletion spec/std/socket/address_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ 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
{% unless flag?(:win32) %}
Socket.ip?("::1:2:3:4:5:6:7").should be_true # fails on Windows
{% 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
11 changes: 1 addition & 10 deletions src/errno.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,7 @@ end
enum Errno
NONE = 0

{% for value in %w(E2BIG EPERM ENOENT ESRCH EINTR EIO ENXIO ENOEXEC EBADF ECHILD EDEADLK ENOMEM
EACCES EFAULT ENOTBLK EBUSY EEXIST EXDEV ENODEV ENOTDIR EISDIR EINVAL ENFILE
EMFILE ENOTTY ETXTBSY EFBIG ENOSPC ESPIPE EROFS EMLINK EPIPE EDOM ERANGE EAGAIN
EWOULDBLOCK EINPROGRESS EALREADY ENOTSOCK EDESTADDRREQ EMSGSIZE EPROTOTYPE ENOPROTOOPT
EPROTONOSUPPORT ESOCKTNOSUPPORT EPFNOSUPPORT EAFNOSUPPORT EADDRINUSE EADDRNOTAVAIL
ENETDOWN ENETUNREACH ENETRESET ECONNABORTED ECONNRESET ENOBUFS EISCONN ENOTCONN
ESHUTDOWN ETOOMANYREFS ETIMEDOUT ECONNREFUSED ELOOP ENAMETOOLONG EHOSTDOWN
EHOSTUNREACH ENOTEMPTY EUSERS EDQUOT ESTALE EREMOTE ENOLCK ENOSYS EOVERFLOW
ECANCELED EIDRM ENOMSG EILSEQ EBADMSG EMULTIHOP ENODATA ENOLINK ENOSR ENOSTR
EPROTO ETIME EOPNOTSUPP ENOTRECOVERABLE EOWNERDEAD) %}
{% for value in %w(E2BIG EPERM ENOENT ESRCH EINTR EIO ENXIO ENOEXEC EBADF ECHILD EDEADLK ENOMEM EACCES EFAULT ENOTBLK EBUSY EEXIST EXDEV ENODEV ENOTDIR EISDIR EINVAL ENFILE EMFILE ENOTTY ETXTBSY EFBIG ENOSPC ESPIPE EROFS EMLINK EPIPE EDOM ERANGE EAGAIN EWOULDBLOCK EINPROGRESS EALREADY ENOTSOCK EDESTADDRREQ EMSGSIZE EPROTOTYPE ENOPROTOOPT EPROTONOSUPPORT ESOCKTNOSUPPORT EPFNOSUPPORT EAFNOSUPPORT EADDRINUSE EADDRNOTAVAIL ENETDOWN ENETUNREACH ENETRESET ECONNABORTED ECONNRESET ENOBUFS EISCONN ENOTCONN ESHUTDOWN ETOOMANYREFS ETIMEDOUT ECONNREFUSED ELOOP ENAMETOOLONG EHOSTDOWN EHOSTUNREACH ENOTEMPTY EUSERS EDQUOT ESTALE EREMOTE ENOLCK ENOSYS EOVERFLOW ECANCELED EIDRM ENOMSG EILSEQ EBADMSG EMULTIHOP ENODATA ENOLINK ENOSR ENOSTR EPROTO ETIME EOPNOTSUPP ENOTRECOVERABLE EOWNERDEAD WSABASEERR WSAEINPROGRESS WSAEINTR WSAENOPROTOOPT) %}
{% if LibC.has_constant?(value) %}
{{value.id}} = LibC::{{value.id}}
{% end %}
Expand Down
3 changes: 2 additions & 1 deletion src/io/evented.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% skip_file if flag?(:win32) %}
# TODO
# {% skip_file if flag?(:win32) %}

require "crystal/thread_local_value"

Expand Down
6 changes: 6 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/arpa/inet.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "../winnt"

lib LibC
fun inet_ntop(family : INT, pAddr : PVOID, pStringBuf : PSTR, stringBufSize : SizeT) : PCSTR
fun inet_pton(family : INT, pszAddrString : PCSTR, pAddrBuf : PVOID) : INT
end
98 changes: 59 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,64 @@
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

# source https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
WSABASEERR = 10000
WSAEINTR = 10004
WSAEINPROGRESS = 10036
WSAEALREADY = 10037
WSAENOPROTOOPT = 10042
WSAEADDRINUSE = 10048
WSAECONNABORTED = 10053
WSAECONNRESET = 10054
WSAEISCONN = 10056
WSAECONNREFUSED = 10061

alias ErrnoT = Int
end
2 changes: 2 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/fcntl.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "./sys/socket"

lib LibC
O_RDONLY = 0x0000
O_WRONLY = 0x0001
Expand Down
46 changes: 46 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/netdb.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require "./sys/socket"

lib LibC
AI_PASSIVE = 0x0001
AI_CANONNAME = 0x0002
AI_NUMERICHOST = 0x0004
AI_ALL = 0x0100
AI_ADDRCONFIG = 0x0400
AI_V4MAPPED = 0x0800
AI_NON_AUTHORITATIVE = 0x04000
AI_SECURE = 0x08000
AI_RETURN_PREFERRED_NAMES = 0x010000
AI_FQDN = 0x00020000
AI_FILESERVER = 0x00040000
AI_NUMERICSERV = 0x00000008

EAI_AGAIN = 11002
EAI_BADFLAGS = 10022
EAI_FAIL = 11003
EAI_FAMILY = 10047
EAI_MEMORY = 8
EAI_NONAME = 11001
EAI_SERVICE = 10109
EAI_SOCKTYPE = 10044

struct Addrinfo
ai_flags : Int
ai_family : Int
ai_socktype : Int
ai_protocol : Int
ai_addrlen : SizeT
ai_canonname : Char*
ai_addr : Sockaddr*
ai_next : Addrinfo*
end

alias ADDRINFOA = Addrinfo
alias PADDRINFOA = Addrinfo*

fun freeaddrinfo(pAddrInfo : PADDRINFOA) : VOID
fun getaddrinfo(pNodeName : PCSTR, pServiceName : PCSTR, pHints : ADDRINFOA*, ppResult : PADDRINFOA*) : INT
fun getnameinfo(pSockaddr : SOCKADDR*, sockaddrLength : SocklenT, pNodeBuffer : PCHAR, nodeBufferSize : DWORD, pServiceBuffer : PCHAR, serviceBufferSize : DWORD, flags : INT) : INT

# fun gai_strerror = gai_strerrorA(ecode : Int) : UInt8*
# See src/socket/addrinfo.cr for `gai_strerrorA` function definition
end
58 changes: 58 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/netinet/in.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require "../sys/socket"
require "../winnt.cr"

lib LibC
IPPROTO_IP = 0
IPPROTO_ICMP = 1
IPPROTO_IGMP = 2
IPPROTO_TCP = 6
IPPROTO_UDP = 17
IPPROTO_ICMPV6 = 58
IPPROTO_RAW = 255

struct SUnB
s_b1 : UCHAR
s_b2 : UCHAR
s_b3 : UCHAR
s_b4 : UCHAR
end

struct SUnW
s_w1 : USHORT
s_w2 : USHORT
end

union InAddrU
s_un_b : SUnB
s_un_w : SUnW
s_addr : ULONG
end

struct InAddr
s_un : InAddrU
end

union In6AddrIn6U
byte : StaticArray(UCHAR, 16)
word : StaticArray(USHORT, 8)
end

struct In6Addr
u : In6AddrIn6U
end

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
Empty file.
102 changes: 102 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/sys/socket.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
require "./types"
require "./un"

@[Link("WS2_32")]
lib LibC
alias SocklenT = Int
alias SaFamilyT = UShort
alias SOCKET = UInt

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

SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
SOCK_RDM = 4
SOCK_SEQPACKET = 5

PF_INET = 2
PF_INET6 = 23
PF_UNIX = 1
PF_UNSPEC = 0

SO_REUSEADDR = 0x0004
SO_BROADCAST = 0x0020
SOL_SOCKET = 0xFFFF
SO_EXCLUSIVEADDRUSE = ~0x0004_i32

# -2147195266 is the value after convertion to long, actual value 2147772030 with type unsigned
FIONBIO = -2147195266

struct Sockaddr
sa_family : UShort
sa_data : StaticArray(Char, 14)
end

alias SOCKADDR = Sockaddr

struct WSAData
vVersion : WORD
wHighVersion : WORD
szDescription : StaticArray(Char, 257)
szSystemStatus : StaticArray(Char, 129)
iMaxSockets : UInt16
iMaxUdpDg : UInt16
lpVendorInfo : Char*
end

struct SockaddrStorage
ss_family : Short
__ss_pad1 : StaticArray(Char, 6)
__ss_align : Int64
__ss_pad2 : StaticArray(Char, 112)
end

alias LPWSADATA = WSAData*

fun wsastartup = WSAStartup(wVersionRequired : WORD, lpWSAData : LPWSADATA) : Int
fun socket(af : Int, type : Int, protocol : Int) : SOCKET
fun bind(s : SOCKET, addr : Sockaddr*, namelen : Int) : Int
fun closesocket(s : SOCKET) : Int
fun send(s : SOCKET, buf : UInt8*, len : Int, flags : Int) : Int
fun setsockopt(s : SOCKET, level : Int, optname : Int, optval : UInt8*, len : Int) : Int
fun ioctlsocket(s : SOCKET, cmd : Int, argp : UInt32*) : Int
fun listen(s : SOCKET, backlog : Int) : Int
fun accept(s : SOCKET, addr : Sockaddr*, addrlen : Int*) : SOCKET
fun getpeername(s : SOCKET, name : Sockaddr*, namelen : Int*) : Int
fun ntohs(netshort : UShort) : UShort
fun recv(s : SOCKET, buf : UInt8*, len : Int, flags : Int) : Int
fun connect(s : SOCKET, name : Sockaddr*, namelen : Int) : Int
fun getsockname(s : SOCKET, name : Sockaddr*, namelen : Int*) : Int
fun htons(hostshort : UShort) : UShort
fun getsockopt(s : SOCKET, level : Int, optname : Int, optval : UInt8*, optlen : Int*) : Int
fun sendto(s : SOCKET, buf : UInt8*, len : Int, flags : Int, to : Sockaddr*, tolen : Int) : Int
fun recvfrom(s : SOCKET, buf : Char*, len : Int, flags : Int, from : Sockaddr*, fromlen : Int*) : Int

SO_RCVBUF = 0x1002
TCP_NODELAY = 0x0001
TCP_KEEPIDLE = 3
TCP_KEEPCNT = 16
TCP_KEEPINTVL = 17
IP_MULTICAST_LOOP = 11
IPV6_MULTICAST_LOOP = 11
IPPROTO_IPV6 = 41
IP_MULTICAST_TTL = 10
IP_MULTICAST_IF = 9
IPV6_MULTICAST_IF = 9
IPV6_MULTICAST_HOPS = 10
IP_ADD_MEMBERSHIP = 12
end

# TODO
wsadata = uninitialized LibC::WSAData
wsaVersion = 514
LibC.wsastartup(wsaVersion, pointerof(wsadata))
16 changes: 16 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/sys/un.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
lib LibC
# struct IpMreq
# imr_multiaddr : IN_ADDR
# imr_interface : IN_ADDR
# end

# https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
alias ADDRESS_FAMILY = UShort

UNIX_PATH_MAX = 108

struct SockaddrUn
sun_family : ADDRESS_FAMILY
sun_path : StaticArray(Char, UNIX_PATH_MAX)
end
end
Loading