diff options
author | Ruslan Mustakov <r.mustakov@gmail.com> | 2017-01-30 13:18:32 +0700 |
---|---|---|
committer | Ruslan Mustakov <r.mustakov@gmail.com> | 2017-02-01 18:18:44 +0700 |
commit | fb8168d338cedd04bad6876538ffa02fd975568b (patch) | |
tree | 303aeaa2da61613d1437f64a197b5c5f1dac7bc0 /lib | |
parent | c57fcf42df4206229de10c8ed0463fe94517bd4b (diff) | |
download | Nim-fb8168d338cedd04bad6876538ffa02fd975568b.tar.gz |
Fix Windows accept() to fail future instead of raising
Resolves: #5279
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/asyncdispatch.nim | 43 | ||||
-rw-r--r-- | lib/pure/nativesockets.nim | 3 | ||||
-rw-r--r-- | lib/pure/net.nim | 25 | ||||
-rw-r--r-- | lib/upcoming/asyncdispatch.nim | 43 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 8 |
5 files changed, 78 insertions, 44 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 8db7eba25..107e26c0c 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -753,26 +753,6 @@ when defined(windows) or defined(nimdoc): let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16) let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16) - template completeAccept() {.dirty.} = - var listenSock = socket - let setoptRet = setsockopt(clientSock, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, addr listenSock, - sizeof(listenSock).SockLen) - if setoptRet != 0: raiseOSError(osLastError()) - - var localSockaddr, remoteSockaddr: ptr SockAddr - var localLen, remoteLen: int32 - getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength, - dwLocalAddressLength, dwRemoteAddressLength, - addr localSockaddr, addr localLen, - addr remoteSockaddr, addr remoteLen) - register(clientSock.AsyncFD) - # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186 - retFuture.complete( - (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr), - client: clientSock.AsyncFD) - ) - template failAccept(errcode) = if flags.isDisconnectionError(errcode): var newAcceptFut = acceptAddr(socket, flags) @@ -785,6 +765,29 @@ when defined(windows) or defined(nimdoc): else: retFuture.fail(newException(OSError, osErrorMsg(errcode))) + template completeAccept() {.dirty.} = + var listenSock = socket + let setoptRet = setsockopt(clientSock, SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, addr listenSock, + sizeof(listenSock).SockLen) + if setoptRet != 0: + let errcode = osLastError() + checkCloseError clientSock.closeSocket() + failAccept(errcode) + else: + var localSockaddr, remoteSockaddr: ptr SockAddr + var localLen, remoteLen: int32 + getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength, + dwLocalAddressLength, dwRemoteAddressLength, + addr localSockaddr, addr localLen, + addr remoteSockaddr, addr remoteLen) + register(clientSock.AsyncFD) + # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186 + retFuture.complete( + (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr), + client: clientSock.AsyncFD) + ) + var ol = PCustomOverlapped() GC_ref(ol) ol.data = CompletionData(fd: socket, cb: diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 5f10a7b4c..d51dbd475 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -22,11 +22,12 @@ const useWinVersion = defined(Windows) or defined(nimdoc) when useWinVersion: import winlean export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET, + WSANOTINITIALISED, WSAENOTSOCK, WSAEINPROGRESS, WSAEINTR, WSAEDISCON, ERROR_NETNAME_DELETED else: import posix export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL, - EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET + EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET, EBADF export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 7f6783358..3699835c2 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -191,6 +191,31 @@ proc isDisconnectionError*(flags: set[SocketFlag], SocketFlag.SafeDisconn in flags and lastError.int32 in {ECONNRESET, EPIPE, ENETRESET} +proc checkCloseError*(ret: cint) = + ## Asserts that the return value of close() or closeSocket() syscall + ## does not indicate a programming error (such as invalid descriptor). + ## This must only be used when an error has already occurred and + ## you are performing a cleanup. + ## Otherwise, error handling must be performed as usual. + ## + ## This procedure must be called right after perfoming the syscall. Example: + ## + ## .. code-block:: nim + ## + ## let ret = someSysCall() + ## if ret != 0: + ## let errcode = osLastError() + ## checkCloseError sock.closeSocket() + ## raise newException(OSError, osErrorMsg(errcode)) + + if ret != 0: + let errcode = osLastError() + when useWinVersion: + doAssert(errcode.int32 notin {WSANOTINITIALISED, WSAENOTSOCK, + WSAEINPROGRESS, WSAEINTR, WSAEWOULDBLOCK}) + else: + doAssert(errcode.int32 notin {EBADF}) + proc toOSFlags*(socketFlags: set[SocketFlag]): cint = ## Converts the flags into the underlying OS representation. for f in socketFlags: diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim index 1dfd0122a..1fef7182d 100644 --- a/lib/upcoming/asyncdispatch.nim +++ b/lib/upcoming/asyncdispatch.nim @@ -738,26 +738,6 @@ when defined(windows) or defined(nimdoc): let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16) let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16) - template completeAccept() {.dirty.} = - var listenSock = socket - let setoptRet = setsockopt(clientSock, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, addr listenSock, - sizeof(listenSock).SockLen) - if setoptRet != 0: raiseOSError(osLastError()) - - var localSockaddr, remoteSockaddr: ptr SockAddr - var localLen, remoteLen: int32 - getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength, - dwLocalAddressLength, dwRemoteAddressLength, - addr localSockaddr, addr localLen, - addr remoteSockaddr, addr remoteLen) - register(clientSock.AsyncFD) - # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186 - retFuture.complete( - (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr), - client: clientSock.AsyncFD) - ) - template failAccept(errcode) = if flags.isDisconnectionError(errcode): var newAcceptFut = acceptAddr(socket, flags) @@ -770,6 +750,29 @@ when defined(windows) or defined(nimdoc): else: retFuture.fail(newException(OSError, osErrorMsg(errcode))) + template completeAccept() {.dirty.} = + var listenSock = socket + let setoptRet = setsockopt(clientSock, SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, addr listenSock, + sizeof(listenSock).SockLen) + if setoptRet != 0: + let errcode = osLastError() + checkCloseError clientSock.closeSocket() + failAccept(errcode) + else: + var localSockaddr, remoteSockaddr: ptr SockAddr + var localLen, remoteLen: int32 + getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength, + dwLocalAddressLength, dwRemoteAddressLength, + addr localSockaddr, addr localLen, + addr remoteSockaddr, addr remoteLen) + register(clientSock.AsyncFD) + # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186 + retFuture.complete( + (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr), + client: clientSock.AsyncFD) + ) + var ol = PCustomOverlapped() GC_ref(ol) ol.data = CompletionData(fd: socket, cb: diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 367fa8b81..02821b792 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -419,9 +419,6 @@ const ws2dll = "Ws2_32.dll" - WSAEWOULDBLOCK* = 10035 - WSAEINPROGRESS* = 10036 - proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.} type @@ -760,6 +757,11 @@ const WSAEDISCON* = 10101 WSAENETRESET* = 10052 WSAETIMEDOUT* = 10060 + WSANOTINITIALISED* = 10093 + WSAENOTSOCK* = 10038 + WSAEINPROGRESS* = 10036 + WSAEINTR* = 10004 + WSAEWOULDBLOCK* = 10035 ERROR_NETNAME_DELETED* = 64 STATUS_PENDING* = 0x103 |