2019-02-06 14:49:11 +00:00
|
|
|
# Chronos Test Suite
|
|
|
|
# (c) Copyright 2018-Present
|
2018-05-21 21:52:57 +00:00
|
|
|
# Status Research & Development GmbH
|
|
|
|
#
|
|
|
|
# Licensed under either of
|
|
|
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
|
|
|
# MIT license (LICENSE-MIT)
|
exception tracking (#166)
* exception tracking
This PR adds minimal exception tracking to chronos, moving the goalpost
one step further.
In particular, it becomes invalid to raise exceptions from `callSoon`
callbacks: this is critical for writing correct error handling because
there's no reasonable way that a user of chronos can possibly _reason_
about exceptions coming out of there: the event loop will be in an
indeterminite state when the loop is executing an _random_ callback.
As expected, there are several issues in the error handling of chronos:
in particular, it will end up in an inconsistent internal state whenever
the selector loop operations fail, because the internal state update
functions are not written in an exception-safe way. This PR turns this
into a Defect, which probably is not the optimal way of handling things
- expect more work to be done here.
Some API have no way of reporting back errors to callers - for example,
when something fails in the accept loop, there's not much it can do, and
no way to report it back to the user of the API - this has been fixed
with the new accept flow - the old one should be deprecated.
Finally, there is information loss in the API: in composite operations
like `poll` and `waitFor` there's no way to differentiate internal
errors from user-level errors originating from callbacks.
* store `CatchableError` in future
* annotate proc's with correct raises information
* `selectors2` to avoid non-CatchableError IOSelectorsException
* `$` should never raise
* remove unnecessary gcsafe annotations
* fix exceptions leaking out of timer waits
* fix some imports
* functions must signal raising the union of all exceptions across all
platforms to enable cross-platform code
* switch to unittest2
* add `selectors2` which supercedes the std library version and fixes
several exception handling issues in there
* fixes
* docs, platform-independent eh specifiers for some functions
* add feature flag for strict exception mode
also bump version to 3.0.0 - _most_ existing code should be compatible
with this version of exception handling but some things might need
fixing - callbacks, existing raises specifications etc.
* fix AsyncCheck for non-void T
2021-03-24 09:08:33 +00:00
|
|
|
import std/[strutils, os]
|
2023-07-14 10:35:08 +00:00
|
|
|
import ".."/chronos/unittest2/asynctests
|
2023-04-30 06:20:08 +00:00
|
|
|
import ".."/chronos, ".."/chronos/[osdefs, oserrno]
|
2018-05-16 08:22:34 +00:00
|
|
|
|
2023-03-31 05:35:04 +00:00
|
|
|
{.used.}
|
2019-10-24 13:01:57 +00:00
|
|
|
|
2018-05-21 21:52:57 +00:00
|
|
|
when defined(windows):
|
2023-02-21 10:48:36 +00:00
|
|
|
proc get_osfhandle*(fd: FileHandle): HANDLE {.
|
|
|
|
importc: "_get_osfhandle", header:"<io.h>".}
|
2018-05-21 21:52:57 +00:00
|
|
|
|
2019-03-30 22:31:10 +00:00
|
|
|
suite "Stream Transport test suite":
|
2024-01-18 12:34:16 +00:00
|
|
|
teardown:
|
|
|
|
checkLeaks()
|
|
|
|
|
2018-05-21 21:52:57 +00:00
|
|
|
const
|
2019-03-30 22:31:10 +00:00
|
|
|
ConstantMessage = "SOMEDATA"
|
|
|
|
BigMessagePattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
FilesTestName = "tests/teststream.nim"
|
|
|
|
BigMessageCount = 100
|
|
|
|
ClientsCount = 5
|
|
|
|
MessagesCount = 10
|
|
|
|
MessageSize = 20
|
|
|
|
FilesCount = 10
|
2020-06-24 08:21:52 +00:00
|
|
|
TestsCount = 100
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2018-10-25 10:19:19 +00:00
|
|
|
when defined(windows):
|
2020-06-24 08:21:52 +00:00
|
|
|
let addresses = [
|
2018-10-25 10:19:19 +00:00
|
|
|
initTAddress("127.0.0.1:33335"),
|
|
|
|
initTAddress(r"/LOCAL\testpipe")
|
|
|
|
]
|
|
|
|
else:
|
2020-06-24 08:21:52 +00:00
|
|
|
let addresses = [
|
2023-08-08 00:10:28 +00:00
|
|
|
initTAddress("127.0.0.1:0"),
|
2018-10-25 10:19:19 +00:00
|
|
|
initTAddress(r"/tmp/testpipe")
|
|
|
|
]
|
2020-06-24 08:21:52 +00:00
|
|
|
|
|
|
|
let prefixes = ["[IP] ", "[UNIX] "]
|
|
|
|
|
|
|
|
var markFD: int
|
|
|
|
|
|
|
|
proc getCurrentFD(): int =
|
2023-08-08 00:10:28 +00:00
|
|
|
let local = initTAddress("127.0.0.1:0")
|
2020-06-24 08:21:52 +00:00
|
|
|
let sock = createAsyncSocket(local.getDomain(), SockType.SOCK_DGRAM,
|
|
|
|
Protocol.IPPROTO_UDP)
|
|
|
|
closeSocket(sock)
|
|
|
|
return int(sock)
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2020-02-12 20:54:05 +00:00
|
|
|
proc createBigMessage(size: int): seq[byte] =
|
|
|
|
var message = "MESSAGE"
|
|
|
|
result = newSeq[byte](size)
|
|
|
|
for i in 0 ..< len(result):
|
|
|
|
result[i] = byte(message[i mod len(message)])
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient1(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
while not transp.atEof():
|
|
|
|
var data = await transp.readLine()
|
|
|
|
if len(data) == 0:
|
|
|
|
doAssert(transp.atEof())
|
|
|
|
break
|
|
|
|
doAssert(data.startsWith("REQUEST"))
|
|
|
|
var numstr = data[7..^1]
|
|
|
|
var num = parseInt(numstr)
|
|
|
|
var ans = "ANSWER" & $num & "\r\n"
|
|
|
|
var res = await transp.write(cast[pointer](addr ans[0]), len(ans))
|
|
|
|
doAssert(res == len(ans))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient2(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var buffer: array[20, char]
|
|
|
|
var check = "REQUEST"
|
|
|
|
while not transp.atEof():
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
try:
|
|
|
|
await transp.readExactly(addr buffer[0], MessageSize)
|
|
|
|
except TransportIncompleteError:
|
|
|
|
break
|
|
|
|
doAssert(equalMem(addr buffer[0], addr check[0], len(check)))
|
|
|
|
var numstr = ""
|
|
|
|
var i = 7
|
|
|
|
while i < MessageSize and (buffer[i] in {'0'..'9'}):
|
|
|
|
numstr.add(buffer[i])
|
|
|
|
inc(i)
|
|
|
|
var num = parseInt(numstr)
|
|
|
|
var ans = "ANSWER" & $num
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
copyMem(addr buffer[0], addr ans[0], len(ans))
|
|
|
|
var res = await transp.write(cast[pointer](addr buffer[0]), MessageSize)
|
|
|
|
doAssert(res == MessageSize)
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient3(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var buffer: array[20, char]
|
|
|
|
var check = "REQUEST"
|
|
|
|
var suffixStr = "SUFFIX"
|
|
|
|
var suffix = newSeq[byte](6)
|
|
|
|
copyMem(addr suffix[0], addr suffixStr[0], len(suffixStr))
|
|
|
|
var counter = MessagesCount
|
|
|
|
while counter > 0:
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
var res = await transp.readUntil(addr buffer[0], MessageSize, suffix)
|
|
|
|
doAssert(equalMem(addr buffer[0], addr check[0], len(check)))
|
|
|
|
var numstr = ""
|
|
|
|
var i = 7
|
|
|
|
while i < MessageSize and (buffer[i] in {'0'..'9'}):
|
|
|
|
numstr.add(buffer[i])
|
|
|
|
inc(i)
|
|
|
|
var num = parseInt(numstr)
|
|
|
|
doAssert(len(numstr) < 8)
|
|
|
|
var ans = "ANSWER" & $num & "SUFFIX"
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
copyMem(addr buffer[0], addr ans[0], len(ans))
|
|
|
|
res = await transp.write(cast[pointer](addr buffer[0]), len(ans))
|
|
|
|
doAssert(res == len(ans))
|
|
|
|
dec(counter)
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient4(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var pathname = await transp.readLine()
|
|
|
|
var size = await transp.readLine()
|
|
|
|
var sizeNum = parseInt(size)
|
|
|
|
doAssert(sizeNum >= 0)
|
|
|
|
var rbuffer = newSeq[byte](sizeNum)
|
|
|
|
await transp.readExactly(addr rbuffer[0], sizeNum)
|
|
|
|
var lbuffer = readFile(pathname)
|
|
|
|
doAssert(len(lbuffer) == sizeNum)
|
|
|
|
doAssert(equalMem(addr rbuffer[0], addr lbuffer[0], sizeNum))
|
|
|
|
var answer = "OK\r\n"
|
|
|
|
var res = await transp.write(cast[pointer](addr answer[0]), len(answer))
|
|
|
|
doAssert(res == len(answer))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient7(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var answer = "DONE\r\n"
|
|
|
|
var expect = ""
|
|
|
|
var line = await transp.readLine()
|
|
|
|
doAssert(len(line) == BigMessageCount * len(BigMessagePattern))
|
|
|
|
for i in 0..<BigMessageCount:
|
|
|
|
expect.add(BigMessagePattern)
|
|
|
|
doAssert(line == expect)
|
|
|
|
var res = await transp.write(answer)
|
|
|
|
doAssert(res == len(answer))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient8(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var answer = "DONE\r\n"
|
|
|
|
var strpattern = BigMessagePattern
|
|
|
|
var pattern = newSeq[byte](len(BigMessagePattern))
|
|
|
|
var expect = newSeq[byte]()
|
|
|
|
var data = newSeq[byte]((BigMessageCount + 1) * len(BigMessagePattern))
|
|
|
|
var sep = @[0x0D'u8, 0x0A'u8]
|
|
|
|
copyMem(addr pattern[0], addr strpattern[0], len(BigMessagePattern))
|
|
|
|
var count = await transp.readUntil(addr data[0], len(data), sep = sep)
|
|
|
|
doAssert(count == BigMessageCount * len(BigMessagePattern) + 2)
|
|
|
|
for i in 0..<BigMessageCount:
|
|
|
|
expect.add(pattern)
|
|
|
|
expect.add(sep)
|
|
|
|
data.setLen(count)
|
|
|
|
doAssert(expect == data)
|
|
|
|
var res = await transp.write(answer)
|
|
|
|
doAssert(res == len(answer))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
proc swarmWorker1(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
for i in 0..<MessagesCount:
|
|
|
|
var data = "REQUEST" & $i & "\r\n"
|
|
|
|
var res = await transp.write(cast[pointer](addr data[0]), len(data))
|
|
|
|
doAssert(res == len(data))
|
|
|
|
var ans = await transp.readLine()
|
|
|
|
doAssert(ans.startsWith("ANSWER"))
|
|
|
|
var numstr = ans[6..^1]
|
|
|
|
var num = parseInt(numstr)
|
|
|
|
doAssert(num == i)
|
|
|
|
inc(result)
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmWorker2(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var buffer: array[MessageSize, char]
|
|
|
|
var check = "ANSWER"
|
|
|
|
for i in 0..<MessagesCount:
|
|
|
|
var data = "REQUEST" & $i & "\r\n"
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
copyMem(addr buffer[0], addr data[0], min(MessageSize, len(data)))
|
|
|
|
var res = await transp.write(cast[pointer](addr buffer[0]), MessageSize)
|
|
|
|
doAssert(res == MessageSize)
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
await transp.readExactly(addr buffer[0], MessageSize)
|
|
|
|
doAssert(equalMem(addr buffer[0], addr check[0], len(check)))
|
|
|
|
var numstr = ""
|
|
|
|
var k = 6
|
|
|
|
while k < MessageSize and (buffer[k] in {'0'..'9'}):
|
|
|
|
numstr.add(buffer[k])
|
|
|
|
inc(k)
|
|
|
|
var num = parseInt(numstr)
|
|
|
|
doAssert(num == i)
|
|
|
|
inc(result)
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmWorker3(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var buffer: array[MessageSize, char]
|
|
|
|
var check = "ANSWER"
|
|
|
|
var suffixStr = "SUFFIX"
|
|
|
|
var suffix = newSeq[byte](6)
|
|
|
|
copyMem(addr suffix[0], addr suffixStr[0], len(suffixStr))
|
|
|
|
for i in 0..<MessagesCount:
|
|
|
|
var data = "REQUEST" & $i & "SUFFIX"
|
|
|
|
doAssert(len(data) <= MessageSize)
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
copyMem(addr buffer[0], addr data[0], len(data))
|
|
|
|
var res = await transp.write(cast[pointer](addr buffer[0]), len(data))
|
|
|
|
doAssert(res == len(data))
|
|
|
|
zeroMem(addr buffer[0], MessageSize)
|
|
|
|
res = await transp.readUntil(addr buffer[0], MessageSize, suffix)
|
|
|
|
doAssert(equalMem(addr buffer[0], addr check[0], len(check)))
|
|
|
|
var numstr = ""
|
|
|
|
var k = 6
|
|
|
|
while k < MessageSize and (buffer[k] in {'0'..'9'}):
|
|
|
|
numstr.add(buffer[k])
|
|
|
|
inc(k)
|
|
|
|
var num = parseInt(numstr)
|
|
|
|
doAssert(num == i)
|
|
|
|
inc(result)
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmWorker4(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var ssize: string
|
|
|
|
var handle = 0
|
|
|
|
var name = FilesTestName
|
|
|
|
var size = int(getFileSize(FilesTestName))
|
|
|
|
var fhandle = open(FilesTestName)
|
|
|
|
when defined(windows):
|
|
|
|
handle = int(get_osfhandle(getFileHandle(fhandle)))
|
|
|
|
else:
|
|
|
|
handle = int(getFileHandle(fhandle))
|
|
|
|
doAssert(handle > 0)
|
|
|
|
name = name & "\r\n"
|
|
|
|
var res = await transp.write(cast[pointer](addr name[0]), len(name))
|
|
|
|
doAssert(res == len(name))
|
|
|
|
ssize = $size & "\r\n"
|
|
|
|
res = await transp.write(cast[pointer](addr ssize[0]), len(ssize))
|
|
|
|
doAssert(res == len(ssize))
|
|
|
|
var checksize = await transp.writeFile(handle, 0'u, size)
|
|
|
|
doAssert(checksize == size)
|
|
|
|
close(fhandle)
|
|
|
|
var ans = await transp.readLine()
|
|
|
|
doAssert(ans == "OK")
|
|
|
|
result = 1
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmWorker7(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var data = BigMessagePattern
|
|
|
|
var crlf = "\r\n"
|
|
|
|
for i in 0..<BigMessageCount:
|
|
|
|
var res = await transp.write(data)
|
|
|
|
doAssert(res == len(data))
|
|
|
|
var res = await transp.write(crlf)
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(res == len(crlf))
|
2019-03-30 22:31:10 +00:00
|
|
|
var line = await transp.readLine()
|
|
|
|
doAssert(line == "DONE")
|
|
|
|
result = 1
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmWorker8(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var data = BigMessagePattern
|
|
|
|
var crlf = "\r\n"
|
|
|
|
for i in 0..<BigMessageCount:
|
|
|
|
var res = await transp.write(data)
|
|
|
|
doAssert(res == len(data))
|
|
|
|
var res = await transp.write(crlf)
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(res == len(crlf))
|
2019-03-30 22:31:10 +00:00
|
|
|
var line = await transp.readLine()
|
|
|
|
doAssert(line == "DONE")
|
|
|
|
result = 1
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc waitAll[T](futs: seq[Future[T]]): Future[void] =
|
|
|
|
var counter = len(futs)
|
|
|
|
var retFuture = newFuture[void]("waitAll")
|
|
|
|
proc cb(udata: pointer) =
|
|
|
|
dec(counter)
|
|
|
|
if counter == 0:
|
|
|
|
retFuture.complete()
|
|
|
|
for fut in futs:
|
|
|
|
fut.addCallback(cb)
|
|
|
|
return retFuture
|
|
|
|
|
|
|
|
proc swarmManager1(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var workers = newSeq[Future[int]](ClientsCount)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
workers[i] = swarmWorker1(address)
|
|
|
|
await waitAll(workers)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
var res = workers[i].read()
|
|
|
|
result += res
|
|
|
|
|
|
|
|
proc swarmManager2(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var workers = newSeq[Future[int]](ClientsCount)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
workers[i] = swarmWorker2(address)
|
|
|
|
await waitAll(workers)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
var res = workers[i].read()
|
|
|
|
result += res
|
|
|
|
|
|
|
|
proc swarmManager3(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var workers = newSeq[Future[int]](ClientsCount)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
workers[i] = swarmWorker3(address)
|
|
|
|
await waitAll(workers)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
var res = workers[i].read()
|
|
|
|
result += res
|
|
|
|
|
|
|
|
proc swarmManager4(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var workers = newSeq[Future[int]](FilesCount)
|
|
|
|
for i in 0..<FilesCount:
|
|
|
|
workers[i] = swarmWorker4(address)
|
|
|
|
await waitAll(workers)
|
|
|
|
for i in 0..<FilesCount:
|
|
|
|
var res = workers[i].read()
|
|
|
|
result += res
|
|
|
|
|
|
|
|
proc test1(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient1, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmManager1(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc test2(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient2, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmManager2(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc test3(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient3, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmManager3(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc testSendFile(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient4, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmManager4(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc testWR(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var counter = ClientsCount
|
|
|
|
|
|
|
|
proc swarmWorker(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var data = ConstantMessage
|
|
|
|
for i in 0..<MessagesCount:
|
|
|
|
var res = await transp.write(data)
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(res == len(data))
|
2019-03-30 22:31:10 +00:00
|
|
|
result = MessagesCount
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmManager(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var workers = newSeq[Future[int]](ClientsCount)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
workers[i] = swarmWorker(address)
|
|
|
|
await waitAll(workers)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
var res = workers[i].read()
|
|
|
|
result += res
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var data = await transp.read()
|
|
|
|
doAssert(len(data) == len(ConstantMessage) * MessagesCount)
|
|
|
|
transp.close()
|
|
|
|
var expect = ""
|
|
|
|
for i in 0..<MessagesCount:
|
|
|
|
expect.add(ConstantMessage)
|
|
|
|
doAssert(equalMem(addr expect[0], addr data[0], len(data)))
|
|
|
|
dec(counter)
|
|
|
|
if counter == 0:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
var server = createStreamServer(address, serveClient, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmManager(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc testWCR(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var counter = ClientsCount
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var expect = ConstantMessage
|
|
|
|
var skip = await transp.consume(len(ConstantMessage) * (MessagesCount - 1))
|
|
|
|
doAssert(skip == len(ConstantMessage) * (MessagesCount - 1))
|
|
|
|
var data = await transp.read()
|
|
|
|
doAssert(len(data) == len(ConstantMessage))
|
|
|
|
transp.close()
|
|
|
|
doAssert(equalMem(addr data[0], addr expect[0], len(expect)))
|
|
|
|
dec(counter)
|
|
|
|
if counter == 0:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
proc swarmWorker(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var data = ConstantMessage
|
|
|
|
var seqdata = newSeq[byte](len(data))
|
|
|
|
copyMem(addr seqdata[0], addr data[0], len(data))
|
|
|
|
for i in 0..<MessagesCount:
|
|
|
|
var res = await transp.write(seqdata)
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(res == len(seqdata))
|
2019-03-30 22:31:10 +00:00
|
|
|
result = MessagesCount
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc swarmManager(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var workers = newSeq[Future[int]](ClientsCount)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
workers[i] = swarmWorker(address)
|
|
|
|
await waitAll(workers)
|
|
|
|
for i in 0..<ClientsCount:
|
|
|
|
var res = workers[i].read()
|
|
|
|
result += res
|
|
|
|
|
|
|
|
var server = createStreamServer(address, serveClient, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmManager(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc test7(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient7, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmWorker7(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc test8(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient8, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmWorker8(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
await server.join()
|
|
|
|
|
|
|
|
# proc serveClient9(server: StreamServer, transp: StreamTransport) {.async.} =
|
|
|
|
# var expect = ""
|
|
|
|
# for i in 0..<BigMessageCount:
|
|
|
|
# expect.add(BigMessagePattern)
|
|
|
|
# var res = await transp.write(expect)
|
|
|
|
# doAssert(res == len(expect))
|
|
|
|
# transp.close()
|
|
|
|
# await transp.join()
|
|
|
|
|
|
|
|
# proc swarmWorker9(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
# var transp = await connect(address)
|
|
|
|
# var expect = ""
|
|
|
|
# for i in 0..<BigMessageCount:
|
|
|
|
# expect.add(BigMessagePattern)
|
|
|
|
# var line = await transp.readLine()
|
|
|
|
# if line == expect:
|
|
|
|
# result = 1
|
|
|
|
# else:
|
|
|
|
# result = 0
|
|
|
|
# transp.close()
|
|
|
|
# await transp.join()
|
|
|
|
|
|
|
|
# proc test9(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
# let flags = {ReuseAddr, NoPipeFlash}
|
|
|
|
# var server = createStreamServer(address, serveClient9, flags)
|
|
|
|
# server.start()
|
|
|
|
# result = await swarmWorker9(address)
|
|
|
|
# server.stop()
|
|
|
|
# server.close()
|
|
|
|
# await server.join()
|
|
|
|
|
|
|
|
# proc serveClient10(server: StreamServer, transp: StreamTransport) {.async.} =
|
|
|
|
# var expect = ""
|
|
|
|
# for i in 0..<BigMessageCount:
|
|
|
|
# expect.add(BigMessagePattern)
|
|
|
|
# var res = await transp.write(expect)
|
|
|
|
# doAssert(res == len(expect))
|
|
|
|
# transp.close()
|
|
|
|
# await transp.join()
|
|
|
|
|
|
|
|
# proc swarmWorker10(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
# var transp = await connect(address)
|
|
|
|
# var expect = ""
|
|
|
|
# for i in 0..<BigMessageCount:
|
|
|
|
# expect.add(BigMessagePattern)
|
|
|
|
# var line = await transp.read()
|
|
|
|
# if equalMem(addr line[0], addr expect[0], len(expect)):
|
|
|
|
# result = 1
|
|
|
|
# else:
|
|
|
|
# result = 0
|
|
|
|
# transp.close()
|
|
|
|
# await transp.join()
|
|
|
|
|
|
|
|
# proc test10(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
# var server = createStreamServer(address, serveClient10, {ReuseAddr})
|
|
|
|
# server.start()
|
|
|
|
# result = await swarmWorker10(address)
|
|
|
|
# server.stop()
|
|
|
|
# server.close()
|
|
|
|
# await server.join()
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient11(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var res = await transp.write(BigMessagePattern)
|
|
|
|
doAssert(res == len(BigMessagePattern))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
proc swarmWorker11(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var buffer: array[len(BigMessagePattern) + 1, byte]
|
|
|
|
var transp = await connect(address)
|
|
|
|
try:
|
|
|
|
await transp.readExactly(addr buffer[0], len(buffer))
|
|
|
|
except TransportIncompleteError:
|
|
|
|
result = 1
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc test11(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient11, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmWorker11(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient12(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var res = await transp.write(BigMessagePattern)
|
|
|
|
doAssert(res == len(BigMessagePattern))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
proc swarmWorker12(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var buffer: array[len(BigMessagePattern), byte]
|
|
|
|
var sep = @[0x0D'u8, 0x0A'u8]
|
|
|
|
var transp = await connect(address)
|
|
|
|
try:
|
|
|
|
var res = await transp.readUntil(addr buffer[0], len(buffer), sep)
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(res == 0)
|
2019-03-30 22:31:10 +00:00
|
|
|
except TransportIncompleteError:
|
|
|
|
result = 1
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc test12(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient12, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmWorker12(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient13(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
proc swarmWorker13(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var transp = await connect(address)
|
|
|
|
var line = await transp.readLine()
|
|
|
|
if line == "":
|
|
|
|
result = 1
|
|
|
|
else:
|
|
|
|
result = 0
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc test13(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient13, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmWorker13(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
# proc serveClient14(server: StreamServer, transp: StreamTransport) {.async.} =
|
|
|
|
# discard
|
|
|
|
|
|
|
|
proc test14(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var subres = 0
|
|
|
|
var server = createStreamServer(address, serveClient13, {ReuseAddr})
|
|
|
|
|
|
|
|
proc swarmWorker(transp: StreamTransport): Future[void] {.async.} =
|
|
|
|
var line = await transp.readLine()
|
|
|
|
if line == "":
|
|
|
|
subres = 1
|
|
|
|
else:
|
|
|
|
subres = 0
|
|
|
|
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
var transp = await connect(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
var fut = swarmWorker(transp)
|
2020-03-05 09:59:10 +00:00
|
|
|
# We perfrom shutdown(SHUT_RD/SD_RECEIVE) for the socket, in such way its
|
|
|
|
# possible to emulate socket's EOF.
|
|
|
|
discard shutdown(SocketHandle(transp.fd), 0)
|
2019-03-30 22:31:10 +00:00
|
|
|
await fut
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
2020-03-05 09:59:10 +00:00
|
|
|
transp.close()
|
2019-04-04 09:34:23 +00:00
|
|
|
await transp.join()
|
2019-03-30 22:31:10 +00:00
|
|
|
result = subres
|
|
|
|
|
|
|
|
proc testConnectionRefused(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
try:
|
|
|
|
var transp = await connect(address)
|
2019-10-29 21:19:41 +00:00
|
|
|
doAssert(isNil(transp))
|
2019-03-30 22:31:10 +00:00
|
|
|
except TransportOsError as e:
|
|
|
|
when defined(windows):
|
2023-04-30 06:20:08 +00:00
|
|
|
return (e.code == ERROR_FILE_NOT_FOUND) or
|
|
|
|
(e.code == ERROR_CONNECTION_REFUSED)
|
2019-03-30 22:31:10 +00:00
|
|
|
else:
|
2023-04-30 06:20:08 +00:00
|
|
|
return (e.code == oserrno.ECONNREFUSED) or (e.code == oserrno.ENOENT)
|
2019-03-30 22:31:10 +00:00
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient16(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
var res = await transp.write(BigMessagePattern)
|
|
|
|
doAssert(res == len(BigMessagePattern))
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-03-30 22:31:10 +00:00
|
|
|
|
|
|
|
proc swarmWorker16(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var buffer = newString(5)
|
|
|
|
var transp = await connect(address)
|
|
|
|
const readLength = 3
|
|
|
|
|
|
|
|
var prevLen = 0
|
|
|
|
while not transp.atEof():
|
|
|
|
if prevLen + readLength > buffer.len:
|
|
|
|
buffer.setLen(prevLen + readLength)
|
|
|
|
|
|
|
|
let bytesRead = await transp.readOnce(addr buffer[prevLen], readLength)
|
|
|
|
inc(prevLen, bytesRead)
|
|
|
|
|
|
|
|
buffer.setLen(prevLen)
|
|
|
|
doAssert(buffer == BigMessagePattern)
|
|
|
|
|
|
|
|
result = 1
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
|
|
|
|
proc test16(address: TransportAddress): Future[int] {.async.} =
|
|
|
|
var server = createStreamServer(address, serveClient16, {ReuseAddr})
|
|
|
|
server.start()
|
2023-08-08 00:10:28 +00:00
|
|
|
result = await swarmWorker16(server.local)
|
2019-03-30 22:31:10 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc testCloseTransport(address: TransportAddress): Future[int] {.async.} =
|
2023-11-15 08:38:48 +00:00
|
|
|
proc client(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
2019-03-30 22:31:10 +00:00
|
|
|
discard
|
|
|
|
var server = createStreamServer(address, client, {ReuseAddr})
|
|
|
|
server.start()
|
|
|
|
server.stop
|
|
|
|
server.close()
|
|
|
|
try:
|
2019-07-04 12:30:07 +00:00
|
|
|
await wait(server.join(), 10.seconds)
|
2019-03-30 22:31:10 +00:00
|
|
|
result = 1
|
2023-06-05 11:03:38 +00:00
|
|
|
except CatchableError:
|
2019-03-30 22:31:10 +00:00
|
|
|
discard
|
|
|
|
|
2019-05-28 06:29:00 +00:00
|
|
|
proc testWriteConnReset(address: TransportAddress): Future[int] {.async.} =
|
2019-07-12 07:40:18 +00:00
|
|
|
var syncFut = newFuture[void]()
|
2023-11-15 08:38:48 +00:00
|
|
|
proc client(server: StreamServer, transp: StreamTransport) {.async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
await transp.closeWait()
|
|
|
|
syncFut.complete()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-05-28 06:29:00 +00:00
|
|
|
var n = 10
|
|
|
|
var server = createStreamServer(address, client, {ReuseAddr})
|
|
|
|
server.start()
|
|
|
|
var msg = "HELLO"
|
2023-08-08 00:10:28 +00:00
|
|
|
var ntransp = await connect(server.local)
|
2019-07-12 07:40:18 +00:00
|
|
|
await syncFut
|
2019-05-28 06:29:00 +00:00
|
|
|
while true:
|
|
|
|
var res = await ntransp.write(msg)
|
|
|
|
if res == 0:
|
|
|
|
result = 1
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
dec(n)
|
|
|
|
if n == 0:
|
|
|
|
break
|
|
|
|
|
|
|
|
server.stop()
|
|
|
|
await ntransp.closeWait()
|
|
|
|
await server.closeWait()
|
|
|
|
|
2019-10-09 12:12:19 +00:00
|
|
|
proc testAnyAddress(): Future[bool] {.async.} =
|
|
|
|
var serverRemote, serverLocal: TransportAddress
|
|
|
|
var connRemote, connLocal: TransportAddress
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
serverRemote = transp.remoteAddress()
|
|
|
|
serverLocal = transp.localAddress()
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2019-10-09 12:12:19 +00:00
|
|
|
|
|
|
|
var ta = initTAddress("0.0.0.0:0")
|
|
|
|
var server = createStreamServer(ta, serveClient, {ReuseAddr})
|
|
|
|
var la = server.localAddress()
|
|
|
|
server.start()
|
|
|
|
var connFut = connect(la)
|
|
|
|
if await withTimeout(connFut, 5.seconds):
|
|
|
|
var conn = connFut.read()
|
|
|
|
connRemote = conn.remoteAddress()
|
|
|
|
connLocal = conn.localAddress()
|
|
|
|
await server.join()
|
|
|
|
await conn.closeWait()
|
|
|
|
result = (connRemote == serverLocal) and (connLocal == serverRemote)
|
|
|
|
else:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
|
2020-02-12 20:54:05 +00:00
|
|
|
proc testWriteReturn(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
var bigMessageSize = 10 * 1024 * 1024 - 1
|
|
|
|
var finishMessage = "DONE"
|
|
|
|
var cdata = newSeqOfCap[byte](bigMessageSize)
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
cdata = await transp.read(bigMessageSize)
|
|
|
|
var size = await transp.write(finishMessage)
|
|
|
|
doAssert(size == len(finishMessage))
|
|
|
|
await transp.closeWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2020-02-12 20:54:05 +00:00
|
|
|
|
|
|
|
var flag = false
|
|
|
|
var server = createStreamServer(address, serveClient, {ReuseAddr})
|
|
|
|
server.start()
|
|
|
|
|
|
|
|
var transp: StreamTransport
|
|
|
|
|
|
|
|
try:
|
2023-08-08 00:10:28 +00:00
|
|
|
transp = await connect(server.local)
|
2020-02-12 20:54:05 +00:00
|
|
|
flag = true
|
2023-06-05 11:03:38 +00:00
|
|
|
except CatchableError:
|
2020-02-12 20:54:05 +00:00
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
if flag:
|
|
|
|
flag = false
|
|
|
|
try:
|
|
|
|
var msg = createBigMessage(bigMessageSize)
|
|
|
|
var size = await transp.write(msg)
|
|
|
|
var data = await transp.read()
|
|
|
|
doAssert(cdata == msg)
|
|
|
|
doAssert(len(data) == len(finishMessage))
|
|
|
|
doAssert(equalMem(addr data[0], addr finishMessage[0], len(data)))
|
|
|
|
|
|
|
|
flag = (size == bigMessageSize)
|
|
|
|
finally:
|
|
|
|
await transp.closeWait()
|
|
|
|
await server.join()
|
|
|
|
result = flag
|
|
|
|
|
2020-03-05 09:59:10 +00:00
|
|
|
proc testReadLine(address: TransportAddress): Future[bool] {.async.} =
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
discard await transp.write("DATA\r\r\r\r\r\n")
|
|
|
|
transp.close()
|
|
|
|
await transp.join()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
|
2020-03-05 09:59:10 +00:00
|
|
|
|
|
|
|
var server = createStreamServer(address, serveClient, {ReuseAddr})
|
|
|
|
server.start()
|
|
|
|
try:
|
|
|
|
var r1, r2, r3, r4, r5: string
|
2023-08-08 00:10:28 +00:00
|
|
|
var t1 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
r1 = await t1.readLine(4)
|
|
|
|
finally:
|
|
|
|
await t1.closeWait()
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t2 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
r2 = await t2.readLine(6)
|
|
|
|
finally:
|
|
|
|
await t2.closeWait()
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t3 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
r3 = await t3.readLine(8)
|
|
|
|
finally:
|
|
|
|
await t3.closeWait()
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t4 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
r4 = await t4.readLine(8)
|
|
|
|
finally:
|
|
|
|
await t4.closeWait()
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t5 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
r5 = await t5.readLine()
|
|
|
|
finally:
|
|
|
|
await t5.closeWait()
|
|
|
|
|
|
|
|
doAssert(r1 == "DATA")
|
|
|
|
doAssert(r2 == "DATA\r\r")
|
|
|
|
doAssert(r3 == "DATA\r\r\r\r")
|
|
|
|
doAssert(r4 == "DATA\r\r\r\r")
|
|
|
|
doAssert(r5 == "DATA\r\r\r\r")
|
|
|
|
|
|
|
|
result = true
|
|
|
|
finally:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
proc readLV(transp: StreamTransport,
|
|
|
|
maxLen: int): Future[seq[byte]] {.async.} =
|
|
|
|
# Read length-prefixed value where length is a 32-bit integer in native
|
|
|
|
# endian (don't do this at home)
|
|
|
|
var
|
|
|
|
valueLen = 0'u32
|
|
|
|
res: seq[byte]
|
exception tracking (#166)
* exception tracking
This PR adds minimal exception tracking to chronos, moving the goalpost
one step further.
In particular, it becomes invalid to raise exceptions from `callSoon`
callbacks: this is critical for writing correct error handling because
there's no reasonable way that a user of chronos can possibly _reason_
about exceptions coming out of there: the event loop will be in an
indeterminite state when the loop is executing an _random_ callback.
As expected, there are several issues in the error handling of chronos:
in particular, it will end up in an inconsistent internal state whenever
the selector loop operations fail, because the internal state update
functions are not written in an exception-safe way. This PR turns this
into a Defect, which probably is not the optimal way of handling things
- expect more work to be done here.
Some API have no way of reporting back errors to callers - for example,
when something fails in the accept loop, there's not much it can do, and
no way to report it back to the user of the API - this has been fixed
with the new accept flow - the old one should be deprecated.
Finally, there is information loss in the API: in composite operations
like `poll` and `waitFor` there's no way to differentiate internal
errors from user-level errors originating from callbacks.
* store `CatchableError` in future
* annotate proc's with correct raises information
* `selectors2` to avoid non-CatchableError IOSelectorsException
* `$` should never raise
* remove unnecessary gcsafe annotations
* fix exceptions leaking out of timer waits
* fix some imports
* functions must signal raising the union of all exceptions across all
platforms to enable cross-platform code
* switch to unittest2
* add `selectors2` which supercedes the std library version and fixes
several exception handling issues in there
* fixes
* docs, platform-independent eh specifiers for some functions
* add feature flag for strict exception mode
also bump version to 3.0.0 - _most_ existing code should be compatible
with this version of exception handling but some things might need
fixing - callbacks, existing raises specifications etc.
* fix AsyncCheck for non-void T
2021-03-24 09:08:33 +00:00
|
|
|
error: ref CatchableError
|
2020-03-05 09:59:10 +00:00
|
|
|
|
2021-12-10 09:55:25 +00:00
|
|
|
proc predicate(data: openArray[byte]): tuple[consumed: int, done: bool] =
|
2020-03-05 09:59:10 +00:00
|
|
|
if len(data) == 0:
|
|
|
|
# There will be no more data, length-value incomplete
|
|
|
|
error = newException(TransportIncompleteError, "LV incomplete")
|
|
|
|
return (0, true)
|
|
|
|
|
|
|
|
var consumed = 0
|
|
|
|
|
|
|
|
if valueLen == 0:
|
|
|
|
if len(data) < 4:
|
|
|
|
return (0, false)
|
|
|
|
copyMem(addr valueLen, unsafeAddr data[0], sizeof(valueLen))
|
|
|
|
if valueLen == 0:
|
|
|
|
return (sizeof(valueLen), true)
|
|
|
|
if int(valueLen) > maxLen:
|
|
|
|
error = newException(ValueError, "Size is too big")
|
|
|
|
return (sizeof(valueLen), true)
|
|
|
|
consumed += sizeof(valueLen)
|
|
|
|
|
|
|
|
let
|
|
|
|
dataLeft = len(data) - consumed
|
|
|
|
count = min(dataLeft, int(valueLen) - len(res))
|
|
|
|
|
|
|
|
res.add(data.toOpenArray(consumed, count + consumed - 1))
|
|
|
|
return (consumed + count, len(res) == int(valueLen))
|
|
|
|
|
|
|
|
await transp.readMessage(predicate)
|
|
|
|
if not isNil(error):
|
|
|
|
raise error
|
|
|
|
else:
|
|
|
|
return res
|
|
|
|
|
|
|
|
proc createMessage(size: uint32): seq[byte] =
|
|
|
|
var message = "MESSAGE"
|
|
|
|
result = newSeq[byte](int(size))
|
|
|
|
for i in 0 ..< size:
|
|
|
|
result[int(i)] = byte(message[int(i) mod len(message)])
|
|
|
|
|
|
|
|
proc createLVMessage(size: uint32): seq[byte] =
|
|
|
|
var message = "MESSAGE"
|
|
|
|
result = newSeq[byte](sizeof(size) + int(size))
|
|
|
|
copyMem(addr result[0], unsafeAddr size, sizeof(size))
|
|
|
|
for i in 0 ..< size:
|
|
|
|
result[int(i) + sizeof(size)] = byte(message[int(i) mod len(message)])
|
|
|
|
|
|
|
|
proc testReadMessage(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
var state = 0
|
|
|
|
var c1, c2, c3, c4, c5, c6, c7: bool
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc serveClient(server: StreamServer, transp: StreamTransport) {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
if state == 0:
|
|
|
|
# EOF from the beginning.
|
|
|
|
state = 1
|
|
|
|
await transp.closeWait()
|
|
|
|
elif state == 1:
|
|
|
|
# Message has only zero-size header.
|
|
|
|
var message = createLVMessage(0'u32)
|
|
|
|
discard await transp.write(message)
|
|
|
|
state = 2
|
|
|
|
await transp.closeWait()
|
|
|
|
elif state == 2:
|
|
|
|
# Message has header, but do not have any data at all.
|
|
|
|
var message = createLVMessage(4'u32)
|
|
|
|
message.setLen(4)
|
|
|
|
discard await transp.write(message)
|
|
|
|
state = 3
|
|
|
|
await transp.closeWait()
|
|
|
|
elif state == 3:
|
|
|
|
# Message do not have enough data for specified size in header.
|
|
|
|
var message = createLVMessage(1024'u32)
|
|
|
|
message.setLen(1024)
|
|
|
|
discard await transp.write(message)
|
|
|
|
state = 4
|
|
|
|
await transp.closeWait()
|
|
|
|
elif state == 4:
|
|
|
|
# Good encoded message with oversize.
|
|
|
|
var message = createLVMessage(1024'u32)
|
|
|
|
discard await transp.write(message)
|
|
|
|
state = 5
|
|
|
|
await transp.closeWait()
|
|
|
|
elif state == 5:
|
|
|
|
# Good encoded message.
|
|
|
|
var message = createLVMessage(1024'u32)
|
|
|
|
discard await transp.write(message)
|
|
|
|
state = 6
|
|
|
|
await transp.closeWait()
|
|
|
|
elif state == 6:
|
|
|
|
# Good encoded message with additional data.
|
|
|
|
var message = createLVMessage(1024'u32)
|
|
|
|
discard await transp.write(message)
|
|
|
|
discard await transp.write("DONE")
|
|
|
|
state = 7
|
|
|
|
await transp.closeWait()
|
|
|
|
else:
|
|
|
|
doAssert(false)
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2020-03-05 09:59:10 +00:00
|
|
|
|
|
|
|
var server = createStreamServer(address, serveClient, {ReuseAddr})
|
|
|
|
server.start()
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t1 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
discard await t1.readLV(2000)
|
|
|
|
except TransportIncompleteError:
|
|
|
|
c1 = true
|
|
|
|
finally:
|
|
|
|
await t1.closeWait()
|
|
|
|
|
|
|
|
if not c1:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
return false
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t2 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
var r2 = await t2.readLV(2000)
|
|
|
|
c2 = (r2 == @[])
|
|
|
|
finally:
|
|
|
|
await t2.closeWait()
|
|
|
|
|
|
|
|
if not c2:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
return false
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t3 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
discard await t3.readLV(2000)
|
|
|
|
except TransportIncompleteError:
|
|
|
|
c3 = true
|
|
|
|
finally:
|
|
|
|
await t3.closeWait()
|
|
|
|
|
|
|
|
if not c3:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
return false
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t4 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
discard await t4.readLV(2000)
|
|
|
|
except TransportIncompleteError:
|
|
|
|
c4 = true
|
|
|
|
finally:
|
|
|
|
await t4.closeWait()
|
|
|
|
|
|
|
|
if not c4:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
return false
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t5 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
discard await t5.readLV(1000)
|
|
|
|
except ValueError:
|
|
|
|
c5 = true
|
|
|
|
finally:
|
|
|
|
await t5.closeWait()
|
|
|
|
|
|
|
|
if not c5:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
return false
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t6 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
var expectMsg = createMessage(1024)
|
|
|
|
var r6 = await t6.readLV(2000)
|
|
|
|
if len(r6) == 1024 and r6 == expectMsg:
|
|
|
|
c6 = true
|
|
|
|
finally:
|
|
|
|
await t6.closeWait()
|
|
|
|
|
|
|
|
if not c6:
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
return false
|
|
|
|
|
2023-08-08 00:10:28 +00:00
|
|
|
var t7 = await connect(server.local)
|
2020-03-05 09:59:10 +00:00
|
|
|
try:
|
|
|
|
var expectMsg = createMessage(1024)
|
|
|
|
var expectDone = "DONE"
|
|
|
|
var r7 = await t7.readLV(2000)
|
|
|
|
if len(r7) == 1024 and r7 == expectMsg:
|
|
|
|
var m = await t7.read(4)
|
|
|
|
if len(m) == 4 and equalMem(addr m[0], addr expectDone[0], 4):
|
|
|
|
c7 = true
|
|
|
|
finally:
|
|
|
|
await t7.closeWait()
|
|
|
|
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
result = c7
|
|
|
|
|
2020-06-24 08:21:52 +00:00
|
|
|
proc testAccept(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
var server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
var connected = 0
|
|
|
|
var accepted = 0
|
|
|
|
|
|
|
|
proc acceptTask(server: StreamServer) {.async.} =
|
|
|
|
for i in 0 ..< TestsCount:
|
|
|
|
let transp = await server.accept()
|
|
|
|
await transp.closeWait()
|
|
|
|
inc(accepted)
|
|
|
|
|
|
|
|
var acceptFut = acceptTask(server)
|
|
|
|
var transp: StreamTransport
|
|
|
|
|
|
|
|
try:
|
|
|
|
for i in 0 ..< TestsCount:
|
2023-08-08 00:10:28 +00:00
|
|
|
transp = await connect(server.local)
|
2020-06-24 08:21:52 +00:00
|
|
|
await sleepAsync(10.milliseconds)
|
|
|
|
await transp.closeWait()
|
|
|
|
inc(connected)
|
|
|
|
if await withTimeout(acceptFut, 5.seconds):
|
|
|
|
if acceptFut.finished() and not(acceptFut.failed()):
|
|
|
|
result = (connected == TestsCount) and (connected == accepted)
|
|
|
|
finally:
|
|
|
|
await server.closeWait()
|
|
|
|
if not(isNil(transp)):
|
|
|
|
await transp.closeWait()
|
|
|
|
|
|
|
|
proc testAcceptClose(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
var server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
|
|
|
|
proc acceptTask(server: StreamServer) {.async.} =
|
|
|
|
let transp = await server.accept()
|
|
|
|
await transp.closeWait()
|
|
|
|
|
|
|
|
var acceptFut = acceptTask(server)
|
|
|
|
await server.closeWait()
|
|
|
|
|
|
|
|
if await withTimeout(acceptFut, 5.seconds):
|
|
|
|
if acceptFut.finished() and acceptFut.failed():
|
|
|
|
if acceptFut.readError() of TransportUseClosedError:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
|
|
|
|
when not(defined(windows)):
|
|
|
|
proc testAcceptTooMany(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
let maxFiles = getMaxOpenFiles()
|
|
|
|
var server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
let isock = int(server.sock)
|
|
|
|
let newMaxFiles = isock + 4
|
|
|
|
setMaxOpenFiles(newMaxFiles)
|
|
|
|
|
|
|
|
proc acceptTask(server: StreamServer): Future[bool] {.async.} =
|
|
|
|
var transports = newSeq[StreamTransport]()
|
|
|
|
try:
|
|
|
|
for i in 0 ..< 3:
|
|
|
|
let transp = await server.accept()
|
|
|
|
transports.add(transp)
|
|
|
|
except TransportTooManyError:
|
|
|
|
var pending = newSeq[Future[void]]()
|
|
|
|
for item in transports:
|
|
|
|
pending.add(closeWait(item))
|
|
|
|
await allFutures(pending)
|
|
|
|
return true
|
|
|
|
|
|
|
|
var acceptFut = acceptTask(server)
|
|
|
|
|
|
|
|
try:
|
|
|
|
for i in 0 ..< 3:
|
|
|
|
try:
|
2023-08-08 00:10:28 +00:00
|
|
|
let transp = await connect(server.local)
|
2020-06-24 08:21:52 +00:00
|
|
|
await sleepAsync(10.milliseconds)
|
|
|
|
await transp.closeWait()
|
|
|
|
except TransportTooManyError:
|
|
|
|
break
|
|
|
|
if await withTimeout(acceptFut, 5.seconds):
|
|
|
|
if acceptFut.finished() and not(acceptFut.failed()):
|
|
|
|
if acceptFut.read() == true:
|
|
|
|
result = true
|
|
|
|
finally:
|
|
|
|
await server.closeWait()
|
|
|
|
setMaxOpenFiles(maxFiles)
|
|
|
|
|
2020-11-18 09:30:33 +00:00
|
|
|
proc testWriteOnClose(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
var server = createStreamServer(address, flags = {ReuseAddr, NoPipeFlash})
|
|
|
|
var res = 0
|
|
|
|
|
|
|
|
proc acceptTask(server: StreamServer) {.async.} =
|
|
|
|
let transp = await server.accept()
|
2021-12-08 10:35:27 +00:00
|
|
|
var futs = newSeq[Future[int]]()
|
2020-11-18 09:30:33 +00:00
|
|
|
var msg = createBigMessage(1024)
|
2021-12-08 10:35:27 +00:00
|
|
|
var tries = 0
|
|
|
|
|
|
|
|
while futs.len() < TestsCount:
|
|
|
|
let fut = transp.write(msg)
|
|
|
|
# `write` has a fast path that puts the data in the OS socket buffer -
|
|
|
|
# we'll keep writing until we get EAGAIN from the OS so that we have
|
|
|
|
# data in the in-chronos queue to fail on close
|
|
|
|
if not fut.completed():
|
|
|
|
futs.add(fut)
|
|
|
|
else:
|
|
|
|
tries += 1
|
|
|
|
if tries > 65*1024:
|
|
|
|
# We've queued 64mb on the socket and it still allows writing,
|
|
|
|
# something is wrong - we'll break here which will cause the test
|
|
|
|
# to fail
|
|
|
|
break
|
2020-11-18 09:30:33 +00:00
|
|
|
|
|
|
|
await transp.closeWait()
|
|
|
|
await sleepAsync(100.milliseconds)
|
|
|
|
|
|
|
|
for i in 0 ..< len(futs):
|
2021-12-08 10:35:27 +00:00
|
|
|
# writes may complete via fast write
|
2020-11-18 09:30:33 +00:00
|
|
|
if futs[i].failed() and (futs[i].error of TransportUseClosedError):
|
|
|
|
inc(res)
|
|
|
|
|
|
|
|
await server.closeWait()
|
|
|
|
|
|
|
|
var acceptFut = acceptTask(server)
|
2023-08-08 00:10:28 +00:00
|
|
|
var transp = await connect(server.local)
|
2020-11-18 09:30:33 +00:00
|
|
|
await server.join()
|
|
|
|
await transp.closeWait()
|
|
|
|
await acceptFut
|
|
|
|
return (res == TestsCount)
|
|
|
|
|
|
|
|
proc testReadOnClose(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
var server = createStreamServer(address, flags = {ReuseAddr, NoPipeFlash})
|
|
|
|
var res = false
|
|
|
|
|
|
|
|
proc acceptTask(server: StreamServer) {.async.} =
|
|
|
|
let transp = await server.accept()
|
|
|
|
var buffer = newSeq[byte](1024)
|
|
|
|
var fut = transp.readOnce(addr buffer[0], len(buffer))
|
|
|
|
await transp.closeWait()
|
|
|
|
await sleepAsync(100.milliseconds)
|
|
|
|
if fut.failed() and (fut.error of TransportUseClosedError):
|
|
|
|
res = true
|
|
|
|
await server.closeWait()
|
|
|
|
|
|
|
|
var acceptFut = acceptTask(server)
|
2023-08-08 00:10:28 +00:00
|
|
|
var transp = await connect(server.local)
|
2020-11-18 09:30:33 +00:00
|
|
|
await server.join()
|
|
|
|
await transp.closeWait()
|
|
|
|
await acceptFut
|
|
|
|
return res
|
|
|
|
|
2021-09-04 21:53:27 +00:00
|
|
|
proc testAcceptRace(address: TransportAddress): Future[bool] {.async.} =
|
|
|
|
proc test1(address: TransportAddress) {.async.} =
|
|
|
|
let server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
let acceptFut = server.accept()
|
|
|
|
server.close()
|
|
|
|
await allFutures(acceptFut.cancelAndWait(), server.join())
|
|
|
|
|
|
|
|
proc test2(address: TransportAddress) {.async.} =
|
|
|
|
let server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
let acceptFut = server.accept()
|
|
|
|
await acceptFut.cancelAndWait()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
proc test3(address: TransportAddress) {.async.} =
|
|
|
|
let server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
let acceptFut = server.accept()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await allFutures(acceptFut.cancelAndWait(), server.join())
|
|
|
|
|
|
|
|
proc test4(address: TransportAddress) {.async.} =
|
|
|
|
let server = createStreamServer(address, flags = {ReuseAddr})
|
|
|
|
let acceptFut = server.accept()
|
|
|
|
await acceptFut.cancelAndWait()
|
|
|
|
server.stop()
|
|
|
|
server.close()
|
|
|
|
await server.join()
|
|
|
|
|
|
|
|
try:
|
|
|
|
await test1(address).wait(5.seconds)
|
|
|
|
await test2(address).wait(5.seconds)
|
|
|
|
await test3(address).wait(5.seconds)
|
|
|
|
await test4(address).wait(5.seconds)
|
|
|
|
return true
|
|
|
|
except AsyncTimeoutError:
|
|
|
|
return false
|
|
|
|
|
2022-01-20 16:38:41 +00:00
|
|
|
proc testPipe(): Future[bool] {.async.} =
|
|
|
|
let (rfd, wfd) = createAsyncPipe()
|
|
|
|
|
|
|
|
let
|
|
|
|
message = createBigMessage(16384 * 1024)
|
|
|
|
rtransp = fromPipe(rfd)
|
|
|
|
wtransp = fromPipe(wfd)
|
|
|
|
var
|
|
|
|
buffer = newSeq[byte](16384 * 1024)
|
|
|
|
|
|
|
|
proc writer(transp: StreamTransport): Future[int] {.async.} =
|
|
|
|
let res =
|
|
|
|
try:
|
|
|
|
await transp.write(message)
|
|
|
|
except CatchableError:
|
|
|
|
-1
|
|
|
|
return res
|
|
|
|
|
2023-02-21 10:48:36 +00:00
|
|
|
var fut {.used.} = wtransp.writer()
|
2022-01-20 16:38:41 +00:00
|
|
|
try:
|
|
|
|
await rtransp.readExactly(addr buffer[0], 16384 * 1024)
|
|
|
|
except CatchableError:
|
|
|
|
discard
|
|
|
|
|
|
|
|
await allFutures(rtransp.closeWait(), wtransp.closeWait())
|
|
|
|
return buffer == message
|
|
|
|
|
2023-04-03 12:34:35 +00:00
|
|
|
proc testConnectBindLocalAddress() {.async.} =
|
|
|
|
|
2023-11-15 08:38:48 +00:00
|
|
|
proc client(server: StreamServer, transp: StreamTransport) {.async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
await transp.closeWait()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2023-04-03 12:34:35 +00:00
|
|
|
|
2023-08-02 19:04:30 +00:00
|
|
|
let server1 = createStreamServer(initTAddress("127.0.0.1:0"), client)
|
|
|
|
let server2 = createStreamServer(initTAddress("127.0.0.1:0"), client)
|
|
|
|
let server3 = createStreamServer(initTAddress("127.0.0.1:0"), client, {ReusePort})
|
2023-04-03 12:34:35 +00:00
|
|
|
|
2023-08-02 19:04:30 +00:00
|
|
|
server1.start()
|
|
|
|
server2.start()
|
|
|
|
server3.start()
|
2023-04-03 12:34:35 +00:00
|
|
|
|
2023-09-15 16:38:39 +00:00
|
|
|
# It works cause even though there's an active listening socket bound to
|
|
|
|
# dst3, we are using ReusePort
|
|
|
|
var transp1 = await connect(
|
|
|
|
server1.localAddress(), localAddress = server3.localAddress(),
|
|
|
|
flags = {SocketFlags.ReusePort})
|
|
|
|
var transp2 = await connect(
|
|
|
|
server2.localAddress(), localAddress = server3.localAddress(),
|
|
|
|
flags = {SocketFlags.ReusePort})
|
2023-04-03 12:34:35 +00:00
|
|
|
|
|
|
|
expect(TransportOsError):
|
2023-09-15 16:38:39 +00:00
|
|
|
var transp2 {.used.} = await connect(
|
|
|
|
server2.localAddress(), localAddress = server3.localAddress())
|
2023-04-03 12:34:35 +00:00
|
|
|
|
|
|
|
expect(TransportOsError):
|
2023-09-15 16:38:39 +00:00
|
|
|
var transp3 {.used.} = await connect(
|
|
|
|
server2.localAddress(),
|
|
|
|
localAddress = initTAddress("::", server3.localAddress().port))
|
2023-04-03 12:34:35 +00:00
|
|
|
|
|
|
|
await transp1.closeWait()
|
|
|
|
await transp2.closeWait()
|
|
|
|
|
2023-08-02 19:04:30 +00:00
|
|
|
server1.stop()
|
|
|
|
await server1.closeWait()
|
|
|
|
|
|
|
|
server2.stop()
|
|
|
|
await server2.closeWait()
|
|
|
|
|
|
|
|
server3.stop()
|
|
|
|
await server3.closeWait()
|
2023-04-03 12:34:35 +00:00
|
|
|
|
2023-09-15 16:38:39 +00:00
|
|
|
proc testConnectCancelLeaksTest() {.async.} =
|
2023-11-15 08:38:48 +00:00
|
|
|
proc client(server: StreamServer, transp: StreamTransport) {.async: (raises: []).} =
|
|
|
|
try:
|
|
|
|
await transp.closeWait()
|
|
|
|
except CatchableError as exc:
|
|
|
|
raiseAssert exc.msg
|
2023-09-15 16:38:39 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
server = createStreamServer(initTAddress("127.0.0.1:0"), client)
|
|
|
|
address = server.localAddress()
|
|
|
|
|
|
|
|
var counter = 0
|
|
|
|
while true:
|
|
|
|
let transpFut = connect(address)
|
|
|
|
if counter > 0:
|
|
|
|
await stepsAsync(counter)
|
|
|
|
if not(transpFut.finished()):
|
|
|
|
await cancelAndWait(transpFut)
|
|
|
|
doAssert(cancelled(transpFut),
|
|
|
|
"Future should be Cancelled at this point")
|
|
|
|
inc(counter)
|
|
|
|
else:
|
|
|
|
let transp = await transpFut
|
|
|
|
await transp.closeWait()
|
|
|
|
break
|
|
|
|
server.stop()
|
|
|
|
await server.closeWait()
|
|
|
|
|
|
|
|
proc testAcceptCancelLeaksTest() {.async.} =
|
|
|
|
var
|
|
|
|
counter = 0
|
|
|
|
exitLoop = false
|
|
|
|
|
|
|
|
# This timer will help to awake events poll in case its going to stuck
|
|
|
|
# usually happens on MacOS.
|
|
|
|
let sleepFut = sleepAsync(1.seconds)
|
|
|
|
|
|
|
|
while not(exitLoop):
|
|
|
|
let
|
|
|
|
server = createStreamServer(initTAddress("127.0.0.1:0"))
|
|
|
|
address = server.localAddress()
|
|
|
|
|
|
|
|
let
|
|
|
|
transpFut = connect(address)
|
|
|
|
acceptFut = server.accept()
|
|
|
|
|
|
|
|
if counter > 0:
|
|
|
|
await stepsAsync(counter)
|
|
|
|
|
|
|
|
exitLoop =
|
|
|
|
if not(acceptFut.finished()):
|
|
|
|
await cancelAndWait(acceptFut)
|
|
|
|
doAssert(cancelled(acceptFut),
|
|
|
|
"Future should be Cancelled at this point")
|
|
|
|
inc(counter)
|
|
|
|
false
|
|
|
|
else:
|
|
|
|
let transp = await acceptFut
|
|
|
|
await transp.closeWait()
|
|
|
|
true
|
|
|
|
|
|
|
|
if not(transpFut.finished()):
|
|
|
|
await transpFut.cancelAndWait()
|
|
|
|
|
|
|
|
if transpFut.completed():
|
|
|
|
let transp = transpFut.value
|
|
|
|
await transp.closeWait()
|
|
|
|
|
|
|
|
server.stop()
|
|
|
|
await server.closeWait()
|
|
|
|
|
|
|
|
if not(sleepFut.finished()):
|
|
|
|
await cancelAndWait(sleepFut)
|
|
|
|
|
2023-10-30 13:27:50 +00:00
|
|
|
proc performDualstackTest(
|
|
|
|
sstack: DualStackType, saddr: TransportAddress,
|
|
|
|
cstack: DualStackType, caddr: TransportAddress
|
|
|
|
): Future[bool] {.async.} =
|
|
|
|
let server = createStreamServer(saddr, dualstack = sstack)
|
|
|
|
var address = caddr
|
|
|
|
address.port = server.localAddress().port
|
|
|
|
var acceptFut = server.accept()
|
|
|
|
let
|
|
|
|
clientTransp =
|
|
|
|
try:
|
|
|
|
let res = await connect(address,
|
|
|
|
dualstack = cstack).wait(500.milliseconds)
|
|
|
|
Opt.some(res)
|
|
|
|
except CatchableError:
|
|
|
|
Opt.none(StreamTransport)
|
|
|
|
serverTransp =
|
|
|
|
if clientTransp.isSome():
|
|
|
|
let res = await acceptFut
|
|
|
|
Opt.some(res)
|
|
|
|
else:
|
|
|
|
Opt.none(StreamTransport)
|
|
|
|
|
|
|
|
let testResult = clientTransp.isSome() and serverTransp.isSome()
|
|
|
|
var pending: seq[FutureBase]
|
|
|
|
if clientTransp.isSome():
|
|
|
|
pending.add(closeWait(clientTransp.get()))
|
|
|
|
if serverTransp.isSome():
|
|
|
|
pending.add(closeWait(serverTransp.get()))
|
|
|
|
else:
|
|
|
|
pending.add(cancelAndWait(acceptFut))
|
|
|
|
await allFutures(pending)
|
|
|
|
server.stop()
|
|
|
|
await server.closeWait()
|
|
|
|
testResult
|
|
|
|
|
2024-04-13 00:04:42 +00:00
|
|
|
proc performAutoAddressTest(port: Port,
|
|
|
|
family: AddressFamily): Future[bool] {.
|
|
|
|
async: (raises: []).} =
|
|
|
|
let server =
|
|
|
|
block:
|
|
|
|
var currentPort = port
|
|
|
|
var res: StreamServer
|
|
|
|
for i in 0 ..< 10:
|
|
|
|
res =
|
|
|
|
try:
|
|
|
|
createStreamServer(port, flags = {ServerFlags.ReuseAddr})
|
|
|
|
except TransportOsError as exc:
|
|
|
|
echo "Unable to create server on port ", currentPort,
|
|
|
|
" with error: ", exc.msg
|
|
|
|
currentPort = Port(uint16(currentPort) + 1'u16)
|
|
|
|
nil
|
|
|
|
if not(isNil(res)):
|
|
|
|
break
|
|
|
|
doAssert(not(isNil(res)), "Unable to create server, giving up")
|
|
|
|
res
|
|
|
|
|
|
|
|
var
|
|
|
|
address =
|
|
|
|
case family
|
|
|
|
of AddressFamily.IPv4:
|
|
|
|
try:
|
|
|
|
initTAddress("127.0.0.1:0")
|
|
|
|
except TransportAddressError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
of AddressFamily.IPv6:
|
|
|
|
try:
|
|
|
|
initTAddress("::1:0")
|
|
|
|
except TransportAddressError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
of AddressFamily.Unix, AddressFamily.None:
|
|
|
|
raiseAssert "Not allowed"
|
|
|
|
|
|
|
|
address.port = server.localAddress().port
|
|
|
|
var acceptFut = server.accept()
|
|
|
|
let
|
|
|
|
clientTransp =
|
|
|
|
try:
|
|
|
|
let res = await connect(address).wait(2.seconds)
|
|
|
|
Opt.some(res)
|
|
|
|
except CatchableError:
|
|
|
|
Opt.none(StreamTransport)
|
|
|
|
serverTransp =
|
|
|
|
if clientTransp.isSome():
|
|
|
|
let res =
|
|
|
|
try:
|
|
|
|
await noCancel acceptFut
|
|
|
|
except TransportError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
Opt.some(res)
|
|
|
|
else:
|
|
|
|
Opt.none(StreamTransport)
|
|
|
|
|
|
|
|
let testResult = clientTransp.isSome() and serverTransp.isSome()
|
|
|
|
var pending: seq[FutureBase]
|
|
|
|
if clientTransp.isSome():
|
|
|
|
pending.add(closeWait(clientTransp.get()))
|
|
|
|
if serverTransp.isSome():
|
|
|
|
pending.add(closeWait(serverTransp.get()))
|
|
|
|
else:
|
|
|
|
pending.add(cancelAndWait(acceptFut))
|
|
|
|
await noCancel allFutures(pending)
|
|
|
|
try:
|
|
|
|
server.stop()
|
|
|
|
except TransportError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
await server.closeWait()
|
|
|
|
testResult
|
|
|
|
|
|
|
|
proc performAutoAddressTest2(
|
|
|
|
address1: Opt[IpAddress],
|
|
|
|
address2: Opt[IpAddress],
|
|
|
|
port: Port,
|
|
|
|
sendType: AddressFamily
|
|
|
|
): Future[bool] {.async: (raises: []).} =
|
|
|
|
let
|
|
|
|
server =
|
|
|
|
block:
|
|
|
|
var
|
|
|
|
currentPort = port
|
|
|
|
res: StreamServer
|
|
|
|
for i in 0 ..< 10:
|
|
|
|
res =
|
|
|
|
try:
|
|
|
|
createStreamServer(port, host = address1,
|
|
|
|
flags = {ServerFlags.ReuseAddr})
|
|
|
|
except TransportOsError as exc:
|
|
|
|
echo "Unable to create server on port ", currentPort,
|
|
|
|
" with error: ", exc.msg
|
|
|
|
currentPort = Port(uint16(currentPort) + 1'u16)
|
|
|
|
nil
|
|
|
|
if not(isNil(res)):
|
|
|
|
break
|
|
|
|
doAssert(not(isNil(res)), "Unable to create server, giving up")
|
|
|
|
res
|
|
|
|
serverAddr = server.localAddress()
|
|
|
|
serverPort = serverAddr.port
|
|
|
|
remoteAddress =
|
|
|
|
try:
|
|
|
|
case sendType
|
|
|
|
of AddressFamily.IPv4:
|
|
|
|
var res = initTAddress("127.0.0.1:0")
|
|
|
|
res.port = serverPort
|
|
|
|
res
|
|
|
|
of AddressFamily.IPv6:
|
|
|
|
var res = initTAddress("[::1]:0")
|
|
|
|
res.port = serverPort
|
|
|
|
res
|
|
|
|
else:
|
|
|
|
raiseAssert "Incorrect sending type"
|
|
|
|
except TransportAddressError as exc:
|
|
|
|
raiseAssert "Unable to initialize transport address, " &
|
|
|
|
"reason = " & exc.msg
|
|
|
|
acceptFut = server.accept()
|
|
|
|
|
|
|
|
let
|
|
|
|
clientTransp =
|
|
|
|
try:
|
|
|
|
if address2.isSome():
|
|
|
|
let
|
|
|
|
laddr = initTAddress(address2.get(), Port(0))
|
|
|
|
res = await connect(remoteAddress, localAddress = laddr).
|
|
|
|
wait(2.seconds)
|
|
|
|
Opt.some(res)
|
|
|
|
|
|
|
|
else:
|
|
|
|
let res = await connect(remoteAddress).wait(2.seconds)
|
|
|
|
Opt.some(res)
|
|
|
|
except CatchableError:
|
|
|
|
Opt.none(StreamTransport)
|
|
|
|
serverTransp =
|
|
|
|
if clientTransp.isSome():
|
|
|
|
let res =
|
|
|
|
try:
|
|
|
|
await noCancel acceptFut
|
|
|
|
except TransportError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
Opt.some(res)
|
|
|
|
else:
|
|
|
|
Opt.none(StreamTransport)
|
|
|
|
testResult =
|
|
|
|
clientTransp.isSome() and serverTransp.isSome() and
|
|
|
|
(serverTransp.get().remoteAddress2().get().family == sendType) and
|
|
|
|
(clientTransp.get().remoteAddress2().get().family == sendType)
|
|
|
|
var pending: seq[FutureBase]
|
|
|
|
if clientTransp.isSome():
|
|
|
|
pending.add(closeWait(clientTransp.get()))
|
|
|
|
if serverTransp.isSome():
|
|
|
|
pending.add(closeWait(serverTransp.get()))
|
|
|
|
else:
|
|
|
|
pending.add(cancelAndWait(acceptFut))
|
|
|
|
await noCancel allFutures(pending)
|
|
|
|
try:
|
|
|
|
server.stop()
|
|
|
|
except TransportError as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
await server.closeWait()
|
|
|
|
|
|
|
|
testResult
|
|
|
|
|
2020-06-24 08:21:52 +00:00
|
|
|
markFD = getCurrentFD()
|
|
|
|
|
2019-03-30 22:31:10 +00:00
|
|
|
for i in 0..<len(addresses):
|
|
|
|
test prefixes[i] & "close(transport) test":
|
|
|
|
check waitFor(testCloseTransport(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readUntil() buffer overflow test":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test8(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readLine() buffer overflow test":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test7(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readExactly() unexpected disconnect test":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test11(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readUntil() unexpected disconnect test":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test12(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readLine() unexpected disconnect empty string test":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test13(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "Closing socket while operation pending test (issue #8)":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test14(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readLine() multiple clients with messages (" &
|
|
|
|
$ClientsCount & " clients x " & $MessagesCount & " messages)":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test1(addresses[i])) == ClientsCount * MessagesCount
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readExactly() multiple clients with messages (" &
|
|
|
|
$ClientsCount & " clients x " & $MessagesCount & " messages)":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test2(addresses[i])) == ClientsCount * MessagesCount
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readUntil() multiple clients with messages (" &
|
|
|
|
$ClientsCount & " clients x " & $MessagesCount & " messages)":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test3(addresses[i])) == ClientsCount * MessagesCount
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "write(string)/read(int) multiple clients (" &
|
|
|
|
$ClientsCount & " clients x " & $MessagesCount & " messages)":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(testWR(addresses[i])) == ClientsCount * MessagesCount
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "write(seq[byte])/consume(int)/read(int) multiple clients (" &
|
|
|
|
$ClientsCount & " clients x " & $MessagesCount & " messages)":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(testWCR(addresses[i])) == ClientsCount * MessagesCount
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "writeFile() multiple clients (" & $FilesCount & " files)":
|
2019-03-30 22:31:10 +00:00
|
|
|
when defined(windows):
|
2024-02-13 22:03:12 +00:00
|
|
|
if addresses[i].family == AddressFamily.IPv4 and (sizeof(int) == 8):
|
2018-10-25 19:59:40 +00:00
|
|
|
check waitFor(testSendFile(addresses[i])) == FilesCount
|
2018-10-25 10:19:19 +00:00
|
|
|
else:
|
2019-10-09 12:12:19 +00:00
|
|
|
skip()
|
2019-03-30 22:31:10 +00:00
|
|
|
else:
|
2024-02-13 22:03:12 +00:00
|
|
|
if defined(emscripten) or (sizeof(int) == 4):
|
2023-08-01 09:56:08 +00:00
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
check waitFor(testSendFile(addresses[i])) == FilesCount
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "Connection refused test":
|
2019-03-30 22:31:10 +00:00
|
|
|
var address: TransportAddress
|
|
|
|
if addresses[i].family == AddressFamily.Unix:
|
|
|
|
address = initTAddress("/tmp/notexistingtestpipe")
|
|
|
|
else:
|
|
|
|
address = initTAddress("127.0.0.1:43335")
|
|
|
|
check waitFor(testConnectionRefused(address)) == true
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "readOnce() read until atEof() test":
|
2019-03-30 22:31:10 +00:00
|
|
|
check waitFor(test16(addresses[i])) == 1
|
2019-05-28 06:29:00 +00:00
|
|
|
test prefixes[i] & "Connection reset test on send() only":
|
2020-11-27 01:50:38 +00:00
|
|
|
when defined(macosx):
|
2020-07-17 06:38:58 +00:00
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
check waitFor(testWriteConnReset(addresses[i])) == 1
|
2021-12-08 10:35:27 +00:00
|
|
|
test prefixes[i] & "0.0.0.0/::0 (INADDR_ANY) test":
|
2019-10-09 12:12:19 +00:00
|
|
|
if addresses[i].family == AddressFamily.IPv4:
|
|
|
|
check waitFor(testAnyAddress()) == true
|
|
|
|
else:
|
|
|
|
skip()
|
2020-02-12 20:54:05 +00:00
|
|
|
test prefixes[i] & "write() return value test (issue #73)":
|
|
|
|
check waitFor(testWriteReturn(addresses[i])) == true
|
2020-03-05 09:59:10 +00:00
|
|
|
test prefixes[i] & "readLine() partial separator test":
|
|
|
|
check waitFor(testReadLine(addresses[i])) == true
|
|
|
|
test prefixes[i] & "readMessage() test":
|
|
|
|
check waitFor(testReadMessage(addresses[i])) == true
|
2020-06-24 08:21:52 +00:00
|
|
|
test prefixes[i] & "accept() test":
|
|
|
|
check waitFor(testAccept(addresses[i])) == true
|
|
|
|
test prefixes[i] & "close() while in accept() waiting test":
|
|
|
|
check waitFor(testAcceptClose(addresses[i])) == true
|
|
|
|
test prefixes[i] & "accept() too many file descriptors test":
|
|
|
|
when defined(windows):
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
check waitFor(testAcceptTooMany(addresses[i])) == true
|
2021-09-04 21:53:27 +00:00
|
|
|
test prefixes[i] & "accept() and close() race test":
|
|
|
|
check waitFor(testAcceptRace(addresses[i])) == true
|
2020-11-18 09:30:33 +00:00
|
|
|
test prefixes[i] & "write() queue notification on close() test":
|
|
|
|
check waitFor(testWriteOnClose(addresses[i])) == true
|
|
|
|
test prefixes[i] & "read() notification on close() test":
|
|
|
|
check waitFor(testReadOnClose(addresses[i])) == true
|
2022-01-20 16:38:41 +00:00
|
|
|
test "[PIPE] readExactly()/write() test":
|
|
|
|
check waitFor(testPipe()) == true
|
2023-09-15 16:38:39 +00:00
|
|
|
test "[IP] bind connect to local address test":
|
2023-04-03 12:34:35 +00:00
|
|
|
waitFor(testConnectBindLocalAddress())
|
2023-09-15 16:38:39 +00:00
|
|
|
test "[IP] connect() cancellation leaks test":
|
|
|
|
waitFor(testConnectCancelLeaksTest())
|
|
|
|
test "[IP] accept() cancellation leaks test":
|
|
|
|
waitFor(testAcceptCancelLeaksTest())
|
2023-10-30 13:27:50 +00:00
|
|
|
asyncTest "[IP] getDomain(socket) [SOCK_STREAM] test":
|
|
|
|
if isAvailable(AddressFamily.IPv4) and isAvailable(AddressFamily.IPv6):
|
|
|
|
block:
|
|
|
|
let res = createAsyncSocket2(Domain.AF_INET, SockType.SOCK_STREAM,
|
|
|
|
Protocol.IPPROTO_TCP)
|
|
|
|
check res.isOk()
|
|
|
|
let fres = getDomain(res.get())
|
|
|
|
check fres.isOk()
|
|
|
|
discard unregisterAndCloseFd(res.get())
|
|
|
|
check fres.get() == AddressFamily.IPv4
|
|
|
|
|
|
|
|
block:
|
|
|
|
let res = createAsyncSocket2(Domain.AF_INET6, SockType.SOCK_STREAM,
|
|
|
|
Protocol.IPPROTO_TCP)
|
|
|
|
check res.isOk()
|
|
|
|
let fres = getDomain(res.get())
|
|
|
|
check fres.isOk()
|
|
|
|
discard unregisterAndCloseFd(res.get())
|
|
|
|
check fres.get() == AddressFamily.IPv6
|
|
|
|
|
|
|
|
when not(defined(windows)):
|
|
|
|
block:
|
|
|
|
let res = createAsyncSocket2(Domain.AF_UNIX, SockType.SOCK_STREAM,
|
|
|
|
Protocol.IPPROTO_IP)
|
|
|
|
check res.isOk()
|
|
|
|
let fres = getDomain(res.get())
|
|
|
|
check fres.isOk()
|
|
|
|
discard unregisterAndCloseFd(res.get())
|
|
|
|
check fres.get() == AddressFamily.Unix
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] DualStack [TCP] server [DualStackType.Auto] test":
|
|
|
|
if isAvailable(AddressFamily.IPv4) and isAvailable(AddressFamily.IPv6):
|
|
|
|
let serverAddress = initTAddress("[::]:0")
|
|
|
|
check:
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Auto, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("127.0.0.1:0"))) == true
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Auto, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("127.0.0.1:0").toIPv6())) == true
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Auto, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("[::1]:0"))) == true
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] DualStack [TCP] server [DualStackType.Enabled] test":
|
|
|
|
if isAvailable(AddressFamily.IPv4) and isAvailable(AddressFamily.IPv6):
|
|
|
|
let serverAddress = initTAddress("[::]:0")
|
|
|
|
check:
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Enabled, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("127.0.0.1:0"))) == true
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Enabled, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("127.0.0.1:0").toIPv6())) == true
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Enabled, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("[::1]:0"))) == true
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] DualStack [TCP] server [DualStackType.Disabled] test":
|
|
|
|
if isAvailable(AddressFamily.IPv4) and isAvailable(AddressFamily.IPv6):
|
|
|
|
let serverAddress = initTAddress("[::]:0")
|
|
|
|
check:
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Disabled, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("127.0.0.1:0"))) == false
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Disabled, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("127.0.0.1:0").toIPv6())) == false
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Disabled, serverAddress,
|
|
|
|
DualStackType.Auto, initTAddress("[::1]:0"))) == true
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] DualStack [TCP] connect [IPv4 mapped address] test":
|
|
|
|
if isAvailable(AddressFamily.IPv4) and isAvailable(AddressFamily.IPv6):
|
|
|
|
let serverAddress = initTAddress("[::]:0")
|
|
|
|
check:
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Auto, serverAddress,
|
|
|
|
DualStackType.Disabled, initTAddress("127.0.0.1:0"))) == true
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Auto, serverAddress,
|
|
|
|
DualStackType.Disabled, initTAddress("127.0.0.1:0").toIPv6())) == false
|
|
|
|
(await performDualstackTest(
|
|
|
|
DualStackType.Auto, serverAddress,
|
|
|
|
DualStackType.Disabled, initTAddress("[::1]:0"))) == true
|
|
|
|
else:
|
|
|
|
skip()
|
2024-04-13 00:04:42 +00:00
|
|
|
asyncTest "[IP] Auto-address constructor test (*:0)":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest(Port(0), AddressFamily.IPv6)) == true
|
|
|
|
# If IPv6 is available createStreamServer should bind to `::` this means
|
|
|
|
# that we should be able to connect to it via IPV4_MAPPED address, but
|
|
|
|
# only when IPv4 is also available.
|
|
|
|
if isAvailable(AddressFamily.IPv4):
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest(Port(0), AddressFamily.IPv4)) == true
|
|
|
|
else:
|
|
|
|
# If IPv6 is not available createStreamServer should bind to `0.0.0.0`
|
|
|
|
# this means we should be able to connect to it via IPV4 address.
|
|
|
|
if isAvailable(AddressFamily.IPv4):
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest(Port(0), AddressFamily.IPv4)) == true
|
|
|
|
|
|
|
|
asyncTest "[IP] Auto-address constructor test (*:30532)":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest(Port(30532), AddressFamily.IPv6)) == true
|
|
|
|
# If IPv6 is available createStreamServer should bind to `::` this means
|
|
|
|
# that we should be able to connect to it via IPV4_MAPPED address, but
|
|
|
|
# only when IPv4 is also available.
|
|
|
|
if isAvailable(AddressFamily.IPv4):
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest(Port(30532), AddressFamily.IPv4)) ==
|
|
|
|
true
|
|
|
|
else:
|
|
|
|
# If IPv6 is not available createStreamServer should bind to `0.0.0.0`
|
|
|
|
# this means we should be able to connect to it via IPV4 address.
|
|
|
|
if isAvailable(AddressFamily.IPv4):
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest(Port(30532), AddressFamily.IPv4)) ==
|
|
|
|
true
|
|
|
|
|
|
|
|
for portNumber in [Port(0), Port(30231)]:
|
|
|
|
asyncTest "[IP] IPv6 mapping test (auto-auto:" & $int(portNumber) & ")":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
let
|
|
|
|
address1 = Opt.none(IpAddress)
|
|
|
|
address2 = Opt.none(IpAddress)
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest2(
|
|
|
|
address1, address2, portNumber, AddressFamily.IPv4))
|
|
|
|
(await performAutoAddressTest2(
|
|
|
|
address1, address2, portNumber, AddressFamily.IPv6))
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] IPv6 mapping test (auto-ipv6:" & $int(portNumber) & ")":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
let
|
|
|
|
address1 = Opt.none(IpAddress)
|
|
|
|
address2 = Opt.some(initTAddress("[::1]:0").toIpAddress())
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest2(
|
|
|
|
address1, address2, portNumber, AddressFamily.IPv6))
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] IPv6 mapping test (auto-ipv4:" & $int(portNumber) & ")":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
let
|
|
|
|
address1 = Opt.none(IpAddress)
|
|
|
|
address2 = Opt.some(initTAddress("127.0.0.1:0").toIpAddress())
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest2(
|
|
|
|
address1, address2, portNumber, AddressFamily.IPv4))
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] IPv6 mapping test (ipv6-auto:" & $int(portNumber) & ")":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
let
|
|
|
|
address1 = Opt.some(initTAddress("[::1]:0").toIpAddress())
|
|
|
|
address2 = Opt.none(IpAddress)
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest2(
|
|
|
|
address1, address2, portNumber, AddressFamily.IPv6))
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
asyncTest "[IP] IPv6 mapping test (ipv4-auto:" & $int(portNumber) & ")":
|
|
|
|
if isAvailable(AddressFamily.IPv6):
|
|
|
|
let
|
|
|
|
address1 = Opt.some(initTAddress("127.0.0.1:0").toIpAddress())
|
|
|
|
address2 = Opt.none(IpAddress)
|
|
|
|
check:
|
|
|
|
(await performAutoAddressTest2(
|
|
|
|
address1, address2, portNumber, AddressFamily.IPv4))
|
|
|
|
else:
|
|
|
|
skip()
|
|
|
|
|
2020-06-24 08:21:52 +00:00
|
|
|
test "File descriptors leak test":
|
|
|
|
when defined(windows):
|
|
|
|
# Windows handle numbers depends on many conditions, so we can't use
|
|
|
|
# our FD leak detection method.
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
check getCurrentFD() == markFD
|