parent
c57fcf42df
commit
fb8168d338
6 changed files with 107 additions and 44 deletions
|
|
@ -753,26 +753,6 @@ when defined(windows) or defined(nimdoc):
|
||||||
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
let dwRemoteAddressLength = 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) =
|
template failAccept(errcode) =
|
||||||
if flags.isDisconnectionError(errcode):
|
if flags.isDisconnectionError(errcode):
|
||||||
var newAcceptFut = acceptAddr(socket, flags)
|
var newAcceptFut = acceptAddr(socket, flags)
|
||||||
|
|
@ -785,6 +765,29 @@ when defined(windows) or defined(nimdoc):
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
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()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = CompletionData(fd: socket, cb:
|
ol.data = CompletionData(fd: socket, cb:
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,12 @@ const useWinVersion = defined(Windows) or defined(nimdoc)
|
||||||
when useWinVersion:
|
when useWinVersion:
|
||||||
import winlean
|
import winlean
|
||||||
export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
|
export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
|
||||||
|
WSANOTINITIALISED, WSAENOTSOCK, WSAEINPROGRESS, WSAEINTR,
|
||||||
WSAEDISCON, ERROR_NETNAME_DELETED
|
WSAEDISCON, ERROR_NETNAME_DELETED
|
||||||
else:
|
else:
|
||||||
import posix
|
import posix
|
||||||
export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
|
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 Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length
|
||||||
|
|
||||||
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
|
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,31 @@ proc isDisconnectionError*(flags: set[SocketFlag],
|
||||||
SocketFlag.SafeDisconn in flags and
|
SocketFlag.SafeDisconn in flags and
|
||||||
lastError.int32 in {ECONNRESET, EPIPE, ENETRESET}
|
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 =
|
proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
|
||||||
## Converts the flags into the underlying OS representation.
|
## Converts the flags into the underlying OS representation.
|
||||||
for f in socketFlags:
|
for f in socketFlags:
|
||||||
|
|
|
||||||
|
|
@ -738,26 +738,6 @@ when defined(windows) or defined(nimdoc):
|
||||||
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
let dwRemoteAddressLength = 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) =
|
template failAccept(errcode) =
|
||||||
if flags.isDisconnectionError(errcode):
|
if flags.isDisconnectionError(errcode):
|
||||||
var newAcceptFut = acceptAddr(socket, flags)
|
var newAcceptFut = acceptAddr(socket, flags)
|
||||||
|
|
@ -770,6 +750,29 @@ when defined(windows) or defined(nimdoc):
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
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()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = CompletionData(fd: socket, cb:
|
ol.data = CompletionData(fd: socket, cb:
|
||||||
|
|
|
||||||
|
|
@ -419,9 +419,6 @@ const
|
||||||
|
|
||||||
ws2dll = "Ws2_32.dll"
|
ws2dll = "Ws2_32.dll"
|
||||||
|
|
||||||
WSAEWOULDBLOCK* = 10035
|
|
||||||
WSAEINPROGRESS* = 10036
|
|
||||||
|
|
||||||
proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -760,6 +757,11 @@ const
|
||||||
WSAEDISCON* = 10101
|
WSAEDISCON* = 10101
|
||||||
WSAENETRESET* = 10052
|
WSAENETRESET* = 10052
|
||||||
WSAETIMEDOUT* = 10060
|
WSAETIMEDOUT* = 10060
|
||||||
|
WSANOTINITIALISED* = 10093
|
||||||
|
WSAENOTSOCK* = 10038
|
||||||
|
WSAEINPROGRESS* = 10036
|
||||||
|
WSAEINTR* = 10004
|
||||||
|
WSAEWOULDBLOCK* = 10035
|
||||||
ERROR_NETNAME_DELETED* = 64
|
ERROR_NETNAME_DELETED* = 64
|
||||||
STATUS_PENDING* = 0x103
|
STATUS_PENDING* = 0x103
|
||||||
|
|
||||||
|
|
|
||||||
29
tests/async/tacceptcloserace.nim
Normal file
29
tests/async/tacceptcloserace.nim
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import asyncdispatch, net, os, nativesockets
|
||||||
|
|
||||||
|
# bug: https://github.com/nim-lang/Nim/issues/5279
|
||||||
|
|
||||||
|
proc setupServerSocket(hostname: string, port: Port): AsyncFD =
|
||||||
|
let fd = newNativeSocket()
|
||||||
|
setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
|
||||||
|
var aiList = getAddrInfo(hostname, port)
|
||||||
|
if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
|
||||||
|
freeAddrInfo(aiList)
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
freeAddrInfo(aiList)
|
||||||
|
if listen(fd) != 0:
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
setBlocking(fd, false)
|
||||||
|
result = fd.AsyncFD
|
||||||
|
register(result)
|
||||||
|
|
||||||
|
const port = Port(5614)
|
||||||
|
for i in 0..100:
|
||||||
|
let serverFd = setupServerSocket("localhost", port)
|
||||||
|
serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
|
||||||
|
if not fut.failed:
|
||||||
|
fut.read().closeSocket()
|
||||||
|
|
||||||
|
var fd = newAsyncNativeSocket()
|
||||||
|
waitFor fd.connect("localhost", port)
|
||||||
|
serverFd.closeSocket()
|
||||||
|
fd.closeSocket()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue