let puncher additional sockets; implement initiating from behind SymmetricRandom NAT using 1000 sockets (untested)
This commit is contained in:
parent
bf9569098f
commit
bdeb00d71c
87
puncher.nim
87
puncher.nim
|
@ -6,21 +6,20 @@ from nativesockets import
|
||||||
SockLen,
|
SockLen,
|
||||||
getSockOptInt,
|
getSockOptInt,
|
||||||
setSockOptInt
|
setSockOptInt
|
||||||
from sequtils import any
|
from sequtils import any, map
|
||||||
|
|
||||||
type
|
type
|
||||||
Attempt* = object
|
Attempt* = object
|
||||||
## A hole punching attempt.
|
## A hole punching attempt.
|
||||||
srcPorts*: seq[Port]
|
socks*: seq[AsyncSocket]
|
||||||
dstIp*: IpAddress
|
dstIp*: IpAddress
|
||||||
dstPorts*: seq[Port]
|
dstPorts*: seq[Port]
|
||||||
future*: Future[(AsyncSocket, Port)]
|
future*: Future[(AsyncSocket, Port)]
|
||||||
|
|
||||||
Puncher* = ref object
|
Puncher* = ref object
|
||||||
socks: seq[AsyncSocket]
|
socks*: seq[AsyncSocket]
|
||||||
srcPorts: seq[Port]
|
natProps*: NatProperties
|
||||||
natProps: NatProperties
|
attempts*: seq[Attempt]
|
||||||
attempts: seq[Attempt]
|
|
||||||
|
|
||||||
PunchHoleError* = object of ValueError
|
PunchHoleError* = object of ValueError
|
||||||
|
|
||||||
|
@ -28,50 +27,73 @@ var IPPROTO_IP {.importc: "IPPROTO_IP", header: "<netinet/in.h>".}: cint
|
||||||
var IP_TTL {.importc: "IP_TTL", header: "<netinet/in.h>".}: cint
|
var IP_TTL {.importc: "IP_TTL", header: "<netinet/in.h>".}: cint
|
||||||
|
|
||||||
const Timeout = 3000
|
const Timeout = 3000
|
||||||
|
const InitiatorMaxSockCount = 1000
|
||||||
|
const ResponderMaxSockCount = 70
|
||||||
|
const MaxSockCount = max(InitiatorMaxSockCount, ResponderMaxSockCount)
|
||||||
|
|
||||||
|
proc srcPort(sock: AsyncSocket): Port =
|
||||||
|
result = sock.getLocalAddr[1]
|
||||||
|
|
||||||
proc `==`(a, b: Attempt): bool =
|
proc `==`(a, b: Attempt): bool =
|
||||||
## ``==`` for hole punching attempts.
|
## ``==`` for hole punching attempts.
|
||||||
##
|
##
|
||||||
## Two hole punching attempts are considered equal if their ``dstIp`` is
|
## Two hole punching attempts are considered equal if their ``dstIp`` is
|
||||||
## equal, their ``srcPorts`` overlap and their ``dstPorts`` overlap.
|
## equal and their ``dstPorts`` overlap.
|
||||||
a.dstIp == b.dstIp and
|
a.dstIp == b.dstIp and a.dstPorts.any(proc (p: Port): bool = p in b.dstPorts)
|
||||||
a.srcPorts.any(proc (p: Port): bool = p in b.srcPorts) and
|
|
||||||
a.dstPorts.any(proc (p: Port): bool = p in b.dstPorts)
|
|
||||||
|
|
||||||
proc initPuncher*(socks: seq[AsyncSocket], probedSrcPorts: seq[Port]): Puncher =
|
proc initPuncher*(sock: AsyncSocket, probedSrcPorts: seq[Port]): Puncher =
|
||||||
assert(socks.len > 0)
|
# TODO: determine IP_TTL
|
||||||
var srcPorts = newSeq[Port](socks.len)
|
let (_, primarySrcPort) = sock.getLocalAddr()
|
||||||
for i in 0 .. socks.len - 1:
|
let natProps = getNatProperties(primarySrcPort, probedSrcPorts)
|
||||||
let (_, srcPort) = socks[i].getLocalAddr()
|
result = Puncher(socks: @[sock], natProps: natProps)
|
||||||
srcPorts[i] = srcPort
|
if result.natProps.natType == SymmetricRandom:
|
||||||
let natProps = getNatProperties(srcPorts[0], probedSrcPorts)
|
# our NAT is of the evil symmetric type with random port allocation. We are
|
||||||
Puncher(socks: socks, srcPorts: srcPorts, natProps: natProps)
|
# trying to help the other peer by allocating a lot of auxillary sockets
|
||||||
|
# for punching more holes
|
||||||
|
result.socks.setLen(MaxSockCount)
|
||||||
|
for i in 1 .. MaxSockCount - 1:
|
||||||
|
result.socks[i] = newAsyncSocket(sockType = SOCK_DGRAM,
|
||||||
|
protocol = IPPROTO_UDP, buffered = false)
|
||||||
|
result.socks[i].bindAddr(Port(0))
|
||||||
|
|
||||||
|
proc primarySrcPort*(puncher: Puncher): Port =
|
||||||
|
puncher.socks[0].srcPort
|
||||||
|
|
||||||
|
# TODO: lowTTL -> isInitiating, if isInitiating: punch with all auxSocks, else only use 70
|
||||||
proc punch(puncher: Puncher, peerIp: IpAddress, peerPort: Port,
|
proc punch(puncher: Puncher, peerIp: IpAddress, peerPort: Port,
|
||||||
peerProbedPorts: seq[Port], lowTTL: bool, msg: string):
|
peerProbedPorts: seq[Port], isInitiating: bool, msg: string):
|
||||||
Future[Attempt] {.async.} =
|
Future[Attempt] {.async.} =
|
||||||
let punchFuture = newFuture[(AsyncSocket, Port)]("punch")
|
let punchFuture = newFuture[(AsyncSocket, Port)]("punch")
|
||||||
let natProps = getNatProperties(peerPort, peerProbedPorts)
|
let peerNatProps = getNatProperties(peerPort, peerProbedPorts)
|
||||||
let predictedDstPorts = predictPortRange(natProps)
|
var sockCount = 1
|
||||||
result = Attempt(srcPorts: @[puncher.srcPorts[0]], dstIp: peerIp,
|
if puncher.natProps.natType == SymmetricRandom:
|
||||||
dstPorts: predictedDstPorts, future: punchFuture)
|
# Our NAT is of the evil symmetric type with random port allocation. We are
|
||||||
if puncher.natProps.natType == SymmetricRandom and puncher.srcPorts.len > 1:
|
|
||||||
# our NAT is of the evil symmetric type with random port allocation. We are
|
|
||||||
# trying to help the other peer by punching more holes using all our
|
# trying to help the other peer by punching more holes using all our
|
||||||
# sockets.
|
# sockets.
|
||||||
result.srcPorts.add(puncher.srcPorts[1 .. ^1])
|
if peerNatProps.natType == SymmetricRandom:
|
||||||
|
# If the other peer is behind a SymmetricRandom NAT too we give up.
|
||||||
|
raise newException(PunchHoleError,
|
||||||
|
"both peers behind symmetric NAT with random port allocation")
|
||||||
|
sockCount = if isInitiating:
|
||||||
|
InitiatorMaxSockCount
|
||||||
|
else:
|
||||||
|
ResponderMaxSockCount
|
||||||
|
let predictedDstPorts = predictPortRange(peerNatProps)
|
||||||
|
result = Attempt(dstIp: peerIp, dstPorts: predictedDstPorts,
|
||||||
|
future: punchFuture)
|
||||||
if puncher.attempts.contains(result):
|
if puncher.attempts.contains(result):
|
||||||
raise newException(PunchHoleError,
|
raise newException(PunchHoleError,
|
||||||
"hole punching for given parameters already active")
|
"hole punching to given destination already active")
|
||||||
puncher.attempts.add(result)
|
puncher.attempts.add(result)
|
||||||
echo &"sending msg {msg} to {peerIp}, srcPorts: {result.srcPorts}, dstPorts: {result.dstPorts}"
|
let srcPorts = puncher.socks[0 .. sockCount - 1].map(srcPort)
|
||||||
|
echo &"sending msg {msg} to {peerIp}, srcPorts: {srcPorts}, dstPorts: {result.dstPorts}"
|
||||||
var peerAddr: Sockaddr_storage
|
var peerAddr: Sockaddr_storage
|
||||||
var peerSockLen: SockLen
|
var peerSockLen: SockLen
|
||||||
try:
|
try:
|
||||||
var defaultTTL: int
|
var defaultTTL: int
|
||||||
for i in 0 .. result.srcPorts.len - 1:
|
for i in 0 .. sockCount - 1:
|
||||||
let sock = puncher.socks[i]
|
let sock = puncher.socks[i]
|
||||||
if lowTTL:
|
if isInitiating:
|
||||||
defaultTTL = sock.getFd.getSockOptInt(IPPROTO_IP, IP_TTL)
|
defaultTTL = sock.getFd.getSockOptInt(IPPROTO_IP, IP_TTL)
|
||||||
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, 2)
|
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, 2)
|
||||||
for dstPort in result.dstPorts:
|
for dstPort in result.dstPorts:
|
||||||
|
@ -79,7 +101,7 @@ proc punch(puncher: Puncher, peerIp: IpAddress, peerPort: Port,
|
||||||
# TODO: replace asyncdispatch.sendTo with asyncnet.sendTo (Nim 1.4 required)
|
# TODO: replace asyncdispatch.sendTo with asyncnet.sendTo (Nim 1.4 required)
|
||||||
await sendTo(sock.getFd.AsyncFD, msg.cstring, msg.len,
|
await sendTo(sock.getFd.AsyncFD, msg.cstring, msg.len,
|
||||||
cast[ptr SockAddr](addr peerAddr), peerSockLen)
|
cast[ptr SockAddr](addr peerAddr), peerSockLen)
|
||||||
if lowTTL:
|
if isInitiating:
|
||||||
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, defaultTTL)
|
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, defaultTTL)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise newException(PunchHoleError, e.msg)
|
raise newException(PunchHoleError, e.msg)
|
||||||
|
@ -107,8 +129,7 @@ proc handleMsg*(puncher: Puncher, msg: string, sock: AsyncSocket,
|
||||||
# We received a SYN packet. We ignore it because we expected it to be
|
# We received a SYN packet. We ignore it because we expected it to be
|
||||||
# filtered by our NAT.
|
# filtered by our NAT.
|
||||||
return
|
return
|
||||||
let query = Attempt(srcPorts: puncher.srcPorts, dstIp: peerIp,
|
let query = Attempt(dstIp: peerIp, dstPorts: @[peerPort])
|
||||||
dstPorts: @[peerPort])
|
|
||||||
let i = puncher.attempts.find(query)
|
let i = puncher.attempts.find(query)
|
||||||
if i != -1:
|
if i != -1:
|
||||||
if msg == "ACK":
|
if msg == "ACK":
|
||||||
|
|
49
quicp2p.nim
49
quicp2p.nim
|
@ -18,7 +18,6 @@ import quicly/defaults
|
||||||
import quicly/recvstate
|
import quicly/recvstate
|
||||||
import quicly/sendstate
|
import quicly/sendstate
|
||||||
import quicly/streambuf
|
import quicly/streambuf
|
||||||
import random
|
|
||||||
import server_connection
|
import server_connection
|
||||||
import strformat
|
import strformat
|
||||||
import strutils
|
import strutils
|
||||||
|
@ -48,8 +47,6 @@ type
|
||||||
expectedPeerId: string
|
expectedPeerId: string
|
||||||
|
|
||||||
QuicP2PContext = ref object
|
QuicP2PContext = ref object
|
||||||
socks: seq[AsyncSocket]
|
|
||||||
puncher: Puncher
|
|
||||||
streamOpen: quicly_stream_open_t
|
streamOpen: quicly_stream_open_t
|
||||||
nextCid: quicly_cid_plaintext_t
|
nextCid: quicly_cid_plaintext_t
|
||||||
signCertCb: ptls_openssl_sign_certificate_t
|
signCertCb: ptls_openssl_sign_certificate_t
|
||||||
|
@ -82,10 +79,6 @@ proc relativeTimeout(ctx: QuicP2PContext): int32 =
|
||||||
let delta = nextTimeout - now
|
let delta = nextTimeout - now
|
||||||
result = min(delta, int32.high).int32
|
result = min(delta, int32.high).int32
|
||||||
|
|
||||||
proc srcPort(ctx: QuicP2PContext): Port =
|
|
||||||
let (_, myPort) = ctx.socks[0].getLocalAddr()
|
|
||||||
myPort
|
|
||||||
|
|
||||||
proc peerId(ctx: QuicP2PContext): string =
|
proc peerId(ctx: QuicP2PContext): string =
|
||||||
assert(ctx.tlsCtx.certificates.count == 2)
|
assert(ctx.tlsCtx.certificates.count == 2)
|
||||||
let firstCertAddr = cast[ByteAddress](ctx.tlsCtx.certificates.list)
|
let firstCertAddr = cast[ByteAddress](ctx.tlsCtx.certificates.list)
|
||||||
|
@ -214,8 +207,7 @@ proc verifyCerts(self: ptr ptls_verify_certificate_t, tls: ptr ptls_t,
|
||||||
X509_STORE_free(store)
|
X509_STORE_free(store)
|
||||||
X509_free(caCert)
|
X509_free(caCert)
|
||||||
|
|
||||||
proc initContext(socks: seq[AsyncSocket], certChainPath: string,
|
proc initContext(certChainPath: string, keyPath: string,
|
||||||
keyPath: string,
|
|
||||||
streamOpenCb: typeof(quicly_stream_open_t.cb)):
|
streamOpenCb: typeof(quicly_stream_open_t.cb)):
|
||||||
QuicP2PContext =
|
QuicP2PContext =
|
||||||
var tlsCtx = ptls_context_t(randomBytes: ptls_openssl_random_bytes,
|
var tlsCtx = ptls_context_t(randomBytes: ptls_openssl_random_bytes,
|
||||||
|
@ -223,8 +215,7 @@ proc initContext(socks: seq[AsyncSocket], certChainPath: string,
|
||||||
keyExchanges: ptls_openssl_key_exchanges,
|
keyExchanges: ptls_openssl_key_exchanges,
|
||||||
cipherSuites: ptls_openssl_cipher_suites)
|
cipherSuites: ptls_openssl_cipher_suites)
|
||||||
quicly_amend_ptls_context(addr tlsCtx)
|
quicly_amend_ptls_context(addr tlsCtx)
|
||||||
result = QuicP2PContext(socks: socks,
|
result = QuicP2PContext(streamOpen: quicly_stream_open_t(cb: streamOpenCb),
|
||||||
streamOpen: quicly_stream_open_t(cb: streamOpenCb),
|
|
||||||
verifyCertsCb: ptls_verify_certificate_t(cb: verifyCerts),
|
verifyCertsCb: ptls_verify_certificate_t(cb: verifyCerts),
|
||||||
tlsCtx: tlsCtx, quiclyCtx: quicly_spec_context)
|
tlsCtx: tlsCtx, quiclyCtx: quicly_spec_context)
|
||||||
result.quiclyCtx.tls = addr result.tlsCtx
|
result.quiclyCtx.tls = addr result.tlsCtx
|
||||||
|
@ -350,19 +341,23 @@ proc handleNotification(puncher: Puncher, notification: NotifyPeer) {.async.} =
|
||||||
discard await attempt.finalize()
|
discard await attempt.finalize()
|
||||||
|
|
||||||
proc runApp(ctx: QuicP2PContext, peerId: string) {.async.} =
|
proc runApp(ctx: QuicP2PContext, peerId: string) {.async.} =
|
||||||
let serverConn = await initServerConnection(rendezvousServers[0].hostname,
|
let primarySock = newAsyncSocket(sockType = SOCK_DGRAM,
|
||||||
|
protocol = IPPROTO_UDP, buffered = false)
|
||||||
|
primarySock.bindAddr(Port(0))
|
||||||
|
let serverConn = await initServerConnection(primarySock,
|
||||||
|
rendezvousServers[0].hostname,
|
||||||
rendezvousServers[0].port,
|
rendezvousServers[0].port,
|
||||||
ctx.srcPort, rendezvousServers)
|
rendezvousServers)
|
||||||
let puncher = initPuncher(ctx.socks, serverConn.probedSrcPorts)
|
let puncher = initPuncher(primarySock, serverConn.probedSrcPorts)
|
||||||
|
|
||||||
asyncCheck handleServerMessages(serverConn)
|
asyncCheck handleServerMessages(serverConn)
|
||||||
for sock in ctx.socks:
|
for sock in puncher.socks:
|
||||||
asyncCheck receive(ctx, puncher, sock, peerId)
|
asyncCheck receive(ctx, puncher, sock, peerId)
|
||||||
|
|
||||||
if peerId.len == 0:
|
if peerId.len == 0:
|
||||||
# We are the responder
|
# We are the responder
|
||||||
let probedPorts = serverConn.probedSrcPorts.join(",")
|
let probedPorts = serverConn.probedSrcPorts.join(",")
|
||||||
let req = &"{ctx.peerId}|{serverConn.probedIp}|{ctx.srcPort}|{probedPorts}"
|
let req = &"{ctx.peerId}|{serverConn.probedIp}|{puncher.primarySrcPort}|{probedPorts}"
|
||||||
discard await serverConn.sendRequest("register", req)
|
discard await serverConn.sendRequest("register", req)
|
||||||
while true:
|
while true:
|
||||||
let (hasData, data) = await serverConn.peerNotifications.read()
|
let (hasData, data) = await serverConn.peerNotifications.read()
|
||||||
|
@ -382,7 +377,7 @@ proc runApp(ctx: QuicP2PContext, peerId: string) {.async.} =
|
||||||
let peerInfo = parseMessage[OkGetPeerInfo](serverResponse)
|
let peerInfo = parseMessage[OkGetPeerInfo](serverResponse)
|
||||||
let myProbedPorts = serverConn.probedSrcPorts.join(",")
|
let myProbedPorts = serverConn.probedSrcPorts.join(",")
|
||||||
let peerProbedPorts = peerInfo.probedPorts.join(",")
|
let peerProbedPorts = peerInfo.probedPorts.join(",")
|
||||||
let req = &"{ctx.peerId}|{peerId}|{serverConn.probedIp}|{ctx.srcPort}|{myProbedPorts}|{peerInfo.ip}|{peerInfo.localPort}|{peerProbedPorts}"
|
let req = &"{ctx.peerId}|{peerId}|{serverConn.probedIp}|{puncher.primarySrcPort}|{myProbedPorts}|{peerInfo.ip}|{peerInfo.localPort}|{peerProbedPorts}"
|
||||||
let attempt = await puncher.initiate(peerInfo.ip, peerInfo.localPort,
|
let attempt = await puncher.initiate(peerInfo.ip, peerInfo.localPort,
|
||||||
peerInfo.probedPorts)
|
peerInfo.probedPorts)
|
||||||
discard await serverConn.sendRequest("notify-peer", req)
|
discard await serverConn.sendRequest("notify-peer", req)
|
||||||
|
@ -391,31 +386,15 @@ proc runApp(ctx: QuicP2PContext, peerId: string) {.async.} =
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
var ctx: QuicP2PContext
|
var ctx: QuicP2PContext
|
||||||
var socks = newSeq[AsyncSocket]()
|
|
||||||
randomize()
|
|
||||||
for i in 0 .. 70:
|
|
||||||
# FIXME: close socks
|
|
||||||
let sock = newAsyncSocket(sockType = SOCK_DGRAM, protocol = IPPROTO_UDP,
|
|
||||||
buffered = false)
|
|
||||||
let srcPort = rand(Port(1024) .. Port.high)
|
|
||||||
# FIXME: Once we start using UDP for endpoint probing (currently done in
|
|
||||||
# initServerConnction) we either have to
|
|
||||||
# - finish the probing before we bind the srcPort here
|
|
||||||
# - pass the primary socket to initServerConnection
|
|
||||||
sock.bindAddr(srcPort)
|
|
||||||
socks.add(sock)
|
|
||||||
|
|
||||||
case paramCount():
|
case paramCount():
|
||||||
of 0:
|
of 0:
|
||||||
ctx = initContext(socks, serverCertChainPath, serverKeyPath,
|
ctx = initContext(serverCertChainPath, serverKeyPath, onServerStreamOpen)
|
||||||
onServerStreamOpen)
|
|
||||||
ctx.tlsCtx.require_client_authentication = 1
|
ctx.tlsCtx.require_client_authentication = 1
|
||||||
asyncCheck runApp(ctx, "")
|
asyncCheck runApp(ctx, "")
|
||||||
|
|
||||||
of 1:
|
of 1:
|
||||||
let peerId = paramStr(1)
|
let peerId = paramStr(1)
|
||||||
ctx = initContext(socks, clientCertChainPath, clientKeyPath,
|
ctx = initContext(clientCertChainPath, clientKeyPath, onClientStreamOpen)
|
||||||
onClientStreamOpen)
|
|
||||||
asyncCheck runApp(ctx, peerId)
|
asyncCheck runApp(ctx, peerId)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -8,7 +8,6 @@ type
|
||||||
outMessages: TableRef[string, Future[string]]
|
outMessages: TableRef[string, Future[string]]
|
||||||
peerNotifications*: FutureStream[string]
|
peerNotifications*: FutureStream[string]
|
||||||
probedIp*: IpAddress
|
probedIp*: IpAddress
|
||||||
srcPort*: Port
|
|
||||||
probedSrcPorts*: seq[Port]
|
probedSrcPorts*: seq[Port]
|
||||||
|
|
||||||
ServerError* = object of ValueError
|
ServerError* = object of ValueError
|
||||||
|
@ -32,39 +31,41 @@ type
|
||||||
dstPort*: Port
|
dstPort*: Port
|
||||||
probedDstPorts*: seq[Port]
|
probedDstPorts*: seq[Port]
|
||||||
|
|
||||||
proc getEndpoint(srcPort: Port, serverHostname: string, serverPort: Port):
|
proc getEndpoint(sock: AsyncSocket, serverHostname: string, serverPort: Port):
|
||||||
Future[OkGetEndpoint] {.async.} =
|
Future[OkGetEndpoint] {.async.} =
|
||||||
let sock = newAsyncSocket()
|
# TODO: use sock (UDP socket) for probing
|
||||||
|
let tcpSock = newAsyncSocket()
|
||||||
|
let (_, srcPort) = sock.getLocalAddr
|
||||||
var failCount = 0
|
var failCount = 0
|
||||||
while true:
|
while true:
|
||||||
try:
|
try:
|
||||||
sock.bindAddr(srcPort)
|
tcpSock.bindAddr(srcPort)
|
||||||
break
|
break
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if failCount == 3:
|
if failCount == 3:
|
||||||
raise e
|
raise e
|
||||||
failCount.inc
|
failCount.inc
|
||||||
await sleepAsync(100)
|
await sleepAsync(100)
|
||||||
await sock.connect(serverHostname, serverPort)
|
await tcpSock.connect(serverHostname, serverPort)
|
||||||
let id = rand(uint32)
|
let id = rand(uint32)
|
||||||
await sock.send(&"get-endpoint|{id}\n")
|
await tcpSock.send(&"get-endpoint|{id}\n")
|
||||||
let line = await sock.recvLine(maxLength = 400)
|
let line = await tcpSock.recvLine(maxLength = 400)
|
||||||
let args = line.parseArgs(3)
|
let args = line.parseArgs(3)
|
||||||
assert(args[0] == "ok")
|
assert(args[0] == "ok")
|
||||||
assert(args[1] == $id)
|
assert(args[1] == $id)
|
||||||
result = parseMessage[OkGetEndpoint](args[2])
|
result = parseMessage[OkGetEndpoint](args[2])
|
||||||
let emptyLine = await sock.recvLine(maxLength = 400)
|
let emptyLine = await tcpSock.recvLine(maxLength = 400)
|
||||||
assert(emptyLine.len == 0)
|
assert(emptyLine.len == 0)
|
||||||
sock.close()
|
tcpSock.close()
|
||||||
|
|
||||||
proc initServerConnection*(serverHostname: string, serverPort: Port,
|
proc initServerConnection*(sock: AsyncSocket, serverHostname: string,
|
||||||
srcPort: Port, probingServers: seq[Endpoint]):
|
serverPort: Port, probingServers: seq[Endpoint]):
|
||||||
Future[ServerConnection] {.async.} =
|
Future[ServerConnection] {.async.} =
|
||||||
|
let peerNotifications = newFutureStream[string]("initServerConnection")
|
||||||
result = ServerConnection(outMessages: newTable[string, Future[string]](),
|
result = ServerConnection(outMessages: newTable[string, Future[string]](),
|
||||||
peerNotifications: newFutureStream[string]("initServerConnection"),
|
peerNotifications: peerNotifications)
|
||||||
srcPort: srcPort)
|
|
||||||
for s in probingServers:
|
for s in probingServers:
|
||||||
let endpoint = await getEndpoint(srcPort, s.hostname, s.port)
|
let endpoint = await getEndpoint(sock, s.hostname, s.port)
|
||||||
# FIXME: what if we get get different IPs from different servers
|
# FIXME: what if we get get different IPs from different servers
|
||||||
result.probedIp = endpoint.ip
|
result.probedIp = endpoint.ip
|
||||||
result.probedSrcPorts.add(endpoint.port)
|
result.probedSrcPorts.add(endpoint.port)
|
||||||
|
|
Loading…
Reference in New Issue