Implement dial, support IPv6 in httpclient (#5763)
* Implement dial, support IPv6 in httpclient Added ``dial`` procedure to networking modules: ``net``, ``asyncdispatch``, ``asyncnet``. It merges socket creation, address resolution, and connection into single step. When using ``dial``, you don't have to worry about IPv4 vs IPv6 problem. Fixed addrInfo loop in connect to behave properly. Previously it would stop on first non-immediate failure, instead of continuing and trying the remaining addresses. Fixed newAsyncNativeSocket to raise proper error if socket creation fails. Fixes: #3811 * Check domain during connect() only on non-Windows This is how it was in the previous implementation of connect(). * Call 'osLastError' before 'close' in net.dial * Record osLastError before freeAddrInfo in net.dial * Add missing docs for 'dial' proc * Optimize dial to create one FD per domain, add tests And make async IPv6 servers work on Windows. * Add IPv6 test to uri module * Fix getAddrString error handling
This commit is contained in:
parent
6377b52d8e
commit
ecf278c467
13 changed files with 559 additions and 334 deletions
53
tests/async/tasyncdial.nim
Normal file
53
tests/async/tasyncdial.nim
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
discard """
|
||||
file: "tasyncdial.nim"
|
||||
output: '''
|
||||
OK AF_INET
|
||||
OK AF_INET6
|
||||
'''
|
||||
"""
|
||||
|
||||
import
|
||||
nativesockets, os, asyncdispatch
|
||||
|
||||
proc setupServerSocket(hostname: string, port: Port, domain: Domain): AsyncFD =
|
||||
## Creates a socket, binds it to the specified address, and starts listening for connecitons.
|
||||
## Registers the descriptor with the dispatcher of the current thread
|
||||
## Raises OSError in case of an error.
|
||||
let fd = newNativeSocket(domain)
|
||||
setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
|
||||
var aiList = getAddrInfo(hostname, port, domain)
|
||||
if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
|
||||
freeAddrInfo(aiList)
|
||||
raiseOSError(osLastError())
|
||||
freeAddrInfo(aiList)
|
||||
if listen(fd) != 0:
|
||||
raiseOSError(osLastError())
|
||||
setBlocking(fd, false)
|
||||
result = fd.AsyncFD
|
||||
register(result)
|
||||
|
||||
proc doTest(domain: static[Domain]) {.async.} =
|
||||
const
|
||||
testHost = when domain == Domain.AF_INET6: "::1" else: "127.0.0.1"
|
||||
testPort = Port(17384)
|
||||
let serverFd = setupServerSocket(testHost, testPort, domain)
|
||||
let acceptFut = serverFd.accept()
|
||||
let clientFdFut = dial(testHost, testPort)
|
||||
|
||||
let serverClientFd = await acceptFut
|
||||
serverFd.closeSocket()
|
||||
|
||||
let clientFd = await clientFdFut
|
||||
|
||||
let recvFut = serverClientFd.recv(2)
|
||||
await clientFd.send("Hi")
|
||||
let msg = await recvFut
|
||||
|
||||
serverClientFd.closeSocket()
|
||||
clientFd.closeSocket()
|
||||
|
||||
if msg == "Hi":
|
||||
echo "OK ", domain
|
||||
|
||||
waitFor(doTest(Domain.AF_INET))
|
||||
waitFor(doTest(Domain.AF_INET6))
|
||||
Loading…
Add table
Add a link
Reference in a new issue