Merge pull request #3787 from vegansk/fix_3539_3

Fixed issue #3539 - could not import inet_ntop on XP/2003 - 3rd try
This commit is contained in:
Andreas Rumpf
2016-01-28 19:34:51 +01:00
2 changed files with 118 additions and 10 deletions

View File

@@ -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)

39
tests/stdlib/tnet_ll.nim Normal file
View File

@@ -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"