diff --git a/src/lib_c/x86_64-windows-msvc/c/netdb.cr b/src/lib_c/x86_64-windows-msvc/c/netdb.cr index b7e348ad8a41..5f957b7a94d3 100644 --- a/src/lib_c/x86_64-windows-msvc/c/netdb.cr +++ b/src/lib_c/x86_64-windows-msvc/c/netdb.cr @@ -3,8 +3,6 @@ # require "./stdint" require "./sys/socket" -#@[Link(ldflags: "WS2tcpip.obj")] -@[Link("Kernel32")] lib LibC AI_PASSIVE = 0x0001 AI_CANONNAME = 0x0002 @@ -89,6 +87,7 @@ lib LibC 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* - fun formatMessageA = FormatMessageA(dwFlags : DWORD, lpSource : LPCVOID, dwMessageId : DWORD, dwLanguageId : DWORD, lpBuffer : LPSTR, nSize : DWORD, ...) : DWORD + + # fun gai_strerror = gai_strerrorA(ecode : Int) : UInt8* + # See src/socket/addrinfo.cr for `gai_strerrorA` function definition end diff --git a/src/lib_c/x86_64-windows-msvc/c/sys/socket.cr b/src/lib_c/x86_64-windows-msvc/c/sys/socket.cr index 1ffd54d0a6b8..895bb024a165 100644 --- a/src/lib_c/x86_64-windows-msvc/c/sys/socket.cr +++ b/src/lib_c/x86_64-windows-msvc/c/sys/socket.cr @@ -2,23 +2,24 @@ require "./types" @[Link("WS2_32")] lib LibC - alias SocklenT = UInt + alias SocklenT = Int alias SaFamilyT = UShort + alias SOCKET = UInt SO_REUSEADDR = 0x0004 SO_BROADCAST = 0x0020 SOL_SOCKET = 0xFFFF + # -2147195266 is the value after convertion to long, actual value 2147772030 with type unsigned + FIONBIO = -2147195266 + struct Sockaddr sa_family : SaFamilyT - sa_data : StaticArray(Char, 14) + sa_data : StaticArray(UInt8, 14) end alias SOCKADDR = Sockaddr - FIONBIO = -2147195266 # -2147195266 is the value after convertion to long, actual value 2147772030 with type unsigned - - alias SOCKET = UInt fun socket(af : Int, type : Int, protocol : Int) : SOCKET fun bind(s : SOCKET, addr : Sockaddr*, namelen : Int) : Int fun closesocket(s : SOCKET) : Int @@ -33,4 +34,4 @@ lib LibC fun connect(s : SOCKET, name : Sockaddr*, namelen : Int) : Int fun getsockname(s : SOCKET, name : Sockaddr*, namelen : Int*) : Int fun htons(hostshort : UShort) : UShort -end \ No newline at end of file +end diff --git a/src/lib_c/x86_64-windows-msvc/c/winbase.cr b/src/lib_c/x86_64-windows-msvc/c/winbase.cr index 989834c6ca23..3b6a215497a8 100644 --- a/src/lib_c/x86_64-windows-msvc/c/winbase.cr +++ b/src/lib_c/x86_64-windows-msvc/c/winbase.cr @@ -2,6 +2,7 @@ require "c/winnt" require "c/win_def" require "c/int_safe" +@[Link("Kernel32")] lib LibC fun GetLastError : DWORD fun SetLastError(dwErrCode : DWORD) @@ -110,4 +111,5 @@ lib LibC MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20_u32 fun MoveFileExW(lpExistingFileName : LPWSTR, lpNewFileName : LPWSTR, dwFlags : DWORD) : BOOL + fun FormatMessageA(dwFlags : DWORD, lpSource : LPCVOID, dwMessageId : DWORD, dwLanguageId : DWORD, lpBuffer : LPSTR, nSize : DWORD, ...) : DWORD end diff --git a/src/socket.cr b/src/socket.cr index 5eba62aeac49..934be5abd727 100644 --- a/src/socket.cr +++ b/src/socket.cr @@ -5,20 +5,6 @@ require "c/netinet/tcp" require "c/sys/socket" require "c/sys/un" require "io/evented" -{% if flag?(:win32) %} - require "c/sys/socket" - - GAI_STRERROR_BUFFER_SIZE = 1024 - - def gai_strerror(ecode : Int) : Bytes - buf = uninitialized StaticArray(UInt8, 1025) - lang = (0x01_u16 << 10) | 0x00_u16 - - LibC.formatMessageA(LibC::FORMAT_MESSAGE_FROM_SYSTEM | LibC::FORMAT_MESSAGE_IGNORE_INSERTS | LibC::FORMAT_MESSAGE_MAX_WIDTH_MASK, Pointer(LibC::DWORD).null, ecode, lang, buf, GAI_STRERROR_BUFFER_SIZE, Pointer(UInt32).null) - - buf.to_slice - end -{% end %} class Socket < IO include IO::Buffered diff --git a/src/socket/addrinfo.cr b/src/socket/addrinfo.cr index f0d993591fcc..70f284bdb99f 100644 --- a/src/socket/addrinfo.cr +++ b/src/socket/addrinfo.cr @@ -1,4 +1,5 @@ require "uri/punycode" +require "c/sys/socket" class Socket # Domain name resolver. @@ -83,10 +84,33 @@ class Socket getter error_code : Int32 def self.new(error_code, domain) - # TODO - # Care - new error_code, String.new(gai_strerror(error_code)), domain + new error_code, String.new(self.gai_strerror(error_code)), domain end + + {% if flag?(:win32) %} + # This is the recreation of gai_strerrorA in Windows, as they + # define their gai_strerrorA in a C-header + # + # See https://gist.github.com/andraantariksa/0dacbe0999427d8554286e568ee5f220#file-ws2tcpip-h-L682 + def self.gai_strerror(ecode : Int) + # The buffer size defined in WS2tcpip.h is 1024 char + # 1024 + 1 (for null at the end of C-string) = 1025 + buf = uninitialized StaticArray(UInt8, 1025) + lang = (0x01_u16 << 10) | 0x00_u16 + + LibC.FormatMessageA(LibC::FORMAT_MESSAGE_FROM_SYSTEM | + LibC::FORMAT_MESSAGE_IGNORE_INSERTS | + LibC::FORMAT_MESSAGE_MAX_WIDTH_MASK, + Pointer(LibC::DWORD).null, ecode, lang, buf, 1024, Pointer(UInt32).null) + + buf.to_slice + end + {% else %} + @[AlwaysInline] + def self.gai_strerror(ecode : Int) + LibC.gai_strerror(ecode) + end + {% end %} def initialize(@error_code, message, domain) super("Hostname lookup for #{domain} failed: #{message}")