diff options
-rw-r--r-- | lib/windows/winlean.nim | 89 | ||||
-rw-r--r-- | tests/stdlib/tnet_ll.nim | 39 |
2 files changed, 118 insertions, 10 deletions
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 4962186fb..d12c661d6 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -12,9 +12,18 @@ {.deadCodeElim:on.} +import dynlib + const useWinUnicode* = not defined(useWinAnsi) +when useWinUnicode: + type WinChar* = Utf16Char + {.deprecated: [TWinChar: WinChar].} +else: + type WinChar* = char + {.deprecated: [TWinChar: WinChar].} + type Handle* = int LONG* = int32 @@ -74,17 +83,18 @@ type nFileIndexHigh*: DWORD nFileIndexLow*: DWORD + OSVERSIONINFO* {.final, pure.} = object + dwOSVersionInfoSize*: DWORD + dwMajorVersion*: DWORD + dwMinorVersion*: DWORD + dwBuildNumber*: DWORD + dwPlatformId*: DWORD + szCSDVersion*: array[0..127, WinChar]; + {.deprecated: [THandle: Handle, TSECURITY_ATTRIBUTES: SECURITY_ATTRIBUTES, TSTARTUPINFO: STARTUPINFO, TPROCESS_INFORMATION: PROCESS_INFORMATION, TFILETIME: FILETIME, TBY_HANDLE_FILE_INFORMATION: BY_HANDLE_FILE_INFORMATION].} -when useWinUnicode: - type WinChar* = Utf16Char - {.deprecated: [TWinChar: WinChar].} -else: - type WinChar* = char - {.deprecated: [TWinChar: WinChar].} - const STARTF_USESHOWWINDOW* = 1'i32 STARTF_USESTDHANDLES* = 256'i32 @@ -117,6 +127,13 @@ const CREATE_NO_WINDOW* = 0x08000000'i32 +when useWinUnicode: + proc getVersionExW*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetVersionExW".} +else: + proc getVersionExA*(lpVersionInfo: ptr OSVERSIONINFO): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetVersionExA".} + +proc getVersion*(): DWORD {.stdcall, dynlib: "kernel32", importc: "GetVersion".} + proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32", importc: "CloseHandle".} @@ -192,6 +209,9 @@ proc flushFileBuffers*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32", proc getLastError*(): int32 {.importc: "GetLastError", stdcall, dynlib: "kernel32".} +proc setLastError*(error: int32) {.importc: "SetLastError", + stdcall, dynlib: "kernel32".} + when useWinUnicode: proc formatMessageW*(dwFlags: int32, lpSource: pointer, dwMessageId, dwLanguageId: int32, @@ -597,9 +617,6 @@ proc freeaddrinfo*(ai: ptr AddrInfo) {. proc inet_ntoa*(i: InAddr): cstring {. stdcall, importc, dynlib: ws2dll.} -proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, - stringBufSize: int32): cstring {.stdcall, importc, dynlib: ws2dll.} - const MAXIMUM_WAIT_OBJECTS* = 0x00000040 @@ -645,6 +662,7 @@ const const ERROR_ACCESS_DENIED* = 5 ERROR_HANDLE_EOF* = 38 + ERROR_BAD_ARGUMENTS* = 165 proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, hTargetProcessHandle: HANDLE, @@ -806,3 +824,54 @@ proc getSystemTimes*(lpIdleTime, lpKernelTime, proc getProcessTimes*(hProcess: Handle; lpCreationTime, lpExitTime, lpKernelTime, lpUserTime: var FILETIME): WINBOOL {.stdcall, dynlib: "kernel32", importc: "GetProcessTimes".} + +type inet_ntop_proc = proc(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall.} + +var inet_ntop_real: inet_ntop_proc = nil + +let l = loadLib(ws2dll) +if l != nil: + inet_ntop_real = cast[inet_ntop_proc](symAddr(l, "inet_ntop")) + +proc WSAAddressToStringA(pAddr: ptr SockAddr, addrSize: DWORD, unused: pointer, pBuff: cstring, pBuffSize: ptr DWORD): cint {.stdcall, importc, dynlib: ws2dll.} +proc inet_ntop_emulated(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall.} = + case family + of AF_INET: + var sa: Sockaddr_in + sa.sin_family = AF_INET + sa.sin_addr = cast[ptr InAddr](paddr)[] + var bs = stringBufSize.DWORD + let r = WSAAddressToStringA(cast[ptr SockAddr](sa.addr), sa.sizeof.DWORD, nil, pStringBuffer, bs.addr) + if r != 0: + result = nil + else: + result = pStringBuffer + of AF_INET6: + var sa: Sockaddr_in6 + sa.sin6_family = AF_INET6 + sa.sin6_addr = cast[ptr In6_addr](paddr)[] + var bs = stringBufSize.DWORD + let r = WSAAddressToStringA(cast[ptr SockAddr](sa.addr), sa.sizeof.DWORD, nil, pStringBuffer, bs.addr) + if r != 0: + result = nil + else: + result = pStringBuffer + else: + setLastError(ERROR_BAD_ARGUMENTS) + result = nil + +proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall.} = + var ver: OSVERSIONINFO + ver.dwOSVersionInfoSize = sizeof(ver).DWORD + let res = when useWinUnicode: getVersionExW(ver.addr) else: getVersionExA(ver.addr) + if res == 0: + result = nil + elif ver.dwMajorVersion >= 6: + if inet_ntop_real == nil: + quit("Can't load inet_ntop proc from " & ws2dll) + result = inet_ntop_real(family, paddr, pStringBuffer, stringBufSize) + else: + result = inet_ntop_emulated(family, paddr, pStringBuffer, stringBufSize) diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim new file mode 100644 index 000000000..4d4df7c13 --- /dev/null +++ b/tests/stdlib/tnet_ll.nim @@ -0,0 +1,39 @@ +discard """ + action: run +""" + +when defined(windows): + import winlean +elif defined(posix): + import posix +else: + {.error: "Unsupported OS".} + +import unittest, strutils + +suite "inet_ntop tests": + + setup: + when defined(windows): + var wsa: WSAData + discard wsaStartup(0x101'i16, wsa.addr) + + test "IP V4": + var ip4 = 0x10111213 + var buff: array[0..255, char] + let r = inet_ntop(AF_INET, ip4.addr, buff[0].addr, buff.sizeof.int32) + let res = if r == nil: "" else: $r + check: res == "19.18.17.16" + + + test "IP V6": + when defined(windows): + let ipv6Support = (getVersion() and 0xff) > 0x5 + else: + let ipv6Support = true + + var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001] + var buff: array[0..255, char] + let r = inet_ntop(AF_INET6, ip6[0].addr, buff[0].addr, buff.sizeof.int32) + let res = if r == nil: "" else: $r + check: not ipv6Support or res == "10:110:20:120:30:130:40:140" |