From 29bb10b1854206015ad411f5b77c8fcd8aa90024 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 14 Mar 2018 22:53:00 +0200 Subject: [PATCH 1/7] Convertion procs for (IpAddress, Port) <-> (SockAddr, Socklen) --- lib/pure/net.nim | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index af9eea51a7..bb1c1ce6e2 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -414,6 +414,39 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} = return false return true +proc toSockAddr*(address: IpAddress, port: Port, sa: var SockAddr, sl: var Socklen) = + ## Converts `IpAddress` and `Port` to `SockAddr` and `Socklen` + let port = htons(uint16(port)) + case address.family + of IpAddressFamily.IPv4: + sl = sizeof(Sockaddr_in).Socklen + let s = cast[ptr Sockaddr_in](addr sa) + s.sin_family = type(s.sin_family)(AF_INET) + s.sin_port = port + copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr)) + of IpAddressFamily.IPv6: + sl = sizeof(Sockaddr_in6).Socklen + let s = cast[ptr Sockaddr_in6](addr sa) + s.sin6_family = type(s.sin6_family)(AF_INET6) + s.sin6_port = port + copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) + +proc fromSockAddr*(sa: SockAddr, sl: Socklen, address: var IpAddress, port: var Port) = + ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises + ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. + if sa.sa_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen: + address = IpAddress(family: IpAddressFamily.IPv4) + let s = cast[ptr Sockaddr_in](unsafeAddr sa) + copyMem(addr address.address_v4, addr s.sin_addr, sizeof(address.address_v4)) + port = ntohs(s.sin_port).Port + elif sa.sa_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen: + address = IpAddress(family: IpAddressFamily.IPv6) + let s = cast[ptr Sockaddr_in6](unsafeAddr sa) + copyMem(addr address.address_v6, addr s.sin6_addr, sizeof(address.address_v6)) + port = ntohs(s.sin6_port).Port + else: + raise newException(ObjectConversionError, "Unexpected SockAddr/Socklen") + when defineSsl: CRYPTO_malloc_init() doAssert SslLibraryInit() == 1 From 1bd0efb067b7c1939f4d68c9014b7d67cb4e7020 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 15 Mar 2018 15:44:12 +0200 Subject: [PATCH 2/7] Fixed crash/interface. Added tests. --- lib/pure/nativesockets.nim | 2 +- lib/pure/net.nim | 12 ++++++------ lib/windows/winlean.nim | 4 ++++ tests/stdlib/tnet.nim | 32 +++++++++++++++++++++++++++++++- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 280c4e9272..68061853b5 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -31,7 +31,7 @@ else: export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, - Sockaddr_in6, + Sockaddr_in6, Sockaddr_storage, inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto, freeAddrInfo diff --git a/lib/pure/net.nim b/lib/pure/net.nim index bb1c1ce6e2..a48e200d8f 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -414,7 +414,7 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} = return false return true -proc toSockAddr*(address: IpAddress, port: Port, sa: var SockAddr, sl: var Socklen) = +proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl: var Socklen) = ## Converts `IpAddress` and `Port` to `SockAddr` and `Socklen` let port = htons(uint16(port)) case address.family @@ -431,18 +431,18 @@ proc toSockAddr*(address: IpAddress, port: Port, sa: var SockAddr, sl: var Sockl s.sin6_port = port copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) -proc fromSockAddr*(sa: SockAddr, sl: Socklen, address: var IpAddress, port: var Port) = +proc fromSockAddr*(sa: Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) = ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. - if sa.sa_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen: + if sa.ss_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen: address = IpAddress(family: IpAddressFamily.IPv4) let s = cast[ptr Sockaddr_in](unsafeAddr sa) - copyMem(addr address.address_v4, addr s.sin_addr, sizeof(address.address_v4)) + copyMem(addr address.address_v4[0], addr s.sin_addr, sizeof(address.address_v4)) port = ntohs(s.sin_port).Port - elif sa.sa_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen: + elif sa.ss_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen: address = IpAddress(family: IpAddressFamily.IPv6) let s = cast[ptr Sockaddr_in6](unsafeAddr sa) - copyMem(addr address.address_v6, addr s.sin6_addr, sizeof(address.address_v6)) + copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6)) port = ntohs(s.sin6_port).Port else: raise newException(ObjectConversionError, "Unexpected SockAddr/Socklen") diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index b2c1cc1f5f..b2afd3f698 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -481,6 +481,10 @@ type sin6_flowinfo*: int32 # unsigned sin6_addr*: In6_addr + Sockaddr_storage* {.importc: "SOCKADDR_STORAGE", + header: "winsock2.h".} = object + ss_family*: int16 + Servent* = object s_name*: cstring s_aliases*: cstringArray diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index e8ada05e70..64d690fc96 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -1,4 +1,4 @@ -import net +import net, nativesockets import unittest suite "isIpAddress tests": @@ -45,3 +45,33 @@ suite "parseIpAddress tests": test "invalid ipv6": expect(ValueError): discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") + +block: # "IpAddress/Sockaddr conversion" + proc test(ipaddrstr: string) = + var ipaddr_1 = parseIpAddress(ipaddrstr) + # echo ipaddrstr, " ", $ipaddr_1 + + doAssert($ipaddrstr == $ipaddr_1) + + var sockaddr: Sockaddr_storage + var socklen: Socklen + var ipaddr_2: IpAddress + var port_2: Port + + toSockAddr(ipaddr_1, Port(0), sockaddr, socklen) + fromSockAddr(sockaddr, socklen, ipaddr_2, port_2) + + doAssert(ipaddrstr == $ipaddr_1) + + doAssert(ipaddr_1 == ipaddr_2) + doAssert($ipaddr_1 == $ipaddr_2) + + + # ipv6 address of example.com + test("2606:2800:220:1:248:1893:25c8:1946") + # ipv6 address of localhost + test("::1") + # ipv4 address of example.com + test("93.184.216.34") + # ipv4 address of localhost + test("127.0.0.1") From b52de1fcee29a8098bfa387524ecb12456afd7d7 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 15 Mar 2018 17:39:09 +0200 Subject: [PATCH 3/7] More flexible fromSockAddr interface --- lib/pure/net.nim | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index a48e200d8f..f16d496b42 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -431,22 +431,26 @@ proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl: v s.sin6_port = port copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) -proc fromSockAddr*(sa: Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) = - ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises - ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. +proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) = if sa.ss_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen: address = IpAddress(family: IpAddressFamily.IPv4) - let s = cast[ptr Sockaddr_in](unsafeAddr sa) + let s = cast[ptr Sockaddr_in](sa) copyMem(addr address.address_v4[0], addr s.sin_addr, sizeof(address.address_v4)) port = ntohs(s.sin_port).Port elif sa.ss_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen: address = IpAddress(family: IpAddressFamily.IPv6) - let s = cast[ptr Sockaddr_in6](unsafeAddr sa) + let s = cast[ptr Sockaddr_in6](sa) copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6)) port = ntohs(s.sin6_port).Port else: raise newException(ObjectConversionError, "Unexpected SockAddr/Socklen") +proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, + sl: Socklen, address: var IpAddress, port: var Port) {.inline.} = + ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises + ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. + fromSockAddrAux(unsafeAddr sa, sl, address, port) + when defineSsl: CRYPTO_malloc_init() doAssert SslLibraryInit() == 1 From 0770844285257b27f34b1f16a9fe4df08394a06a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sat, 24 Mar 2018 22:55:06 +0200 Subject: [PATCH 4/7] Comments addressed --- lib/pure/net.nim | 2 +- lib/windows/winlean.nim | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index f16d496b42..336068df05 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -443,7 +443,7 @@ proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, address: var IpAddre copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6)) port = ntohs(s.sin6_port).Port else: - raise newException(ObjectConversionError, "Unexpected SockAddr/Socklen") + raise newException(ValueError, "Neither IPv4 nor IPv6") proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, sl: Socklen, address: var IpAddress, port: var Port) {.inline.} = diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index b2afd3f698..a0c784637a 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -484,6 +484,9 @@ type Sockaddr_storage* {.importc: "SOCKADDR_STORAGE", header: "winsock2.h".} = object ss_family*: int16 + ss_pad1: array[6, byte] + ss_align: int64 + ss_pad2: array[112, byte] Servent* = object s_name*: cstring From 759023e157806bf9cdeb9f442002367a55fb8698 Mon Sep 17 00:00:00 2001 From: data-man Date: Sun, 1 Apr 2018 00:41:38 +0300 Subject: [PATCH 5/7] Comparing datetimes --- lib/pure/times.nim | 12 ++++++++++++ tests/stdlib/ttimes.nim | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 6c1e1fe877..75b5bac439 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -274,6 +274,18 @@ proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = # so we need to compensate for that here. result.inc dt.utcOffset +proc `<`*(a, b: DateTime): bool = + ## Returns true iff ``a < b``, that is iff a happened before b. + return a.toTime < b.toTime + +proc `<=` * (a, b: DateTime): bool = + ## Returns true iff ``a <= b``. + return a.toTime <= b.toTime + +proc `==`*(a, b: DateTime): bool = + ## Returns true if ``a == b``, that is if both dates represent the same point in datetime. + return a.toTime == b.toTime + proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime = let adjTime = zt.adjTime.int64 let epochday = (if adjTime >= 0: adjTime else: adjTime - (secondsInDay - 1)) div secondsInDay diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index ae056a79fd..8efc500868 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -367,4 +367,12 @@ suite "ttimes": check $(dt - 1.months) == "2017-02-15T00:00:00+00:00" dt = initDateTime(31, mMar, 2017, 00, 00, 00, utc()) # This happens due to monthday overflow. It's consistent with Phobos. - check $(dt - 1.months) == "2017-03-03T00:00:00+00:00" \ No newline at end of file + check $(dt - 1.months) == "2017-03-03T00:00:00+00:00" + + test "compare datetimes": + var dt1 = now() + var dt2 = dt1 + check dt1 == dt2 + check dt1 <= dt2 + dt2 = dt2 + 1.seconds + check dt1 < dt2 From 9e51e737b6216fa373662442907874d7b61db1a6 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Sun, 1 Apr 2018 20:17:32 +0800 Subject: [PATCH 6/7] RLIMIT_NOFILE as posix const --- lib/posix/posix_linux_amd64_consts.nim | 3 +++ lib/posix/posix_other_consts.nim | 3 +++ lib/pure/ioselects/ioselectors_epoll.nim | 6 ++---- lib/pure/ioselects/ioselectors_poll.nim | 6 ++---- tools/detect/detect.nim | 3 +++ 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 4b693960e6..ee4fac1e86 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -433,6 +433,9 @@ const POSIX_MADV_WILLNEED* = cint(3) const POSIX_MADV_DONTNEED* = cint(4) const MAP_POPULATE* = cint(32768) +# +const RLIMIT_NOFILE* = cint(7) + # const FD_SETSIZE* = cint(1024) diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 003414a6a8..1b27fc5f64 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -451,6 +451,9 @@ var POSIX_TYPED_MEM_ALLOCATE* {.importc: "POSIX_TYPED_MEM_ALLOCATE", header: "".}: cint var POSIX_TYPED_MEM_MAP_ALLOCATABLE* {.importc: "POSIX_TYPED_MEM_MAP_ALLOCATABLE", header: "".}: cint +# +var RLIMIT_NOFILE* {.importc: "RLIMIT_NOFILE", header: "".}: cint + # var FD_SETSIZE* {.importc: "FD_SETSIZE", header: "".}: cint diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 98b8a2b2bb..65efeabab3 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -48,8 +48,6 @@ when not defined(android): proc signalfd(fd: cint, mask: var Sigset, flags: cint): cint {.cdecl, importc: "signalfd", header: "".} -var RLIMIT_NOFILE {.importc: "RLIMIT_NOFILE", - header: "".}: cint type RLimit {.importc: "struct rlimit", header: "", pure, final.} = object @@ -82,7 +80,7 @@ type proc newSelector*[T](): Selector[T] = # Retrieve the maximum fd count (for current OS) via getrlimit() var a = RLimit() - if getrlimit(RLIMIT_NOFILE, a) != 0: + if getrlimit(posix.RLIMIT_NOFILE, a) != 0: raiseOsError(osLastError()) var maxFD = int(a.rlim_max) doAssert(maxFD > 0) @@ -528,4 +526,4 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, body2 proc getFd*[T](s: Selector[T]): int = - return s.epollFd.int \ No newline at end of file + return s.epollFd.int diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 66d52b3529..081c57fa68 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -40,8 +40,6 @@ type wfd: cint SelectEvent* = ptr SelectEventImpl -var RLIMIT_NOFILE {.importc: "RLIMIT_NOFILE", - header: "".}: cint type rlimit {.importc: "struct rlimit", header: "", pure, final.} = object @@ -64,7 +62,7 @@ else: proc newSelector*[T](): Selector[T] = var a = rlimit() - if getrlimit(RLIMIT_NOFILE, a) != 0: + if getrlimit(posix.RLIMIT_NOFILE, a) != 0: raiseIOSelectorsError(osLastError()) var maxFD = int(a.rlim_max) @@ -317,4 +315,4 @@ template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, proc getFd*[T](s: Selector[T]): int = - return -1 \ No newline at end of file + return -1 diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index 1b016cef9c..5b4fdc99e6 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -586,6 +586,9 @@ v("POSIX_TYPED_MEM_ALLOCATE_CONTIG") v("POSIX_TYPED_MEM_MAP_ALLOCATABLE") v("MAP_POPULATE", no_other = true) +header("") +v("RLIMIT_NOFILE") + header("") v("FD_SETSIZE") From 0b99e8e8cb8dfe3de8d3fa38cc48f919acd0fe4c Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Mon, 2 Apr 2018 22:54:27 +0300 Subject: [PATCH 7/7] Fix compiler stuck on waiting C/CPP backends. (#7472) --- lib/pure/osproc.nim | 8 +++++++- lib/windows/winlean.nim | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index c1c727fc66..555626514a 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -494,7 +494,7 @@ when defined(Windows) and not defined(useNimRtl): sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint sa.lpSecurityDescriptor = nil sa.bInheritHandle = 1 - if createPipe(rdHandle, wrHandle, sa, 1024) == 0'i32: + if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32: raiseOSError(osLastError()) proc fileClose(h: Handle) {.inline.} = @@ -524,6 +524,12 @@ when defined(Windows) and not defined(useNimRtl): he = ho else: createPipeHandles(he, si.hStdError) + if setHandleInformation(he, DWORD(1), DWORD(0)) == 0'i32: + raiseOsError(osLastError()) + if setHandleInformation(hi, DWORD(1), DWORD(0)) == 0'i32: + raiseOsError(osLastError()) + if setHandleInformation(ho, DWORD(1), DWORD(0)) == 0'i32: + raiseOsError(osLastError()) else: createAllPipeHandles(si, hi, ho, he, cast[int](result)) result.inHandle = FileHandle(hi) diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index a0c784637a..f403443967 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -704,6 +704,11 @@ proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "DuplicateHandle".} + +proc setHandleInformation*(hObject: HANDLE, dwMask: DWORD, + dwFlags: DWORD): WINBOOL {.stdcall, + dynlib: "kernel32", importc: "SetHandleInformation".} + proc getCurrentProcess*(): HANDLE{.stdcall, dynlib: "kernel32", importc: "GetCurrentProcess".}