diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 4a4ef8bdd4..a3a4099e0f 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -957,80 +957,3 @@ proc runForever*() = ## Begins a never ending global dispatcher poll loop. while true: poll() - -when isMainModule: - - var p = newDispatcher() - var sock = p.socket() - sock.setBlocking false - - - when false: - # Await tests - proc main(p: PDispatcher): PFuture[int] {.async.} = - discard await p.connect(sock, "irc.freenode.net", TPort(6667)) - while true: - echo("recvLine") - var line = await p.recvLine(sock) - echo("Line is: ", line.repr) - if line == "": - echo "Disconnected" - break - - proc peekTest(p: PDispatcher): PFuture[int] {.async.} = - discard await p.connect(sock, "localhost", TPort(6667)) - while true: - var line = await p.recv(sock, 1, MSG_PEEK) - var line2 = await p.recv(sock, 1) - echo(line.repr) - echo(line2.repr) - echo("---") - if line2 == "": break - sleep(500) - - var f = main(p) - - - else: - when false: - - var f = p.connect(sock, "irc.poop.nl", TPort(6667)) - f.callback = - proc (future: PFuture[int]) = - echo("Connected in future!") - echo(future.read) - for i in 0 .. 50: - var recvF = p.recv(sock, 10) - recvF.callback = - proc (future: PFuture[string]) = - echo("Read ", future.read.len, ": ", future.read.repr) - - else: - - sock.bindAddr(TPort(6667)) - sock.listen() - proc onAccept(future: PFuture[TSocketHandle]) = - let client = future.read - echo "Accepted ", client.cint - var t = p.send(client, "test\c\L") - t.callback = - proc (future: PFuture[int]) = - echo("Send: ", future.read) - client.close() - - var f = p.accept(sock) - f.callback = onAccept - - var f = p.accept(sock) - f.callback = onAccept - - while true: - p.poll() - - - - - - - - diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 451ef25ac7..de5d84a53a 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -14,32 +14,17 @@ when defined(ssl): import openssl type - TAsyncSocket = object ## socket type - fd: TAsyncFD - case isBuffered: bool # determines whether this socket is buffered. - of true: - buffer: array[0..BufferSize, char] - currPos: int # current index in buffer - bufLen: int # current length of buffer - of false: nil - when defined(ssl): - case isSsl: bool - of true: - sslHandle: PSSL - sslContext: PSSLContext - sslNoHandshake: bool # True if needs handshake. - sslHasPeekChar: bool - sslPeekChar: char - of false: nil - + # TODO: I would prefer to just do: + # PAsyncSocket* {.borrow: `.`.} = distinct PAsyncSocket. But that doesn't work. + TAsyncSocket {.borrow: `.`.} = distinct TSocketImpl PAsyncSocket* = ref TAsyncSocket # TODO: Save AF, domain etc info and reuse it in procs which need it like connect. proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket = assert fd != osInvalidSocket.TAsyncFD - new(result) - result.fd = fd + new(result.PSocket) + result.fd = fd.TSocketHandle result.isBuffered = isBuff if isBuff: result.currPos = 0 @@ -55,7 +40,7 @@ proc connect*(socket: PAsyncSocket, address: string, port: TPort, ## ## Returns a ``PFuture`` which will complete when the connection succeeds ## or an error occurs. - result = connect(socket.fd, address, port, af) + result = connect(socket.fd.TAsyncFD, address, port, af) proc recv*(socket: PAsyncSocket, size: int, flags: int = 0): PFuture[string] = @@ -64,12 +49,12 @@ proc recv*(socket: PAsyncSocket, size: int, ## recv operation then the future may complete with only a part of the ## requested data read. If socket is disconnected and no data is available ## to be read then the future will complete with a value of ``""``. - result = recv(socket.fd, size, flags) + result = recv(socket.fd.TAsyncFD, size, flags) proc send*(socket: PAsyncSocket, data: string): PFuture[void] = ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. - result = send(socket.fd, data) + result = send(socket.fd.TAsyncFD, data) proc acceptAddr*(socket: PAsyncSocket): PFuture[tuple[address: string, client: PAsyncSocket]] = @@ -77,7 +62,7 @@ proc acceptAddr*(socket: PAsyncSocket): ## corresponding to that connection and the remote address of the client. ## The future will complete when the connection is successfully accepted. var retFuture = newFuture[tuple[address: string, client: PAsyncSocket]]() - var fut = acceptAddr(socket.fd) + var fut = acceptAddr(socket.fd.TAsyncFD) fut.callback = proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) = assert future.finished @@ -139,17 +124,72 @@ proc recvLine*(socket: PAsyncSocket): PFuture[string] {.async.} = return add(result.string, c) +proc bindAddr*(socket: PAsyncSocket, port = TPort(0), address = "") = + ## Binds ``address``:``port`` to the socket. + ## + ## If ``address`` is "" then ADDR_ANY will be bound. + socket.PSocket.bindAddr(port, address) + +proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) = + ## Marks ``socket`` as accepting connections. + ## ``Backlog`` specifies the maximum length of the + ## queue of pending connections. + ## + ## Raises an EOS error upon failure. + socket.PSocket.listen(backlog) + +proc close*(socket: PAsyncSocket) = + ## Closes the socket. + socket.fd.TAsyncFD.close() + # TODO SSL + when isMainModule: - proc main() {.async.} = + type + TestCases = enum + HighClient, LowClient, LowServer + + const test = LowServer + + when test == HighClient: + proc main() {.async.} = + var sock = newAsyncSocket() + await sock.connect("irc.freenode.net", TPort(6667)) + while true: + let line = await sock.recvLine() + if line == "": + echo("Disconnected") + break + else: + echo("Got line: ", line) + main() + elif test == LowClient: var sock = newAsyncSocket() - await sock.connect("irc.freenode.net", TPort(6667)) - while true: - let line = await sock.recvLine() - if line == "": - echo("Disconnected") - break - else: - echo("Got line: ", line) - main() + var f = connect(sock, "irc.freenode.net", TPort(6667)) + f.callback = + proc (future: PFuture[void]) = + echo("Connected in future!") + for i in 0 .. 50: + var recvF = recv(sock, 10) + recvF.callback = + proc (future: PFuture[string]) = + echo("Read ", future.read.len, ": ", future.read.repr) + elif test == LowServer: + var sock = newAsyncSocket() + sock.bindAddr(TPort(6667)) + sock.listen() + proc onAccept(future: PFuture[PAsyncSocket]) = + let client = future.read + echo "Accepted ", client.fd.cint + var t = send(client, "test\c\L") + t.callback = + proc (future: PFuture[void]) = + echo("Send") + client.close() + + var f = accept(sock) + f.callback = onAccept + + var f = accept(sock) + f.callback = onAccept runForever() diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 2461ece1b7..43642c7b9e 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -318,22 +318,22 @@ const BufferSize*: int = 4000 ## size of a buffered socket's buffer type - TSocketImpl = object ## socket type - fd: TSocketHandle - case isBuffered: bool # determines whether this socket is buffered. + TSocketImpl* = object ## socket type + fd*: TSocketHandle + case isBuffered*: bool # determines whether this socket is buffered. of true: - buffer: array[0..BufferSize, char] - currPos: int # current index in buffer - bufLen: int # current length of buffer + buffer*: array[0..BufferSize, char] + currPos*: int # current index in buffer + bufLen*: int # current length of buffer of false: nil when defined(ssl): - case isSsl: bool + case isSsl*: bool of true: - sslHandle: PSSL - sslContext: PSSLContext - sslNoHandshake: bool # True if needs handshake. - sslHasPeekChar: bool - sslPeekChar: char + sslHandle*: PSSL + sslContext*: PSSLContext + sslNoHandshake*: bool # True if needs handshake. + sslHasPeekChar*: bool + sslPeekChar*: char of false: nil PSocket* = ref TSocketImpl @@ -519,9 +519,9 @@ proc listen*(socket: PSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} = proc bindAddr*(socket: PSocket, port = TPort(0), address = "") {. tags: [FReadIO].} = - ## Binds an address/port number to a socket. - ## Use address string in dotted decimal form like "a.b.c.d" - ## or leave "" for any address. + ## Binds ``address``:``port`` to the socket. + ## + ## If ``address`` is "" then ADDR_ANY will be bound. if address == "": var name: TSockaddr_in diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index 7e62702476..bd722842f2 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -21,7 +21,6 @@ proc launchSwarm(port: TPort) {.async.} = for i in 0 ..