From 960b675d627c2dd4ce9bced98a15242233545b8f Mon Sep 17 00:00:00 2001 From: cheatfate Date: Sat, 2 Jun 2018 17:25:26 +0300 Subject: [PATCH] Changed TransportAddress API. Introduced resolveTAddress(). Added TransportAddress tests. --- asyncdispatch2.nimble | 4 ++ asyncdispatch2/transports/common.nim | 61 ++++++++++++++++++++++++-- asyncdispatch2/transports/datagram.nim | 10 ++--- tests/testaddress.nim | 59 +++++++++++++++++++++++++ tests/testdatagram.nim | 12 ++--- tests/teststream.nim | 8 ++-- 6 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 tests/testaddress.nim diff --git a/asyncdispatch2.nimble b/asyncdispatch2.nimble index 6dd81713..8cc818c5 100644 --- a/asyncdispatch2.nimble +++ b/asyncdispatch2.nimble @@ -30,6 +30,10 @@ task test, "Run all tests": exec "nim c -r tests/testsignal" exec "nim c -r -d:release tests/testsignal" + exec "nim c -r -d:useSysAssert -d:useGcAssert tests/testaddress" + exec "nim c -r tests/testaddress" + exec "nim c -r -d:release tests/testaddress" + exec "nim c -r -d:useSysAssert -d:useGcAssert tests/testdatagram" exec "nim c -r tests/testdatagram" exec "nim c -r -d:release tests/testdatagram" diff --git a/asyncdispatch2/transports/common.nim b/asyncdispatch2/transports/common.nim index 8809830b..eee81f77 100644 --- a/asyncdispatch2/transports/common.nim +++ b/asyncdispatch2/transports/common.nim @@ -7,7 +7,7 @@ # Apache License, version 2.0, (LICENSE-APACHEv2) # MIT license (LICENSE-MIT) -import net, strutils +import net, nativesockets, strutils import ../asyncloop, ../asyncsync const @@ -102,7 +102,7 @@ proc `$`*(address: TransportAddress): string = result.add(":") result.add($int(address.port)) -proc strAddress*(address: string): TransportAddress = +proc initTAddress*(address: string): TransportAddress = ## Parses string representation of ``address``. ## ## IPv4 transport address format is ``a.b.c.d:port``. @@ -110,13 +110,65 @@ proc strAddress*(address: string): TransportAddress = var parts = address.rsplit(":", maxsplit = 1) doAssert(len(parts) == 2, "Format is
:!") let port = parseInt(parts[1]) - doAssert(port > 0 and port < 65536, "Illegal port number!") + doAssert(port >= 0 and port < 65536, "Illegal port number!") result.port = Port(port) if parts[0][0] == '[' and parts[0][^1] == ']': result.address = parseIpAddress(parts[0][1..^2]) else: result.address = parseIpAddress(parts[0]) +proc initTAddress*(address: string, port: Port): TransportAddress = + ## Initialize ``TransportAddress`` with IP address ``address`` and + ## port number ``port``. + result.address = parseIpAddress(address) + result.port = port + +proc initTAddress*(address: string, port: int): TransportAddress = + ## Initialize ``TransportAddress`` with IP address ``address`` and + ## port number ``port``. + result.address = parseIpAddress(address) + result.port = Port(Port(port and 0xFFFF)) + +proc resolveTAddress*(address: string, + family = IpAddressFamily.IPv4): seq[TransportAddress] = + ## Resolve string representation of ``address``. + ## + ## Supported formats are: + ## IPv4 numeric address ``a.b.c.d:port`` + ## IPv6 numeric address ``[::]:port`` + ## Hostname address ``hostname:port`` + ## + ## If hostname address is detected, then network address translation via DNS + ## will be performed. + var + ta: TransportAddress + ap: Port + result = newSeq[TransportAddress]() + var parts = address.rsplit(":", maxsplit = 1) + doAssert(len(parts) == 2, "Format is
:!") + let port = parseInt(parts[1]) + doAssert(port >= 0 and port < 65536, "Illegal port number!") + if parts[0][0] == '[' and parts[0][^1] == ']': + ta = TransportAddress(address: parseIpAddress(parts[0][1..^2]), + port: Port(port)) + result.add(ta) + else: + if isIpAddress(parts[0]): + ta = TransportAddress(address: parseIpAddress(parts[0]), + port: Port(port)) + result.add(ta) + else: + var domain = if family == IpAddressFamily.IPv4: Domain(AF_INET) else: + Domain(AF_INET6) + var aiList = getAddrInfo(parts[0], Port(port), domain) + var it = aiList + while it != nil: + fromSockAddr(cast[ptr Sockaddr_storage](it.ai_addr)[], + SockLen(it.ai_addrlen), ta.address, ta.port) + result.add(ta) + it = it.ai_next + freeAddrInfo(aiList) + template checkClosed*(t: untyped) = if (ReadClosed in (t).state) or (WriteClosed in (t).state): raise newException(TransportError, "Transport is already closed!") @@ -133,3 +185,6 @@ when defined(windows): const ERROR_SUCCESS* = 0 proc cancelIo*(hFile: HANDLE): WINBOOL {.stdcall, dynlib: "kernel32", importc: "CancelIo".} + +when isMainModule: + echo $resolveTAddress("localhost:443", IpAddressFamily.IPv6) \ No newline at end of file diff --git a/asyncdispatch2/transports/datagram.nim b/asyncdispatch2/transports/datagram.nim index f49e594d..f6cad55b 100644 --- a/asyncdispatch2/transports/datagram.nim +++ b/asyncdispatch2/transports/datagram.nim @@ -36,6 +36,11 @@ else: writer: Future[void] # Writer vector completion Future type + DatagramServer* = ref object of RootRef + ## Datagram server object + transport*: DatagramTransport ## Datagram transport + status*: ServerStatus ## Current server status + DatagramCallback* = proc(transp: DatagramTransport, pbytes: pointer, nbytes: int, @@ -558,11 +563,6 @@ proc sendTo*(transp: DatagramTransport, pbytes: pointer, nbytes: int, if WriteError in transp.state: raise transp.getError() -type - DatagramServer* = ref object of RootRef - transport*: DatagramTransport - status*: ServerStatus - proc createDatagramServer*(host: TransportAddress, cbproc: DatagramCallback, flags: set[ServerFlags] = {}, diff --git a/tests/testaddress.nim b/tests/testaddress.nim new file mode 100644 index 00000000..6e7c6a06 --- /dev/null +++ b/tests/testaddress.nim @@ -0,0 +1,59 @@ +# Asyncdispatch2 Test Suite +# (c) Copyright 2018 +# Status Research & Development GmbH +# +# Licensed under either of +# Apache License, version 2.0, (LICENSE-APACHEv2) +# MIT license (LICENSE-MIT) + +import strutils, unittest +import ../asyncdispatch2 + +when isMainModule: + suite "TransportAddress test suite": + test "initTAddress(string)": + check $initTAddress("0.0.0.0:0") == "0.0.0.0:0" + check $initTAddress("255.255.255.255:65535") == "255.255.255.255:65535" + check $initTAddress("[::]:0") == "[::]:0" + check $initTAddress("[FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]:65535") == + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535" + test "initTAddress(string, Port)": + check $initTAddress("0.0.0.0", Port(0)) == "0.0.0.0:0" + check $initTAddress("255.255.255.255", Port(65535)) == + "255.255.255.255:65535" + check $initTAddress("::", Port(0)) == "[::]:0" + check $initTAddress("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", + Port(65535)) == + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535" + test "initTAddress(string, int)": + check $initTAddress("0.0.0.0", 0) == "0.0.0.0:0" + check $initTAddress("255.255.255.255", 65535) == + "255.255.255.255:65535" + check $initTAddress("::", 0) == "[::]:0" + check $initTAddress("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", 65535) == + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535" + test "resolveTAddress(string)": + var numeric = [ + "0.0.0.0:0", + "255.0.0.255:54321", + "128.128.128.128:12345", + "255.255.255.255:65535", + "[::]:0", + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535", + "[aaaa:bbbb:cccc:dddd:eeee:ffff::1111]:12345", + "[aaaa:bbbb:cccc:dddd:eeee:ffff::]:12345", + "[a:b:c:d:e:f::]:12345", + "[2222:3333:4444:5555:6666:7777:8888:9999]:56789" + ] + var hostnames = [ + "www.google.com:443", + "www.github.com:443" + ] + for item in numeric: + var taseq = resolveTAddress(item) + check len(taseq) == 1 + check $taseq[0] == item + + for item in hostnames: + var taseq = resolveTAddress(item) + check len(taseq) >= 1 diff --git a/tests/testdatagram.nim b/tests/testdatagram.nim index ed91d736..dad4d34e 100644 --- a/tests/testdatagram.nim +++ b/tests/testdatagram.nim @@ -46,7 +46,7 @@ proc client2(transp: DatagramTransport, pbytes: pointer, nbytes: int, if counterPtr[] == TestsCount: transp.close() else: - var ta = strAddress("127.0.0.1:33336") + var ta = initTAddress("127.0.0.1:33336") var req = "REQUEST" & $counterPtr[] await transp.sendTo(addr req[0], len(req), ta) else: @@ -119,7 +119,7 @@ proc client5(transp: DatagramTransport, pbytes: pointer, nbytes: int, if counterPtr[] == MessagesCount: transp.close() else: - var ta = strAddress("127.0.0.1:33337") + var ta = initTAddress("127.0.0.1:33337") var req = "REQUEST" & $counterPtr[] await transp.sendTo(addr req[0], len(req), ta) else: @@ -133,7 +133,7 @@ proc client5(transp: DatagramTransport, pbytes: pointer, nbytes: int, transp.close() proc test1(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:33336") + var ta = initTAddress("127.0.0.1:33336") var counter = 0 var dgram1 = newDatagramTransport(client1, udata = addr counter, local = ta) var dgram2 = newDatagramTransport(client2, udata = addr counter) @@ -144,7 +144,7 @@ proc test1(): Future[int] {.async.} = result = counter proc test2(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:33337") + var ta = initTAddress("127.0.0.1:33337") var counter = 0 var dgram1 = newDatagramTransport(client1, udata = addr counter, local = ta) var dgram2 = newDatagramTransport(client3, udata = addr counter, remote = ta) @@ -166,7 +166,7 @@ proc waitAll(futs: seq[Future[void]]): Future[void] = return retFuture proc test3(bounded: bool): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:33337") + var ta = initTAddress("127.0.0.1:33337") var counter = 0 var dgram1 = newDatagramTransport(client1, udata = addr counter, local = ta) var clients = newSeq[Future[void]](ClientsCount) @@ -265,7 +265,7 @@ proc serveDatagramClient(transp: DatagramTransport, await transp.sendTo(addr answer[0], len(answer), raddr) proc test4(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:31346") + var ta = initTAddress("127.0.0.1:31346") var counter = 0 var server = createDatagramServer(ta, serveDatagramClient, {ReuseAddr}) server.start() diff --git a/tests/teststream.nim b/tests/teststream.nim index 6dd58733..a1dd3488 100644 --- a/tests/teststream.nim +++ b/tests/teststream.nim @@ -244,7 +244,7 @@ proc swarmManager4(address: TransportAddress): Future[int] {.async.} = result += res proc test1(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:31344") + var ta = initTAddress("127.0.0.1:31344") var server = createStreamServer(ta, serveClient1, {ReuseAddr}) server.start() result = await swarmManager1(ta) @@ -252,7 +252,7 @@ proc test1(): Future[int] {.async.} = server.close() proc test2(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:31345") + var ta = initTAddress("127.0.0.1:31345") var counter = 0 var server = createStreamServer(ta, serveClient2, {ReuseAddr}) server.start() @@ -261,7 +261,7 @@ proc test2(): Future[int] {.async.} = server.close() proc test3(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:31346") + var ta = initTAddress("127.0.0.1:31346") var counter = 0 var server = createStreamServer(ta, serveClient3, {ReuseAddr}) server.start() @@ -270,7 +270,7 @@ proc test3(): Future[int] {.async.} = server.close() proc test4(): Future[int] {.async.} = - var ta = strAddress("127.0.0.1:31347") + var ta = initTAddress("127.0.0.1:31347") var counter = 0 var server = createStreamServer(ta, serveClient4, {ReuseAddr}) server.start()