Resolve bugs based on unreliable bytesReceived value.

This commit is contained in:
cheatfate 2016-05-12 21:11:42 +03:00
commit 6fa6fdeb34
2 changed files with 21 additions and 53 deletions

View file

@ -659,34 +659,14 @@ when defined(windows) or defined(nimdoc):
retFuture.complete("") retFuture.complete("")
else: else:
retFuture.fail(newException(OSError, osErrorMsg(err))) retFuture.fail(newException(OSError, osErrorMsg(err)))
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0': elif ret == 0:
# We have to ensure that the buffer is empty because WSARecv will tell if bytesReceived != 0:
# us immediately when it was disconnected, even when there is still var data = newString(bytesReceived)
# data in the buffer. copyMem(addr data[0], addr dataBuf.buf[0], bytesReceived)
# We want to give the user as much data as we can. So we only return retFuture.complete($data)
# the empty string (which signals a disconnection) when there is else:
# nothing left to read. if hasOverlappedIoCompleted(cast[POVERLAPPED](ol)):
retFuture.complete("") retFuture.complete("")
# TODO: "For message-oriented sockets, where a zero byte message is often
# allowable, a failure with an error code of WSAEDISCON is used to
# indicate graceful closure."
# ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
else:
# Request to read completed immediately.
# From my tests bytesReceived isn't reliable.
let realSize =
if bytesReceived == 0:
size
else:
bytesReceived
var data = newString(realSize)
assert realSize <= size
copyMem(addr data[0], addr dataBuf.buf[0], realSize)
#dealloc dataBuf.buf
retFuture.complete($data)
# We don't deallocate ``ol`` here because even though this completed
# immediately poll will still be notified about its completion and it will
# free ``ol``.
return retFuture return retFuture
proc recvInto*(socket: AsyncFD, buf: cstring, size: int, proc recvInto*(socket: AsyncFD, buf: cstring, size: int,
@ -749,31 +729,12 @@ when defined(windows) or defined(nimdoc):
retFuture.complete(0) retFuture.complete(0)
else: else:
retFuture.fail(newException(OSError, osErrorMsg(err))) retFuture.fail(newException(OSError, osErrorMsg(err)))
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0': elif ret == 0:
# We have to ensure that the buffer is empty because WSARecv will tell if bytesReceived != 0:
# us immediately when it was disconnected, even when there is still retFuture.complete(bytesReceived)
# data in the buffer. else:
# We want to give the user as much data as we can. So we only return if hasOverlappedIoCompleted(cast[POVERLAPPED](ol)):
# the empty string (which signals a disconnection) when there is retFuture.complete(bytesReceived)
# nothing left to read.
retFuture.complete(0)
# TODO: "For message-oriented sockets, where a zero byte message is often
# allowable, a failure with an error code of WSAEDISCON is used to
# indicate graceful closure."
# ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
else:
# Request to read completed immediately.
# From my tests bytesReceived isn't reliable.
let realSize =
if bytesReceived == 0:
size
else:
bytesReceived
assert realSize <= size
retFuture.complete(realSize)
# We don't deallocate ``ol`` here because even though this completed
# immediately poll will still be notified about its completion and it will
# free ``ol``.
return retFuture return retFuture
proc send*(socket: AsyncFD, data: string, proc send*(socket: AsyncFD, data: string,

View file

@ -759,6 +759,7 @@ const
WSAENETRESET* = 10052 WSAENETRESET* = 10052
WSAETIMEDOUT* = 10060 WSAETIMEDOUT* = 10060
ERROR_NETNAME_DELETED* = 64 ERROR_NETNAME_DELETED* = 64
STATUS_PENDING* = 0x103
proc createIoCompletionPort*(FileHandle: Handle, ExistingCompletionPort: Handle, proc createIoCompletionPort*(FileHandle: Handle, ExistingCompletionPort: Handle,
CompletionKey: ULONG_PTR, CompletionKey: ULONG_PTR,
@ -775,6 +776,12 @@ proc getOverlappedResult*(hFile: Handle, lpOverlapped: POVERLAPPED,
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{. lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".} stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
# this is copy of HasOverlappedIoCompleted() macro from <winbase.h>
# because we have declared own OVERLAPPED structure with member names not
# compatible with original names.
template hasOverlappedIoCompleted*(lpOverlapped): bool =
(cast[uint](lpOverlapped.internal) != STATUS_PENDING)
const const
IOC_OUT* = 0x40000000 IOC_OUT* = 0x40000000
IOC_IN* = 0x80000000 IOC_IN* = 0x80000000