diff --git a/examples/app/app.nim b/examples/app/app.nim index 81d0be1..6f0805c 100644 --- a/examples/app/app.nim +++ b/examples/app/app.nim @@ -22,6 +22,8 @@ type sock: AsyncSocket outMessages: TableRef[string, Future[string]] peerNotifications: FutureStream[string] + probedIp: IpAddress + probedPorts: seq[Port] # Punchd messages ProgressTcpSyniConnect* = object @@ -152,36 +154,50 @@ proc punchHole(punchdConn: PunchdConnection, serverConn: ServerConnection, future.fail(e) except ValueError as e: future.fail(e) - let myPorts = &"{1234},{1234},{1234}" + let myPorts = (@[Port(1234)] & serverConn.probedPorts).join(",") let peerPorts = peerInfo.ports.join(",") let req = &"{ipAddress}|{myPorts}|{peerInfo.ip}|{peerPorts}" let pResp = await punchdConn.sendRequest("tcp-syni-connect", req, progressCb) result = pResp.sock +proc initServerConnection(serverHostname: string, serverPort: Port, + myPort: Port, probePorts: bool): + Future[ServerConnection] {.async.} = + if probePorts: + for i in 0 .. 1: + let sock = newAsyncSocket() + sock.setSockOpt(OptReuseAddr, true) + sock.bindAddr(myPort) + await sock.connect(serverHostname, serverPort) + let line = await sock.recvLine(maxLength = 400) + let endpoint = parseMessage[NotifyEndpoint](line) + result.probedPorts.add(endpoint.port) + sock.close() + result.sock = await asyncnet.dial(serverHostname, serverPort) + let line = await result.sock.recvLine(maxLength = 400) + result.probedIp = parseMessage[NotifyEndpoint](line).ip + result.outMessages = newTable[string, Future[string]]() + result.peerNotifications = newFutureStream[string]("initServerConnection") + proc runApp(serverHostname: string, serverPort: Port, peerId: string, otherPeerId: string = "") {.async.} = - # TODO: determine endpoint in another proc randomize() # initialize random number generator var punchdConn = PunchdConnection() punchdConn.sock = newAsyncSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) punchdConn.outMessages = newTable[string, OutgoingPunchdMessage]() punchdConn.inConnections = newFutureStream[AsyncSocket]("runApp") await punchdConn.sock.connectUnix("/tmp/punchd.socket") - var serverConn = ServerConnection() - serverConn.sock = await asyncnet.dial(serverHostname, serverPort, IPPROTO_TCP) - serverConn.outMessages = newTable[string, Future[string]]() - serverConn.peerNotifications = newFutureStream[string]("runApp") - let resp = await serverConn.sock.recvLine(maxLength = 400) - let endpoint = parseMessage[NotifyEndpoint](resp) - echo &"rendezvous server says I am {endpoint.ip}:{endpoint.port.int}" asyncCheck handlePunchdMessages(punchdConn) - asyncCheck handleServerMessages(serverConn) - asyncCheck handlePeerNotifications(serverConn, punchdConn, peerId) if otherPeerId.len == 0: # register and wait for connections - let req = &"{peerId}|{endpoint.ip}|{endpoint.port.int},{endpoint.port.int},{endpoint.port.int}" + let serverConn = await initServerConnection(serverHostname, serverPort, + Port(4321), true) + asyncCheck handleServerMessages(serverConn) + asyncCheck handlePeerNotifications(serverConn, punchdConn, peerId) + let myPorts = (@[Port(4321)] & serverConn.probedPorts).join(",") + let req = &"{peerId}|{serverConn.probedIp}|{myPorts}" + echo "registering: ", req discard await serverConn.sendRequest("register", req) - echo "registered" while true: let (hasSock, sock) = await punchdConn.inConnections.read if not hasSock: @@ -193,8 +209,11 @@ proc runApp(serverHostname: string, serverPort: Port, peerId: string, else: # initiate a new connection - let sock = await punchHole(punchdConn, serverConn, endpoint.ip, peerId, - otherPeerId) + let serverConn = await initServerConnection(serverHostname, serverPort, + Port(1234), true) + asyncCheck handleServerMessages(serverConn) + let sock = await punchHole(punchdConn, serverConn, serverConn.probedIp, + peerId, otherPeerId) await sock.send("ping") let msg = await sock.recv(1000) echo "received message: ", msg