I recently trying to follow the Nim days 15: https://xmonader.github.io/nimdays/day15_tcprouter.html, but when I tried to set up the server to serve on port say 11000 and forward to my local hosted http server 6543, I just got all these kind of errors:
Async traceback:
/Users/geohuz/Coding/nimlearn/portForwarding2.nim(69) portForwarding2
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncdispatch.nim(1874) runForever
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncdispatch.nim(1569) poll
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncdispatch.nim(1335) runOnce
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncdispatch.nim(210) processPendingCallbacks
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncmacro.nim(34) remoteHasDataNimAsyncContinue
/Users/geohuz/Coding/nimlearn/portForwarding2.nim(37) remoteHasDataIter
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncmacro.nim(313) send
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncmacro.nim(34) sendNimAsyncContinue
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncnet.nim(446) sendIter
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/pure/asyncdispatch.nim(1843) send
/Users/geohuz/.choosenim/toolchains/nim-1.0.4/lib/system/fatal.nim(39) sysFatal
Exception message: index out of bounds, the container is empty
Exception type:
in remote has data loop
got data:
index out of bounds, the container is empty
and here is the code:
import strformat, tables, json, strutils, sequtils, hashes, net, asyncdispatch, asyncnet, os, strutils, parseutils, deques, options, net
type ForwardOptions = object
listenAddr*: string
listenPort*: Port
toAddr*: string
toPort*: Port
type Forwarder = object of RootObj
options*: ForwardOptions
proc processClient(this: ref Forwarder, client: AsyncSocket) {.async.} =
let remote = newAsyncSocket(buffered=false)
await remote.connect(this.options.toAddr, this.options.toPort)
proc clientHasData() {.async.} =
while not client.isClosed and not remote.isClosed:
echo "in client has data loop"
let data = await client.recv(1024)
echo "got data: " & data
try:
await remote.send(data)
except:
echo getCurrentExceptionMsg()
client.close()
remote.close()
proc remoteHasData() {.async.} =
while not remote.isClosed and not client.isClosed:
echo " in remote has data loop"
let data = await remote.recv(1024)
echo "got data: " & data
try:
await client.send(data)
except:
echo getCurrentExceptionMsg()
client.close()
remote.close()
try:
asyncCheck clientHasData()
asyncCheck remoteHasData()
except:
echo getCurrentExceptionMsg()
proc serve(this: ref Forwarder) {.async.} =
var server = newAsyncSocket(buffered=false)
server.setSockOpt(OptReuseAddr, true)
server.bindAddr(this.options.listenPort, this.options.listenAddr)
echo fmt"Started tcp server... {this.options.listenAddr}:{this.options.listenPort} "
server.listen()
while true:
let client = await server.accept()
echo "..Got connection "
asyncCheck this.processClient(client)
proc newForwarder(opts: ForwardOptions): ref Forwarder =
result = new(Forwarder)
result.options = opts
let opts = ForwardOptions(listenAddr:"127.0.0.1", listenPort:11000.Port, toAddr:"127.0.0.1", toPort:6543.Port)
var f = newForwarder(opts)
asyncCheck f.serve()
runForever()
Does it work if you remove the try/except blocks you added in ...HasData procedures? If it does, then the issue is as roughly explained here: https://nim-lang.org/docs/asyncdispatch.html#asynchronous-procedures-handling-exceptions
It seems like async and exceptions don't go very well together, at least not yet.
So I changed code as below:
proc processClient(this: ref Forwarder, client: AsyncSocket) {.async.} =
let remote = newAsyncSocket(buffered=false)
await remote.connect(this.options.toAddr, this.options.toPort)
proc clientHasData() {.async.} =
while not client.isClosed and not remote.isClosed:
let recv = client.recv(1024)
yield recv
if recv.failed:
echo "recv error........."
else:
let send = remote.send(recv.read)
yield send
if send.failed:
echo "send error...."
client.close()
remote.close()
proc remoteHasData() {.async.} =
while not remote.isClosed and not client.isClosed:
let recv = remote.recv(1024)
yield recv
if recv.failed:
echo "recv error...."
else:
let send = client.send(recv.read)
yield send
if send.failed:
echo "send error...."
client.close()
remote.close()
try:
asyncCheck clientHasData()
asyncCheck remoteHasData()
except:
echo getCurrentExceptionMsg()
but I still got numerous "send error...", but the forwarding seems working.