Skip to content

Commit

Permalink
fixup! Implement Socket for Windows (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
andraantariksa committed Jun 25, 2020
1 parent cb7b265 commit 56ecf85
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 27 deletions.
7 changes: 3 additions & 4 deletions src/lib_c/x86_64-windows-msvc/c/netdb.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
# require "./stdint"
require "./sys/socket"

#@[Link(ldflags: "WS2tcpip.obj")]
@[Link("Kernel32")]
lib LibC
AI_PASSIVE = 0x0001
AI_CANONNAME = 0x0002
Expand Down Expand Up @@ -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
13 changes: 7 additions & 6 deletions src/lib_c/x86_64-windows-msvc/c/sys/socket.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
end
2 changes: 2 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/winbase.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
14 changes: 0 additions & 14 deletions src/socket.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 27 additions & 3 deletions src/socket/addrinfo.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "uri/punycode"
require "c/sys/socket"

class Socket
# Domain name resolver.
Expand Down Expand Up @@ -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}")
Expand Down

0 comments on commit 56ecf85

Please sign in to comment.