import net, asyncnet, asyncdispatch, asyncreadline, punch from strutils import format, join from nativesockets import setSockOptInt from os import paramCount, paramStr var IPPROTO_IP {.importc: "IPPROTO_IP", header: "".}: cint var IP_TTL {.importc: "IP_TTL", header: "".}: cint proc usage() = echo("Usage: $# client|server".format(paramStr(0))) proc processInput(client: AsyncSocket) {.async.} = while true: let input = await asyncReadline() await client.send(input & "\c\L") proc connectAsClient(clientAddress: string, clientPort: Port, serverAddress: string, serverPort: Port) {.async.} = var client = newAsyncSocket() client.setSockOpt(OptReuseAddr, true) client.getFd().setSockOptInt(IPPROTO_IP, IP_TTL, 2) client.bindAddr(clientPort, clientAddress) try: echo "trying to connect" await client.connect(serverAddress, serverPort) let (address, port) = client.getPeerAddr() echo("connected to $#:$#!".format(address, port.uint16)) asyncCheck processInput(client) while true: let line = await client.recvLine() if line.len == 0: break echo("server responded: $#".format(line)) except OSError as e: echo("Error: $#".format(e.msg)) proc processClient(client: AsyncSocket) {.async.} = while true: let line = await client.recvLine() if line.len == 0: break echo("client sent message: $#".format(line)) await client.send(line & "\c\L") proc runServer(serverAddress: string, serverPort: Port, clientAddress: string, clientPort: Port) {.async.} = var server = newAsyncSocket() server.setSockOpt(OptReuseAddr, true) server.bindAddr(serverPort) server.listen() echo("listening on port $#".format(serverPort.uint16)) while true: let client = await server.accept() let (address, port) = client.getPeerAddr() echo("client $#:$# connected!".format(address, port.uint16())) asyncCheck processClient(client) proc main() = if paramCount() != 1: usage() return let serverAddress = "176.95.209.87" let serverPort = Port(80) let clientAddress = $getPrimaryIPAddr(parseIpAddress(serverAddress)) let clientPort = Port(1234) case paramStr(1) of "client": asyncCheck punchHoleAsClient(clientAddress, clientPort, serverAddress, serverPort) asyncCheck connectAsClient(clientAddress, clientPort, serverAddress, serverPort) try: runForever() except NetworkInterfaceError as e: echo(e.msg) except PunchHoleError as e: echo(e.msg) of "server": asyncCheck runServer(serverAddress, serverPort, clientAddress, clientPort) try: runForever() except ValueError: echo "server got ValueError!" discard else: usage() when isMainModule: main()