From 3612aca5fe0dfdc703115dfc27af4fef03acd2c9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 13 Apr 2014 14:18:47 +0100 Subject: Implemented buffering for asynchronous sockets. --- lib/pure/asyncdispatch.nim | 2 +- lib/pure/asynchttpserver.nim | 2 +- lib/pure/asyncnet.nim | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index a8802dec3..5e638dc74 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -381,8 +381,8 @@ when defined(windows) or defined(nimdoc): let err = osLastError() if err.int32 != ERROR_IO_PENDING: dealloc dataBuf.buf - retFuture.fail(newException(EOS, osErrorMsg(err))) dealloc(ol) + retFuture.fail(newException(EOS, osErrorMsg(err))) elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0': # We have to ensure that the buffer is empty because WSARecv will tell # us immediatelly when it was disconnected, even when there is still diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index f1aa1a09d..2ebd7036d 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -134,7 +134,7 @@ proc processClient(client: PAsyncSocket, address: string, return case reqMethod.normalize - of "get": + of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch": await callback(request) else: request.respond(Http400, "Invalid request method. Got: " & reqMethod) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 7cf2ad134..b1abf627b 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -80,14 +80,48 @@ proc connect*(socket: PAsyncSocket, address: string, port: TPort, ## or an error occurs. result = connect(socket.fd.TAsyncFD, address, port, af) +proc readIntoBuf(socket: PAsyncSocket, flags: int): PFuture[int] {.async.} = + var data = await recv(socket.fd.TAsyncFD, BufferSize, flags) + if data.len != 0: + copyMem(addr socket.buffer[0], addr data[0], data.len) + socket.bufLen = data.len + socket.currPos = 0 + result = data.len + proc recv*(socket: PAsyncSocket, size: int, - flags: int = 0): PFuture[string] = + flags: int = 0): PFuture[string] {.async.} = ## Reads ``size`` bytes from ``socket``. Returned future will complete once ## all of the requested data is read. If socket is disconnected during the ## 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.TAsyncFD, size, flags) + if socket.isBuffered: + result = newString(size) + + template returnNow(readBytes: int) = + result.setLen(readBytes) + # Only increase buffer position when not peeking. + if (flags and MSG_PEEK) != MSG_PEEK: + socket.currPos.inc(readBytes) + return + + if socket.bufLen == 0: + let res = await socket.readIntoBuf(flags and (not MSG_PEEK)) + if res == 0: returnNow(0) + + var read = 0 + while read < size: + if socket.currPos >= socket.bufLen: + let res = await socket.readIntoBuf(flags and (not MSG_PEEK)) + if res == 0: returnNow(read) + + let chunk = min(socket.bufLen-socket.currPos, size-read) + copyMem(addr(result[read]), addr(socket.buffer[socket.currPos+read]), chunk) + read.inc(chunk) + + returnNow(read) + else: + result = await 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 -- cgit 1.4.1-2-gfad0