From 64583b4269b7e51c01d4af4346bad4869e7600ed Mon Sep 17 00:00:00 2001 From: cheatfate Date: Tue, 25 Feb 2020 23:50:39 +0200 Subject: [PATCH] Fix Windows datagram's AnyAddress issue. Add test for datagram's AnyAddress. Bump version to 2.3.6. --- chronos.nimble | 2 +- chronos/transports/common.nim | 15 ++++++++++ chronos/transports/datagram.nim | 8 ++++-- chronos/transports/stream.nim | 12 +------- tests/testdatagram.nim | 51 +++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/chronos.nimble b/chronos.nimble index 04543c2..9526d72 100644 --- a/chronos.nimble +++ b/chronos.nimble @@ -1,5 +1,5 @@ packageName = "chronos" -version = "2.3.5" +version = "2.3.6" author = "Status Research & Development GmbH" description = "Chronos" license = "Apache License 2.0 or MIT" diff --git a/chronos/transports/common.nim b/chronos/transports/common.nim index 6dd5715..976f09b 100644 --- a/chronos/transports/common.nim +++ b/chronos/transports/common.nim @@ -448,6 +448,21 @@ proc resolveTAddress*(address: string, port: Port, elif family == IpAddressFamily.IPv6: result = resolveTAddress(address, port, AddressFamily.IPv6) +proc windowsAnyAddressFix*(a: TransportAddress): TransportAddress {.inline.} = + ## BSD Sockets on *nix systems are able to perform connections to + ## `0.0.0.0` or `::0` which are equal to `127.0.0.1` or `::1`. + when defined(windows): + if (a.family == AddressFamily.IPv4 and + a.address_v4 == AnyAddress.address_v4): + result = initTAddress("127.0.0.1", a.port) + elif (a.family == AddressFamily.IPv6 and + a.address_v6 == AnyAddress6.address_v6): + result = initTAddress("::1", a.port) + else: + result = a + else: + result = a + template checkClosed*(t: untyped) = if (ReadClosed in (t).state) or (WriteClosed in (t).state): raise newException(TransportError, "Transport is already closed!") diff --git a/chronos/transports/datagram.nim b/chronos/transports/datagram.nim index 0cc4ae5..6525b54 100644 --- a/chronos/transports/datagram.nim +++ b/chronos/transports/datagram.nim @@ -165,7 +165,8 @@ when defined(windows): transp.setWriterWSABuffer(vector) var ret: cint if vector.kind == WithAddress: - toSAddr(vector.address, transp.waddr, transp.walen) + var fixedAddress = windowsAnyAddressFix(vector.address) + toSAddr(fixedAddress, transp.waddr, transp.walen) ret = WSASendTo(fd, addr transp.wwsabuf, DWORD(1), addr bytesCount, DWORD(0), cast[ptr SockAddr](addr transp.waddr), cint(transp.walen), @@ -359,16 +360,17 @@ when defined(windows): raiseTransportOsError(err) if remote.port != Port(0): + var fixedAddress = windowsAnyAddressFix(remote) var saddr: Sockaddr_storage var slen: SockLen - toSAddr(remote, saddr, slen) + toSAddr(fixedAddress, saddr, slen) if connect(SocketHandle(localSock), cast[ptr SockAddr](addr saddr), slen) != 0: let err = osLastError() if sock == asyncInvalidSocket: closeSocket(localSock) raiseTransportOsError(err) - result.remote = remote + result.remote = fixedAddress result.fd = localSock result.function = cbproc diff --git a/chronos/transports/stream.nim b/chronos/transports/stream.nim index 4a619cc..bdf550d 100644 --- a/chronos/transports/stream.nim +++ b/chronos/transports/stream.nim @@ -685,18 +685,8 @@ when defined(windows): sock: AsyncFD povl: RefCustomOverlapped proto: Protocol - raddress: TransportAddress - ## BSD Sockets on *nix systems are able to perform connections to - ## `0.0.0.0` or `::0` which are equal to `127.0.0.1` or `::1`. - if (address.family == AddressFamily.IPv4 and - address.address_v4 == AnyAddress.address_v4): - raddress = initTAddress("127.0.0.1", address.port) - elif (address.family == AddressFamily.IPv6 and - address.address_v6 == AnyAddress6.address_v6): - raddress = initTAddress("::1", address.port) - else: - raddress = address + var raddress = windowsAnyAddressFix(address) toSAddr(raddress, saddr, slen) proto = Protocol.IPPROTO_TCP diff --git a/tests/testdatagram.nim b/tests/testdatagram.nim index 01ca7b2..d6557f2 100644 --- a/tests/testdatagram.nim +++ b/tests/testdatagram.nim @@ -483,6 +483,55 @@ suite "Datagram Transport test suite": await wait(dgram1.join(), 5.seconds) result = res + proc testAnyAddress(): Future[int] {.async.} = + var expectStr = "ANYADDRESS MESSAGE" + var expectSeq = cast[seq[byte]](expectStr) + let ta = initTAddress("0.0.0.0:0") + var res = 0 + var event = newAsyncEvent() + + proc clientMark1(transp: DatagramTransport, + raddr: TransportAddress): Future[void] {.async.} = + var bmsg = transp.getMessage() + var smsg = cast[string](bmsg) + if smsg == expectStr: + inc(res) + event.fire() + + proc clientMark2(transp: DatagramTransport, + raddr: TransportAddress): Future[void] {.async.} = + discard + + var dgram1 = newDatagramTransport(clientMark1, local = ta) + let la = dgram1.localAddress() + var dgram2 = newDatagramTransport(clientMark2) + var dgram3 = newDatagramTransport(clientMark2, + remote = la) + await dgram2.sendTo(la, addr expectStr[0], len(expectStr)) + await event.wait() + event.clear() + await dgram2.sendTo(la, expectStr) + await event.wait() + event.clear() + await dgram2.sendTo(la, expectSeq) + await event.wait() + event.clear() + await dgram3.send(addr expectStr[0], len(expectStr)) + await event.wait() + event.clear() + await dgram3.send(expectStr) + await event.wait() + event.clear() + await dgram3.send(expectSeq) + await event.wait() + event.clear() + + await dgram1.closeWait() + await dgram2.closeWait() + await dgram3.closeWait() + + result = res + test "close(transport) test": check waitFor(testTransportClose()) == true test m1: @@ -505,5 +554,7 @@ suite "Datagram Transport test suite": check waitFor(testConnReset()) == true test "Broadcast test": check waitFor(testBroadcast()) == 1 + test "0.0.0.0/::0 (INADDR_ANY) test": + check waitFor(testAnyAddress()) == 6 test "Transports leak test": check getTracker("datagram.transport").isLeaked() == false