Fix cast[pointer] issues on nim-devel. (#381)
* Fix cast[pointer] issues on nim-devel. * More cast[T] fixes. * Fix compilation error. * Add oserrno.nim Further fixes for Windows and Linux. * MacOS fixes. * More Windows fixes and attempt to fix 1.2, 1.4 branches. * Implicitly import/export oserrno. * Replace oserrno with osdefs. * Return back oserrno. * epoll to oserrno. * datagram/stream to oserrno. * common to oserrno. * test to oserrno.
This commit is contained in:
parent
e05d2f8e96
commit
3118f8c1b2
|
@ -152,14 +152,15 @@ elif defined(macosx) or defined(freebsd) or defined(netbsd) or
|
|||
defined(openbsd) or defined(dragonfly) or defined(macos) or
|
||||
defined(linux) or defined(android) or defined(solaris):
|
||||
import "."/selectors2
|
||||
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
|
||||
MSG_NOSIGNAL,
|
||||
import "."/oserrno
|
||||
from posix import MSG_PEEK, MSG_NOSIGNAL,
|
||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
|
||||
SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
|
||||
SIGPIPE, SIGALRM, SIGTERM, SIGPIPE
|
||||
export SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
|
||||
SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
|
||||
SIGPIPE, SIGALRM, SIGTERM, SIGPIPE
|
||||
export oserrno
|
||||
|
||||
type
|
||||
CallbackFunc* = proc (arg: pointer) {.gcsafe, raises: [Defect].}
|
||||
|
@ -282,6 +283,12 @@ proc raiseOsDefect*(error: OSErrorCode, msg = "") {.noreturn, noinline.} =
|
|||
raise (ref Defect)(msg: msg & "\n[" & $int(error) & "] " & osErrorMsg(error) &
|
||||
"\n" & getStackTrace())
|
||||
|
||||
func toPointer(error: OSErrorCode): pointer =
|
||||
when sizeof(int) == 8:
|
||||
cast[pointer](uint64(uint32(error)))
|
||||
else:
|
||||
cast[pointer](uint32(error))
|
||||
|
||||
func toException*(v: OSErrorCode): ref OSError = newOSError(v)
|
||||
# This helper will allow to use `tryGet()` and raise OSError for
|
||||
# Result[T, OSErrorCode] values.
|
||||
|
@ -518,27 +525,30 @@ when defined(windows):
|
|||
## Closes a socket and ensures that it is unregistered.
|
||||
let loop = getThreadDispatcher()
|
||||
loop.handles.excl(fd)
|
||||
let param =
|
||||
if closeFd(SocketHandle(fd)) == 0:
|
||||
OSErrorCode(0)
|
||||
else:
|
||||
osLastError()
|
||||
if not isNil(aftercb):
|
||||
var acb = AsyncCallback(function: aftercb, udata: cast[pointer](param))
|
||||
loop.callbacks.addLast(acb)
|
||||
let
|
||||
param = toPointer(
|
||||
if closeFd(SocketHandle(fd)) == 0:
|
||||
OSErrorCode(0)
|
||||
else:
|
||||
osLastError()
|
||||
)
|
||||
if not(isNil(aftercb)):
|
||||
loop.callbacks.addLast(AsyncCallback(function: aftercb, udata: param))
|
||||
|
||||
proc closeHandle*(fd: AsyncFD, aftercb: CallbackFunc = nil) =
|
||||
## Closes a (pipe/file) handle and ensures that it is unregistered.
|
||||
let loop = getThreadDispatcher()
|
||||
loop.handles.excl(fd)
|
||||
let param =
|
||||
if closeFd(HANDLE(fd)) == 0:
|
||||
OSErrorCode(0)
|
||||
else:
|
||||
osLastError()
|
||||
if not isNil(aftercb):
|
||||
var acb = AsyncCallback(function: aftercb, udata: cast[pointer](param))
|
||||
loop.callbacks.addLast(acb)
|
||||
let
|
||||
param = toPointer(
|
||||
if closeFd(HANDLE(fd)) == 0:
|
||||
OSErrorCode(0)
|
||||
else:
|
||||
osLastError()
|
||||
)
|
||||
|
||||
if not(isNil(aftercb)):
|
||||
loop.callbacks.addLast(AsyncCallback(function: aftercb, udata: param))
|
||||
|
||||
proc contains*(disp: PDispatcher, fd: AsyncFD): bool =
|
||||
## Returns ``true`` if ``fd`` is registered in thread's dispatcher.
|
||||
|
@ -720,21 +730,22 @@ elif defined(macosx) or defined(freebsd) or defined(netbsd) or
|
|||
let loop = getThreadDispatcher()
|
||||
|
||||
proc continuation(udata: pointer) =
|
||||
let param =
|
||||
if SocketHandle(fd) in loop.selector:
|
||||
let ures = unregister2(fd)
|
||||
if ures.isErr():
|
||||
discard closeFd(cint(fd))
|
||||
ures.error()
|
||||
else:
|
||||
if closeFd(cint(fd)) != 0:
|
||||
osLastError()
|
||||
let
|
||||
param = toPointer(
|
||||
if SocketHandle(fd) in loop.selector:
|
||||
let ures = unregister2(fd)
|
||||
if ures.isErr():
|
||||
discard closeFd(cint(fd))
|
||||
ures.error()
|
||||
else:
|
||||
OSErrorCode(0)
|
||||
else:
|
||||
OSErrorCode(osdefs.EBADF)
|
||||
if not isNil(aftercb):
|
||||
aftercb(cast[pointer](param))
|
||||
if closeFd(cint(fd)) != 0:
|
||||
osLastError()
|
||||
else:
|
||||
OSErrorCode(0)
|
||||
else:
|
||||
OSErrorCode(osdefs.EBADF)
|
||||
)
|
||||
if not(isNil(aftercb)): aftercb(param)
|
||||
|
||||
withData(loop.selector, cint(fd), adata) do:
|
||||
# We are scheduling reader and writer callbacks to be called
|
||||
|
|
|
@ -42,7 +42,7 @@ proc getVirtualId[T](s: Selector[T]): SelectResult[int32] =
|
|||
ok(s.virtualHoles.popLast())
|
||||
else:
|
||||
if s.virtualId == low(int32):
|
||||
err(OSErrorCode(EMFILE))
|
||||
err(oserrno.EMFILE)
|
||||
else:
|
||||
dec(s.virtualId)
|
||||
ok(s.virtualId)
|
||||
|
@ -139,7 +139,7 @@ proc trigger2*(event: SelectEvent): SelectResult[void] =
|
|||
if res == -1:
|
||||
err(osLastError())
|
||||
elif res != sizeof(uint64):
|
||||
err(OSErrorCode(osdefs.EINVAL))
|
||||
err(oserrno.EINVAL)
|
||||
else:
|
||||
ok()
|
||||
|
||||
|
@ -521,11 +521,11 @@ proc prepareKey[T](s: Selector[T], event: EpollEvent): Opt[ReadyKey] =
|
|||
|
||||
if (event.events and EPOLLERR) != 0:
|
||||
rkey.events.incl(Event.Error)
|
||||
rkey.errorCode = OSErrorCode(ECONNRESET)
|
||||
rkey.errorCode = oserrno.ECONNRESET
|
||||
|
||||
if (event.events and EPOLLHUP) != 0 or (event.events and EPOLLRDHUP) != 0:
|
||||
rkey.events.incl(Event.Error)
|
||||
rkey.errorCode = OSErrorCode(ECONNRESET)
|
||||
rkey.errorCode = oserrno.ECONNRESET
|
||||
|
||||
if (event.events and EPOLLOUT) != 0:
|
||||
rkey.events.incl(Event.Write)
|
||||
|
@ -580,7 +580,8 @@ proc prepareKey[T](s: Selector[T], event: EpollEvent): Opt[ReadyKey] =
|
|||
let res = handleEintr(osdefs.read(fdi32, addr data, sizeof(uint64)))
|
||||
if res != sizeof(uint64):
|
||||
let errorCode = osLastError()
|
||||
if errorCode == EAGAIN:
|
||||
case errorCode
|
||||
of oserrno.EAGAIN:
|
||||
return Opt.none(ReadyKey)
|
||||
else:
|
||||
rkey.events.incl({Event.User, Event.Error})
|
||||
|
|
|
@ -58,6 +58,12 @@ proc toString(key: int32|cint|SocketHandle|int): string =
|
|||
else:
|
||||
Base10.toString(uint32(fdi32))
|
||||
|
||||
proc toPointer(data: int32): pointer =
|
||||
when sizeof(int) == 8:
|
||||
cast[pointer](uint64(uint32(data)))
|
||||
else:
|
||||
cast[pointer](uint32(data))
|
||||
|
||||
template addKey[T](s: Selector[T], key: int32, skey: SelectorKey[T]) =
|
||||
if s.fds.hasKeyOrPut(key, skey):
|
||||
raiseAssert "Descriptor [" & key.toString() &
|
||||
|
@ -154,7 +160,7 @@ proc trigger2*(event: SelectEvent): SelectResult[void] =
|
|||
if res == -1:
|
||||
err(osLastError())
|
||||
elif res != sizeof(uint64):
|
||||
err(OSErrorCode(osdefs.EINVAL))
|
||||
err(oserrno.EINVAL)
|
||||
else:
|
||||
ok()
|
||||
|
||||
|
@ -310,7 +316,7 @@ proc registerSignal*[T](s: Selector[T], signal: int,
|
|||
# To be compatible with linux semantic we need to "eat" signals
|
||||
signal(cint(signal), SIG_IGN)
|
||||
changes.modifyKQueue(0, uint(signal), EVFILT_SIGNAL, EV_ADD, 0, 0,
|
||||
cast[pointer](uint32(fdi32)))
|
||||
fdi32.toPointer())
|
||||
if handleEintr(kevent(s.kqFd, addr(changes[0]), cint(1), nil, 0, nil)) == -1:
|
||||
let errorCode = osLastError()
|
||||
s.freeKey(fdi32)
|
||||
|
@ -341,7 +347,7 @@ proc registerProcess*[T](s: Selector[T], pid: int,
|
|||
s.addKey(fdi32, selectorKey)
|
||||
|
||||
changes.modifyKQueue(0, uint(uint32(pid)), EVFILT_PROC, flags, NOTE_EXIT,
|
||||
0, cast[pointer](uint32(fdi32)))
|
||||
0, fdi32.toPointer())
|
||||
if handleEintr(kevent(s.kqFd, addr(changes[0]), cint(1), nil, 0, nil)) == -1:
|
||||
s.freeKey(fdi32)
|
||||
return err(osLastError())
|
||||
|
@ -490,14 +496,14 @@ proc prepareKey[T](s: Selector[T], event: KEvent): Opt[ReadyKey] =
|
|||
of EVFILT_READ:
|
||||
if (event.flags and EV_EOF) != 0:
|
||||
rkey.events.incl(Event.Error)
|
||||
rkey.errorCode = OSErrorCode(ECONNRESET)
|
||||
rkey.errorCode = oserrno.ECONNRESET
|
||||
|
||||
if Event.User in pkey.events:
|
||||
var data: uint64 = 0
|
||||
if handleEintr(osdefs.read(cint(event.ident), addr data,
|
||||
sizeof(uint64))) != sizeof(uint64):
|
||||
let errorCode = osLastError()
|
||||
if errorCode == EAGAIN:
|
||||
if errorCode == oserrno.EAGAIN:
|
||||
# Someone already consumed event data
|
||||
return Opt.none(ReadyKey)
|
||||
else:
|
||||
|
@ -510,7 +516,7 @@ proc prepareKey[T](s: Selector[T], event: KEvent): Opt[ReadyKey] =
|
|||
of EVFILT_WRITE:
|
||||
if (event.flags and EV_EOF) != 0:
|
||||
rkey.events.incl(Event.Error)
|
||||
rkey.errorCode = OSErrorCode(ECONNRESET)
|
||||
rkey.errorCode = oserrno.ECONNRESET
|
||||
|
||||
rkey.events.incl(Event.Write)
|
||||
|
||||
|
@ -577,7 +583,7 @@ proc selectInto2*[T](s: Selector[T], timeout: int,
|
|||
maxEventsCount, ptrTimeout)
|
||||
if res < 0:
|
||||
let errorCode = osLastError()
|
||||
if errorCode == EINTR:
|
||||
if errorCode == oserrno.EINTR:
|
||||
continue
|
||||
return err(errorCode)
|
||||
else:
|
||||
|
|
|
@ -6,18 +6,10 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
from std/os import osLastError, osErrorMsg, OSErrorCode, raiseOSError,
|
||||
newOSError
|
||||
export osLastError, osErrorMsg, OSError, OSErrorCode, raiseOSError, newOSError
|
||||
import oserrno
|
||||
export oserrno
|
||||
|
||||
when defined(windows):
|
||||
from std/winlean import SocketHandle, SockLen, SockAddr, InAddr,
|
||||
In6_addr, Sockaddr_in, Sockaddr_in6, Sockaddr_storage,
|
||||
AddrInfo
|
||||
export SocketHandle, SockLen, SockAddr, InAddr,
|
||||
In6_addr, Sockaddr_in, Sockaddr_in6, Sockaddr_storage, AddrInfo
|
||||
|
||||
# Prerequisites for constants
|
||||
template WSAIORW*(x, y): untyped = (IOC_INOUT or x or y)
|
||||
template WSAIOW*(x, y): untyped =
|
||||
|
@ -25,6 +17,49 @@ when defined(windows):
|
|||
((clong(sizeof(int32)) and clong(IOCPARM_MASK)) shl 16) or (x shl 8) or y
|
||||
|
||||
type
|
||||
Sockaddr_storage* {.final, pure.} = object
|
||||
ss_family*: uint16
|
||||
ss_pad1: array[6, byte]
|
||||
ss_align: int64
|
||||
ss_pad2: array[112, byte]
|
||||
|
||||
InAddr* {.final, pure, union.} = object
|
||||
s_addr*: uint32
|
||||
|
||||
In6Addr* {.final, pure, union.} = object
|
||||
s_addr*: array[16, byte]
|
||||
|
||||
Sockaddr_in* {.final, pure.} = object
|
||||
sin_family*: uint16
|
||||
sin_port*: uint16
|
||||
sin_addr*: InAddr
|
||||
sin_zero*: array[0..7, char]
|
||||
|
||||
Sockaddr_in6* {.final, pure.} = object
|
||||
sin6_family*: uint16
|
||||
sin6_port*: uint16
|
||||
sin6_flowinfo*: uint32
|
||||
sin6_addr*: In6Addr
|
||||
sin6_scope_id*: uint32
|
||||
|
||||
SockLen* = cuint
|
||||
|
||||
SockAddr* {.final, pure.} = object
|
||||
sa_family*: uint16
|
||||
sa_data*: array[14, char]
|
||||
|
||||
AddrInfo* {.final, pure.} = object
|
||||
ai_flags*: cint ## Input flags.
|
||||
ai_family*: cint ## Address family of socket.
|
||||
ai_socktype*: cint ## Socket type.
|
||||
ai_protocol*: cint ## Protocol of socket.
|
||||
ai_addrlen*: csize_t ## Length of socket address.
|
||||
ai_canonname*: pointer ## Canonical name of service location.
|
||||
ai_addr*: ptr SockAddr ## Socket address of socket.
|
||||
ai_next*: ptr AddrInfo ## Pointer to next in list.
|
||||
|
||||
SocketHandle* = distinct int
|
||||
|
||||
HANDLE* = distinct uint
|
||||
GUID* {.final, pure.} = object
|
||||
D1*: uint32
|
||||
|
@ -104,36 +139,6 @@ when defined(windows):
|
|||
PIPE_UNLIMITED_INSTANCES* = 255'u32
|
||||
DEFAULT_PIPE_SIZE* = 65536'u32
|
||||
|
||||
ERROR_SUCCESS* = 0
|
||||
ERROR_FILE_NOT_FOUND* = 2
|
||||
ERROR_TOO_MANY_OPEN_FILES* = 4
|
||||
ERROR_ACCESS_DENIED* = 5
|
||||
ERROR_BROKEN_PIPE* = 109
|
||||
ERROR_BUFFER_OVERFLOW* = 111
|
||||
ERROR_PIPE_BUSY* = 231
|
||||
ERROR_NO_DATA* = 232
|
||||
ERROR_PIPE_NOT_CONNECTED* = 233
|
||||
ERROR_PIPE_CONNECTED* = 535
|
||||
ERROR_OPERATION_ABORTED* = 995
|
||||
ERROR_IO_PENDING* = 997
|
||||
ERROR_CONNECTION_REFUSED* = 1225
|
||||
ERROR_CONNECTION_ABORTED* = 1236
|
||||
|
||||
WSAEMFILE* = 10024
|
||||
WSAENETDOWN* = 10050
|
||||
WSAENETRESET* = 10052
|
||||
WSAECONNABORTED* = 10053
|
||||
WSAECONNRESET* = 10054
|
||||
WSAENOBUFS* = 10055
|
||||
WSAETIMEDOUT* = 10060
|
||||
WSAEADDRINUSE* = 10048
|
||||
WSAEDISCON* = 10101
|
||||
WSANOTINITIALISED* = 10093
|
||||
WSAENOTSOCK* = 10038
|
||||
WSAEINPROGRESS* = 10036
|
||||
WSAEINTR* = 10004
|
||||
WSAEWOULDBLOCK* = 10035
|
||||
ERROR_NETNAME_DELETED* = 64
|
||||
STATUS_PENDING* = 0x103
|
||||
|
||||
IOCPARM_MASK* = 0x7f'u32
|
||||
|
@ -1283,8 +1288,6 @@ when defined(posix):
|
|||
INVALID_SOCKET* = SocketHandle(-1)
|
||||
INVALID_HANDLE_VALUE* = cint(-1)
|
||||
|
||||
proc `==`*(x: OSErrorCode, y: int): bool =
|
||||
int(x) == y
|
||||
proc `==`*(x: SocketHandle, y: int): bool =
|
||||
x == SocketHandle(y)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,9 +7,9 @@
|
|||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
import stew/results
|
||||
import osdefs
|
||||
import osdefs, oserrno
|
||||
|
||||
export results
|
||||
export results, osdefs, oserrno
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
|
@ -187,10 +187,10 @@ when defined(windows):
|
|||
let cleanupFlag =
|
||||
block:
|
||||
let errorCode = osLastError()
|
||||
case int(errorCode)
|
||||
of osdefs.ERROR_PIPE_CONNECTED:
|
||||
case errorCode
|
||||
of ERROR_PIPE_CONNECTED:
|
||||
false
|
||||
of osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
if DescriptorFlag.NonBlock in writeset:
|
||||
var bytesRead = 0.DWORD
|
||||
if getOverlappedResult(pipeIn, addr ovl, bytesRead, 1) == FALSE:
|
||||
|
@ -215,7 +215,7 @@ else:
|
|||
var res = 0
|
||||
while true:
|
||||
res = body
|
||||
if not((res == -1) and (osLastError() == EINTR)):
|
||||
if not((res == -1) and (osLastError() == oserrno.EINTR)):
|
||||
break
|
||||
res
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
# backwards-compatible.
|
||||
|
||||
import stew/results
|
||||
import osdefs, osutils
|
||||
export results
|
||||
import osdefs, osutils, oserrno
|
||||
export results, oserrno
|
||||
|
||||
const
|
||||
asyncEventsCount* {.intdefine.} = 64
|
||||
|
|
|
@ -12,10 +12,17 @@ when (NimMajor, NimMinor) < (1, 4):
|
|||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import std/[strutils, nativesockets, net]
|
||||
import std/[strutils]
|
||||
import stew/[base10, byteutils]
|
||||
import ".."/[asyncloop, osdefs]
|
||||
export net
|
||||
import ".."/[asyncloop, osdefs, oserrno]
|
||||
|
||||
from std/net import Domain, `==`, IpAddress, IpAddressFamily, parseIpAddress,
|
||||
SockType, Protocol, Port, `$`
|
||||
from std/nativesockets import toInt, `$`
|
||||
|
||||
export Domain, `==`, IpAddress, IpAddressFamily, parseIpAddress, SockType,
|
||||
Protocol, Port, toInt, `$`
|
||||
|
||||
|
||||
const
|
||||
DefaultStreamBufferSize* = 4096 ## Default buffer size for stream
|
||||
|
@ -600,35 +607,37 @@ proc isLiteral*[T](s: seq[T]): bool {.inline.} =
|
|||
else:
|
||||
(cast[ptr SeqHeader](s).reserved and (1 shl (sizeof(int) * 8 - 2))) != 0
|
||||
|
||||
template getTransportTooManyError*(code: int = 0): ref TransportTooManyError =
|
||||
template getTransportTooManyError*(
|
||||
code = OSErrorCode(0)
|
||||
): ref TransportTooManyError =
|
||||
let msg =
|
||||
when defined(posix):
|
||||
if code == 0:
|
||||
if code == OSErrorCode(0):
|
||||
"Too many open transports"
|
||||
elif code == EMFILE:
|
||||
elif code == oserrno.EMFILE:
|
||||
"[EMFILE] Too many open files in the process"
|
||||
elif code == ENFILE:
|
||||
elif code == oserrno.ENFILE:
|
||||
"[ENFILE] Too many open files in system"
|
||||
elif code == ENOBUFS:
|
||||
elif code == oserrno.ENOBUFS:
|
||||
"[ENOBUFS] No buffer space available"
|
||||
elif code == ENOMEM:
|
||||
elif code == oserrno.ENOMEM:
|
||||
"[ENOMEM] Not enough memory availble"
|
||||
else:
|
||||
"[" & $code & "] Too many open transports"
|
||||
"[" & $int(code) & "] Too many open transports"
|
||||
elif defined(windows):
|
||||
case code
|
||||
of 0:
|
||||
of OSErrorCode(0):
|
||||
"Too many open transports"
|
||||
of osdefs.ERROR_TOO_MANY_OPEN_FILES:
|
||||
of ERROR_TOO_MANY_OPEN_FILES:
|
||||
"[ERROR_TOO_MANY_OPEN_FILES] Too many open files"
|
||||
of osdefs.WSAENOBUFS:
|
||||
of WSAENOBUFS:
|
||||
"[WSAENOBUFS] No buffer space available"
|
||||
of osdefs.WSAEMFILE:
|
||||
of WSAEMFILE:
|
||||
"[WSAEMFILE] Too many open sockets"
|
||||
else:
|
||||
"[" & $code & "] Too many open transports"
|
||||
"[" & $int(code) & "] Too many open transports"
|
||||
else:
|
||||
"[" & $code & "] Too many open transports"
|
||||
"[" & $int(code) & "] Too many open transports"
|
||||
newException(TransportTooManyError, msg)
|
||||
|
||||
template getConnectionAbortedError*(m: string = ""): ref TransportAbortedError =
|
||||
|
@ -639,32 +648,34 @@ template getConnectionAbortedError*(m: string = ""): ref TransportAbortedError =
|
|||
"[ECONNABORTED] " & m
|
||||
newException(TransportAbortedError, msg)
|
||||
|
||||
template getConnectionAbortedError*(code: int): ref TransportAbortedError =
|
||||
template getConnectionAbortedError*(
|
||||
code: OSErrorCode
|
||||
): ref TransportAbortedError =
|
||||
let msg =
|
||||
when defined(posix):
|
||||
if code == 0:
|
||||
if code == OSErrorCode(0):
|
||||
"[ECONNABORTED] Connection has been aborted before being accepted"
|
||||
elif code == EPERM:
|
||||
elif code == oserrno.EPERM:
|
||||
"[EPERM] Firewall rules forbid connection"
|
||||
elif code == ETIMEDOUT:
|
||||
elif code == oserrno.ETIMEDOUT:
|
||||
"[ETIMEDOUT] Operation has been timed out"
|
||||
else:
|
||||
"[" & $code & "] Connection has been aborted"
|
||||
"[" & $int(code) & "] Connection has been aborted"
|
||||
elif defined(windows):
|
||||
case code
|
||||
of 0, osdefs.WSAECONNABORTED:
|
||||
of OSErrorCode(0), oserrno.WSAECONNABORTED:
|
||||
"[ECONNABORTED] Connection has been aborted before being accepted"
|
||||
of osdefs.WSAENETDOWN:
|
||||
of WSAENETDOWN:
|
||||
"[ENETDOWN] Network is down"
|
||||
of osdefs.WSAENETRESET:
|
||||
of oserrno.WSAENETRESET:
|
||||
"[ENETRESET] Network dropped connection on reset"
|
||||
of osdefs.WSAECONNRESET:
|
||||
of oserrno.WSAECONNRESET:
|
||||
"[ECONNRESET] Connection reset by peer"
|
||||
of osdefs.WSAETIMEDOUT:
|
||||
of WSAETIMEDOUT:
|
||||
"[ETIMEDOUT] Connection timed out"
|
||||
else:
|
||||
"[" & $code & "] Connection has been aborted"
|
||||
"[" & $int(code) & "] Connection has been aborted"
|
||||
else:
|
||||
"[" & $code & "] Connection has been aborted"
|
||||
"[" & $int(code) & "] Connection has been aborted"
|
||||
|
||||
newException(TransportAbortedError, msg)
|
||||
|
|
|
@ -14,7 +14,7 @@ else:
|
|||
|
||||
import std/deques
|
||||
when not(defined(windows)): import ".."/selectors2
|
||||
import ".."/[asyncloop, osdefs, handles]
|
||||
import ".."/[asyncloop, osdefs, oserrno, handles]
|
||||
import "."/common
|
||||
|
||||
type
|
||||
|
@ -139,10 +139,11 @@ when defined(windows):
|
|||
transp.state.excl(WritePending)
|
||||
let err = transp.wovl.data.errCode
|
||||
let vector = transp.queue.popFirst()
|
||||
if err == OSErrorCode(-1):
|
||||
case err
|
||||
of OSErrorCode(-1):
|
||||
if not(vector.writer.finished()):
|
||||
vector.writer.complete()
|
||||
elif int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.incl(WritePaused)
|
||||
if not(vector.writer.finished()):
|
||||
|
@ -170,13 +171,14 @@ when defined(windows):
|
|||
DWORD(0), cast[POVERLAPPED](addr transp.wovl), nil)
|
||||
if ret != 0:
|
||||
let err = osLastError()
|
||||
if int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(WritePending)
|
||||
transp.state.incl(WritePaused)
|
||||
if not(vector.writer.finished()):
|
||||
vector.writer.complete()
|
||||
elif int(err) == osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
transp.queue.addFirst(vector)
|
||||
else:
|
||||
transp.state.excl(WritePending)
|
||||
|
@ -201,14 +203,15 @@ when defined(windows):
|
|||
## Continuation
|
||||
transp.state.excl(ReadPending)
|
||||
let err = transp.rovl.data.errCode
|
||||
if err == OSErrorCode(-1):
|
||||
case err
|
||||
of OSErrorCode(-1):
|
||||
let bytesCount = transp.rovl.data.bytesCount
|
||||
if bytesCount == 0:
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
fromSAddr(addr transp.raddr, transp.ralen, raddr)
|
||||
transp.buflen = int(bytesCount)
|
||||
asyncSpawn transp.function(transp, raddr)
|
||||
elif int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt or closeSocket() call.
|
||||
transp.state.incl(ReadPaused)
|
||||
if ReadClosed in transp.state and not(transp.future.finished()):
|
||||
|
@ -237,15 +240,16 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr transp.rovl), nil)
|
||||
if ret != 0:
|
||||
let err = osLastError()
|
||||
if int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl(ReadPaused)
|
||||
elif int(err) == osdefs.WSAECONNRESET:
|
||||
of WSAECONNRESET:
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl({ReadPaused, ReadEof})
|
||||
break
|
||||
elif int(err) == osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
discard
|
||||
else:
|
||||
transp.state.excl(ReadPending)
|
||||
|
@ -419,7 +423,8 @@ else:
|
|||
asyncSpawn transp.function(transp, raddr)
|
||||
else:
|
||||
let err = osLastError()
|
||||
if int(err) == EINTR:
|
||||
case err
|
||||
of oserrno.EINTR:
|
||||
continue
|
||||
else:
|
||||
transp.buflen = 0
|
||||
|
@ -454,7 +459,8 @@ else:
|
|||
vector.writer.complete()
|
||||
else:
|
||||
let err = osLastError()
|
||||
if int(err) == EINTR:
|
||||
case err
|
||||
of oserrno.EINTR:
|
||||
continue
|
||||
else:
|
||||
if not(vector.writer.finished()):
|
||||
|
|
|
@ -838,17 +838,15 @@ elif defined(macosx) or defined(macos) or defined(bsd):
|
|||
if family == osdefs.AF_INET:
|
||||
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_netmask),
|
||||
SockLen(sizeof(Sockaddr_in)), na)
|
||||
if cint(ifaddress.host.family) == osdefs.AF_INET:
|
||||
if ifaddress.host.family == AddressFamily.IPv4:
|
||||
ifaddress.net = IpNet.init(ifaddress.host, na)
|
||||
elif family == osdefs.AF_INET6:
|
||||
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_netmask),
|
||||
SockLen(sizeof(Sockaddr_in6)), na)
|
||||
if cint(ifaddress.host.family) == osdefs.AF_INET6:
|
||||
if ifaddress.host.family == AddressFamily.IPv6:
|
||||
ifaddress.net = IpNet.init(ifaddress.host, na)
|
||||
|
||||
if ifaddress.host.family != AddressFamily.None:
|
||||
if len(res[i].addresses) == 0:
|
||||
res[i].addresses = newSeq[InterfaceAddress]()
|
||||
res[i].addresses.add(ifaddress)
|
||||
ifap = ifap.ifa_next
|
||||
|
||||
|
@ -1047,10 +1045,11 @@ elif defined(windows):
|
|||
var addresses = cast[ptr IpAdapterAddressesXp](addr buffer[0])
|
||||
gres = getAdaptersAddresses(osdefs.AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
|
||||
nil, addresses, addr size)
|
||||
if gres == ERROR_SUCCESS:
|
||||
case OSErrorCode(gres)
|
||||
of ERROR_SUCCESS:
|
||||
buffer.setLen(size)
|
||||
break
|
||||
elif gres == ERROR_BUFFER_OVERFLOW:
|
||||
of ERROR_BUFFER_OVERFLOW:
|
||||
discard
|
||||
else:
|
||||
break
|
||||
|
@ -1058,7 +1057,7 @@ elif defined(windows):
|
|||
if tries >= MaxTries:
|
||||
break
|
||||
|
||||
if gres == ERROR_SUCCESS:
|
||||
if OSErrorCode(gres) == ERROR_SUCCESS:
|
||||
var slider = cast[ptr IpAdapterAddressesXp](addr buffer[0])
|
||||
while not isNil(slider):
|
||||
var iface = NetworkInterface(
|
||||
|
|
|
@ -13,7 +13,7 @@ else:
|
|||
{.push raises: [].}
|
||||
|
||||
import std/deques
|
||||
import ".."/[asyncloop, handles, osdefs, osutils]
|
||||
import ".."/[asyncloop, handles, osdefs, osutils, oserrno]
|
||||
import common
|
||||
|
||||
type
|
||||
|
@ -322,10 +322,12 @@ when defined(windows):
|
|||
(t).wwsabuf.buf = cast[cstring](v.buf)
|
||||
(t).wwsabuf.len = cast[ULONG](v.buflen)
|
||||
|
||||
proc isConnResetError(err: OSErrorCode): bool {.inline.} =
|
||||
result = (err == OSErrorCode(osdefs.WSAECONNRESET)) or
|
||||
(err == OSErrorCode(osdefs.WSAECONNABORTED)) or
|
||||
(err == OSErrorCode(osdefs.ERROR_PIPE_NOT_CONNECTED))
|
||||
func isConnResetError(err: OSErrorCode): bool {.inline.} =
|
||||
case err
|
||||
of WSAECONNRESET, WSAECONNABORTED, ERROR_PIPE_NOT_CONNECTED:
|
||||
true
|
||||
else:
|
||||
false
|
||||
|
||||
proc writeStreamLoop(udata: pointer) {.gcsafe, nimcall.} =
|
||||
var bytesCount: uint32
|
||||
|
@ -343,7 +345,8 @@ when defined(windows):
|
|||
## Continuation
|
||||
transp.state.excl(WritePending)
|
||||
let err = transp.wovl.data.errCode
|
||||
if err == OSErrorCode(-1):
|
||||
case err
|
||||
of OSErrorCode(-1):
|
||||
bytesCount = transp.wovl.data.bytesCount
|
||||
var vector = transp.queue.popFirst()
|
||||
if bytesCount == 0:
|
||||
|
@ -377,7 +380,7 @@ when defined(windows):
|
|||
# This conversion to `int` safe, because its impossible
|
||||
# to call write() with size bigger than `int`.
|
||||
vector.writer.complete(int(transp.wwsabuf.len))
|
||||
elif int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.incl({WritePaused, WriteEof})
|
||||
let vector = transp.queue.popFirst()
|
||||
|
@ -416,7 +419,8 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr transp.wovl), nil)
|
||||
if ret != 0:
|
||||
let err = osLastError()
|
||||
if int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(WritePending)
|
||||
transp.state.incl({WritePaused, WriteEof})
|
||||
|
@ -424,7 +428,7 @@ when defined(windows):
|
|||
vector.writer.complete(0)
|
||||
completePendingWriteQueue(transp.queue, 0)
|
||||
break
|
||||
elif int(err) == osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
transp.queue.addFirst(vector)
|
||||
else:
|
||||
transp.state.excl(WritePending)
|
||||
|
@ -456,7 +460,8 @@ when defined(windows):
|
|||
nil, 0'u32)
|
||||
if ret == 0:
|
||||
let err = osLastError()
|
||||
if int(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(WritePending)
|
||||
transp.state.incl({WritePaused, WriteEof})
|
||||
|
@ -464,7 +469,7 @@ when defined(windows):
|
|||
vector.writer.complete(0)
|
||||
completePendingWriteQueue(transp.queue, 0)
|
||||
break
|
||||
elif int(err) == osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
transp.queue.addFirst(vector)
|
||||
else:
|
||||
transp.state.excl(WritePending)
|
||||
|
@ -496,8 +501,8 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr transp.wovl))
|
||||
if ret == 0:
|
||||
let err = osLastError()
|
||||
if int(err) in {osdefs.ERROR_OPERATION_ABORTED,
|
||||
osdefs.ERROR_NO_DATA}:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED, ERROR_NO_DATA:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(WritePending)
|
||||
transp.state.incl({WritePaused, WriteEof})
|
||||
|
@ -505,7 +510,7 @@ when defined(windows):
|
|||
vector.writer.complete(0)
|
||||
completePendingWriteQueue(transp.queue, 0)
|
||||
break
|
||||
elif int(err) == osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
transp.queue.addFirst(vector)
|
||||
else:
|
||||
transp.state.excl(WritePending)
|
||||
|
@ -539,7 +544,8 @@ when defined(windows):
|
|||
## Continuation
|
||||
transp.state.excl(ReadPending)
|
||||
let err = transp.rovl.data.errCode
|
||||
if err == OSErrorCode(-1):
|
||||
case err
|
||||
of OSErrorCode(-1):
|
||||
let bytesCount = transp.rovl.data.bytesCount
|
||||
if bytesCount == 0:
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
|
@ -552,19 +558,20 @@ when defined(windows):
|
|||
transp.roffset = transp.offset
|
||||
if transp.offset == len(transp.buffer):
|
||||
transp.state.incl(ReadPaused)
|
||||
elif int(err) in {osdefs.ERROR_OPERATION_ABORTED,
|
||||
osdefs.ERROR_CONNECTION_ABORTED,
|
||||
osdefs.ERROR_BROKEN_PIPE,
|
||||
osdefs.ERROR_NETNAME_DELETED}:
|
||||
of ERROR_OPERATION_ABORTED, ERROR_CONNECTION_ABORTED,
|
||||
ERROR_BROKEN_PIPE:
|
||||
# CancelIO() interrupt or closeSocket() call.
|
||||
transp.state.incl(ReadPaused)
|
||||
elif transp.kind == TransportKind.Socket and
|
||||
(int(err) in {osdefs.ERROR_NETNAME_DELETED,
|
||||
osdefs.WSAECONNABORTED}):
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
elif transp.kind == TransportKind.Pipe and
|
||||
(int(err) in {osdefs.ERROR_PIPE_NOT_CONNECTED}):
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
of ERROR_NETNAME_DELETED, WSAECONNABORTED:
|
||||
if transp.kind == TransportKind.Socket:
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
else:
|
||||
transp.setReadError(err)
|
||||
of ERROR_PIPE_NOT_CONNECTED:
|
||||
if transp.kind == TransportKind.Pipe:
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
else:
|
||||
transp.setReadError(err)
|
||||
else:
|
||||
transp.setReadError(err)
|
||||
|
||||
|
@ -593,16 +600,18 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr transp.rovl), nil)
|
||||
if ret != 0:
|
||||
let err = osLastError()
|
||||
if int32(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl(ReadPaused)
|
||||
elif int32(err) in {osdefs.WSAECONNRESET, osdefs.WSAENETRESET,
|
||||
osdefs.WSAECONNABORTED}:
|
||||
of WSAECONNRESET, WSAENETRESET, WSAECONNABORTED:
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
transp.completeReader()
|
||||
elif int32(err) != osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
discard
|
||||
else:
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl(ReadPaused)
|
||||
transp.setReadError(err)
|
||||
|
@ -616,16 +625,18 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr transp.rovl))
|
||||
if ret == 0:
|
||||
let err = osLastError()
|
||||
if int32(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl(ReadPaused)
|
||||
elif int32(err) in {osdefs.ERROR_BROKEN_PIPE,
|
||||
osdefs.ERROR_PIPE_NOT_CONNECTED}:
|
||||
of ERROR_BROKEN_PIPE, ERROR_PIPE_NOT_CONNECTED:
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
transp.completeReader()
|
||||
elif int32(err) != osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
discard
|
||||
else:
|
||||
transp.state.excl(ReadPending)
|
||||
transp.state.incl(ReadPaused)
|
||||
transp.setReadError(err)
|
||||
|
@ -769,8 +780,8 @@ when defined(windows):
|
|||
var ovl = cast[RefCustomOverlapped](udata)
|
||||
if not(retFuture.finished()):
|
||||
if ovl.data.errCode == OSErrorCode(-1):
|
||||
if setsockopt(SocketHandle(sock), cint(osdefs.SOL_SOCKET),
|
||||
cint(osdefs.SO_UPDATE_CONNECT_CONTEXT), nil,
|
||||
if setsockopt(SocketHandle(sock), cint(SOL_SOCKET),
|
||||
cint(SO_UPDATE_CONNECT_CONTEXT), nil,
|
||||
SockLen(0)) != 0'i32:
|
||||
let err = wsaGetLastError()
|
||||
sock.closeSocket()
|
||||
|
@ -796,9 +807,12 @@ when defined(windows):
|
|||
cint(slen), nil, 0, nil,
|
||||
cast[POVERLAPPED](povl))
|
||||
# We will not process immediate completion, to avoid undefined behavior.
|
||||
if res == osdefs.FALSE:
|
||||
if res == FALSE:
|
||||
let err = osLastError()
|
||||
if int32(err) != osdefs.ERROR_IO_PENDING:
|
||||
case err
|
||||
of ERROR_IO_PENDING:
|
||||
discard
|
||||
else:
|
||||
GC_unref(povl)
|
||||
sock.closeSocket()
|
||||
retFuture.fail(getTransportOsError(err))
|
||||
|
@ -809,7 +823,7 @@ when defined(windows):
|
|||
## Unix domain socket emulation with Windows Named Pipes.
|
||||
# For some reason Nim compiler does not detect `pipeHandle` usage in
|
||||
# pipeContinuation() procedure, so we marking it as {.used.} here.
|
||||
var pipeHandle {.used.} = osdefs.INVALID_HANDLE_VALUE
|
||||
var pipeHandle {.used.} = INVALID_HANDLE_VALUE
|
||||
var pipeContinuation: proc (udata: pointer) {.gcsafe, raises: [Defect].}
|
||||
|
||||
pipeContinuation = proc (udata: pointer) {.gcsafe, raises: [Defect].} =
|
||||
|
@ -821,15 +835,16 @@ when defined(windows):
|
|||
pipeName = toWideString(pipeAsciiName).valueOr:
|
||||
retFuture.fail(getTransportOsError(error))
|
||||
return
|
||||
genericFlags = osdefs.GENERIC_READ or osdefs.GENERIC_WRITE
|
||||
shareFlags = osdefs.FILE_SHARE_READ or osdefs.FILE_SHARE_WRITE
|
||||
genericFlags = GENERIC_READ or GENERIC_WRITE
|
||||
shareFlags = FILE_SHARE_READ or FILE_SHARE_WRITE
|
||||
pipeHandle = createFile(pipeName, genericFlags, shareFlags,
|
||||
nil, osdefs.OPEN_EXISTING,
|
||||
osdefs.FILE_FLAG_OVERLAPPED, HANDLE(0))
|
||||
nil, OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED, HANDLE(0))
|
||||
free(pipeName)
|
||||
if pipeHandle == osdefs.INVALID_HANDLE_VALUE:
|
||||
if pipeHandle == INVALID_HANDLE_VALUE:
|
||||
let err = osLastError()
|
||||
if int32(err) == osdefs.ERROR_PIPE_BUSY:
|
||||
case err
|
||||
of ERROR_PIPE_BUSY:
|
||||
discard setTimer(Moment.fromNow(50.milliseconds),
|
||||
pipeContinuation, nil)
|
||||
else:
|
||||
|
@ -856,23 +871,22 @@ when defined(windows):
|
|||
openMode =
|
||||
if FirstPipe notin server.flags:
|
||||
server.flags.incl(FirstPipe)
|
||||
osdefs.PIPE_ACCESS_DUPLEX or osdefs.FILE_FLAG_OVERLAPPED or
|
||||
osdefs.FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED or
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
else:
|
||||
osdefs.PIPE_ACCESS_DUPLEX or osdefs.FILE_FLAG_OVERLAPPED
|
||||
pipeMode = osdefs.PIPE_TYPE_BYTE or osdefs.PIPE_READMODE_BYTE or
|
||||
osdefs.PIPE_WAIT
|
||||
PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED
|
||||
pipeMode = PIPE_TYPE_BYTE or PIPE_READMODE_BYTE or PIPE_WAIT
|
||||
pipeHandle = createNamedPipe(pipeName, openMode, pipeMode,
|
||||
osdefs.PIPE_UNLIMITED_INSTANCES,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
DWORD(server.bufferSize),
|
||||
DWORD(server.bufferSize),
|
||||
DWORD(0), nil)
|
||||
free(pipeName)
|
||||
if pipeHandle == osdefs.INVALID_HANDLE_VALUE:
|
||||
if pipeHandle == INVALID_HANDLE_VALUE:
|
||||
return err(osLastError())
|
||||
let res = register2(AsyncFD(pipeHandle))
|
||||
if res.isErr():
|
||||
discard osdefs.closeHandle(pipeHandle)
|
||||
discard closeHandle(pipeHandle)
|
||||
return err(res.error())
|
||||
|
||||
ok(AsyncFD(pipeHandle))
|
||||
|
@ -886,7 +900,8 @@ when defined(windows):
|
|||
## Continuation
|
||||
server.apending = false
|
||||
if server.status notin {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
if ovl.data.errCode == OSErrorCode(-1):
|
||||
case ovl.data.errCode
|
||||
of OSErrorCode(-1):
|
||||
var ntransp: StreamTransport
|
||||
var flags = {WinServerPipe}
|
||||
if NoPipeFlash in server.flags:
|
||||
|
@ -901,7 +916,7 @@ when defined(windows):
|
|||
# Start tracking transport
|
||||
trackStream(ntransp)
|
||||
asyncSpawn server.function(server, ntransp)
|
||||
elif int32(ovl.data.errCode) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt or close call.
|
||||
if server.status in {ServerStatus.Closed, ServerStatus.Stopped}:
|
||||
server.clean()
|
||||
|
@ -931,19 +946,18 @@ when defined(windows):
|
|||
openMode =
|
||||
if FirstPipe notin server.flags:
|
||||
server.flags.incl(FirstPipe)
|
||||
osdefs.PIPE_ACCESS_DUPLEX or osdefs.FILE_FLAG_OVERLAPPED or
|
||||
osdefs.FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED or
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
else:
|
||||
osdefs.PIPE_ACCESS_DUPLEX or osdefs.FILE_FLAG_OVERLAPPED
|
||||
pipeMode = osdefs.PIPE_TYPE_BYTE or osdefs.PIPE_READMODE_BYTE or
|
||||
osdefs.PIPE_WAIT
|
||||
PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED
|
||||
pipeMode = PIPE_TYPE_BYTE or PIPE_READMODE_BYTE or PIPE_WAIT
|
||||
pipeHandle = createNamedPipe(pipeName, openMode, pipeMode,
|
||||
osdefs.PIPE_UNLIMITED_INSTANCES,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
DWORD(server.bufferSize),
|
||||
DWORD(server.bufferSize),
|
||||
DWORD(0), nil)
|
||||
free(pipeName)
|
||||
if pipeHandle == osdefs.INVALID_HANDLE_VALUE:
|
||||
if pipeHandle == INVALID_HANDLE_VALUE:
|
||||
raiseOsDefect(osLastError(), "acceptPipeLoop(): Unable to create " &
|
||||
"new pipe")
|
||||
server.sock = AsyncFD(pipeHandle)
|
||||
|
@ -955,12 +969,12 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr server.aovl))
|
||||
if res == 0:
|
||||
let errCode = osLastError()
|
||||
if errCode == osdefs.ERROR_OPERATION_ABORTED:
|
||||
if errCode == ERROR_OPERATION_ABORTED:
|
||||
server.apending = false
|
||||
break
|
||||
elif errCode == osdefs.ERROR_IO_PENDING:
|
||||
elif errCode == ERROR_IO_PENDING:
|
||||
discard
|
||||
elif errCode == osdefs.ERROR_PIPE_CONNECTED:
|
||||
elif errCode == ERROR_PIPE_CONNECTED:
|
||||
discard
|
||||
else:
|
||||
raiseOsDefect(errCode, "acceptPipeLoop(): Unable to establish " &
|
||||
|
@ -983,9 +997,10 @@ when defined(windows):
|
|||
## Continuation
|
||||
server.apending = false
|
||||
if server.status notin {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
if ovl.data.errCode == OSErrorCode(-1):
|
||||
if setsockopt(SocketHandle(server.asock), cint(osdefs.SOL_SOCKET),
|
||||
cint(osdefs.SO_UPDATE_ACCEPT_CONTEXT),
|
||||
case ovl.data.errCode
|
||||
of OSErrorCode(-1):
|
||||
if setsockopt(SocketHandle(server.asock), cint(SOL_SOCKET),
|
||||
cint(SO_UPDATE_ACCEPT_CONTEXT),
|
||||
addr server.sock,
|
||||
SockLen(sizeof(SocketHandle))) != 0'i32:
|
||||
let errCode = OSErrorCode(wsaGetLastError())
|
||||
|
@ -1006,7 +1021,7 @@ when defined(windows):
|
|||
trackStream(ntransp)
|
||||
asyncSpawn server.function(server, ntransp)
|
||||
|
||||
elif int32(ovl.data.errCode) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt or close.
|
||||
server.asock.closeSocket()
|
||||
if server.status in {ServerStatus.Closed, ServerStatus.Stopped}:
|
||||
|
@ -1049,12 +1064,12 @@ when defined(windows):
|
|||
dwReceiveDataLength, dwLocalAddressLength,
|
||||
dwRemoteAddressLength, addr dwBytesReceived,
|
||||
cast[POVERLAPPED](addr server.aovl))
|
||||
if res == osdefs.FALSE:
|
||||
if res == FALSE:
|
||||
let errCode = osLastError()
|
||||
if errCode == osdefs.ERROR_OPERATION_ABORTED:
|
||||
if errCode == ERROR_OPERATION_ABORTED:
|
||||
server.apending = false
|
||||
break
|
||||
elif errCode == osdefs.ERROR_IO_PENDING:
|
||||
elif errCode == ERROR_IO_PENDING:
|
||||
discard
|
||||
else:
|
||||
raiseOsDefect(errCode, "acceptLoop(): Unable to accept " &
|
||||
|
@ -1121,13 +1136,14 @@ when defined(windows):
|
|||
else:
|
||||
case ovl.data.errCode
|
||||
of OSErrorCode(-1):
|
||||
if setsockopt(SocketHandle(server.asock), cint(osdefs.SOL_SOCKET),
|
||||
cint(osdefs.SO_UPDATE_ACCEPT_CONTEXT),
|
||||
if setsockopt(SocketHandle(server.asock), cint(SOL_SOCKET),
|
||||
cint(SO_UPDATE_ACCEPT_CONTEXT),
|
||||
addr server.sock,
|
||||
SockLen(sizeof(SocketHandle))) != 0'i32:
|
||||
let err = osLastError()
|
||||
server.asock.closeSocket()
|
||||
if err == osdefs.WSAENOTSOCK:
|
||||
case err
|
||||
of WSAENOTSOCK:
|
||||
# This can be happened when server get closed, but continuation
|
||||
# was already scheduled, so we failing it not with OS error.
|
||||
retFuture.fail(getServerUseClosedError())
|
||||
|
@ -1147,18 +1163,15 @@ when defined(windows):
|
|||
# Start tracking transport
|
||||
trackStream(ntransp)
|
||||
retFuture.complete(ntransp)
|
||||
of OSErrorCode(osdefs.ERROR_OPERATION_ABORTED):
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt or close.
|
||||
server.asock.closeSocket()
|
||||
retFuture.fail(getServerUseClosedError())
|
||||
server.clean()
|
||||
of OSErrorCode(osdefs.WSAENETDOWN),
|
||||
OSErrorCode(osdefs.WSAENETRESET),
|
||||
OSErrorCode(osdefs.WSAECONNABORTED),
|
||||
OSErrorCode(osdefs.WSAECONNRESET),
|
||||
OSErrorCode(osdefs.WSAETIMEDOUT):
|
||||
of WSAENETDOWN, WSAENETRESET, WSAECONNABORTED, WSAECONNRESET,
|
||||
WSAETIMEDOUT:
|
||||
server.asock.closeSocket()
|
||||
retFuture.fail(getConnectionAbortedError(int(ovl.data.errCode)))
|
||||
retFuture.fail(getConnectionAbortedError(ovl.data.errCode))
|
||||
server.clean()
|
||||
else:
|
||||
server.asock.closeSocket()
|
||||
|
@ -1189,7 +1202,8 @@ when defined(windows):
|
|||
server.sock.closeHandle()
|
||||
server.clean()
|
||||
else:
|
||||
if ovl.data.errCode == OSErrorCode(-1):
|
||||
case ovl.data.errCode
|
||||
of OSErrorCode(-1):
|
||||
var ntransp: StreamTransport
|
||||
var flags = {WinServerPipe}
|
||||
if NoPipeFlash in server.flags:
|
||||
|
@ -1210,8 +1224,7 @@ when defined(windows):
|
|||
trackStream(ntransp)
|
||||
retFuture.complete(ntransp)
|
||||
|
||||
elif int32(ovl.data.errCode) in {osdefs.ERROR_OPERATION_ABORTED,
|
||||
osdefs.ERROR_PIPE_NOT_CONNECTED}:
|
||||
of ERROR_OPERATION_ABORTED, ERROR_PIPE_NOT_CONNECTED:
|
||||
# CancelIO() interrupt or close call.
|
||||
retFuture.fail(getServerUseClosedError())
|
||||
server.clean()
|
||||
|
@ -1236,10 +1249,9 @@ when defined(windows):
|
|||
Protocol.IPPROTO_TCP)
|
||||
if server.asock == asyncInvalidSocket:
|
||||
let err = osLastError()
|
||||
case int(err)
|
||||
of osdefs.ERROR_TOO_MANY_OPEN_FILES,
|
||||
osdefs.WSAENOBUFS, osdefs.WSAEMFILE:
|
||||
retFuture.fail(getTransportTooManyError(int(err)))
|
||||
case err
|
||||
of ERROR_TOO_MANY_OPEN_FILES, WSAENOBUFS, WSAEMFILE:
|
||||
retFuture.fail(getTransportTooManyError(err))
|
||||
else:
|
||||
retFuture.fail(getTransportOsError(err))
|
||||
return retFuture
|
||||
|
@ -1258,19 +1270,19 @@ when defined(windows):
|
|||
dwReceiveDataLength, dwLocalAddressLength,
|
||||
dwRemoteAddressLength, addr dwBytesReceived,
|
||||
cast[POVERLAPPED](addr server.aovl))
|
||||
if res == osdefs.FALSE:
|
||||
if res == FALSE:
|
||||
let err = osLastError()
|
||||
case int(err)
|
||||
of osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
server.apending = false
|
||||
retFuture.fail(getServerUseClosedError())
|
||||
return retFuture
|
||||
of osdefs.ERROR_IO_PENDING:
|
||||
of ERROR_IO_PENDING:
|
||||
discard
|
||||
of osdefs.WSAECONNRESET, osdefs.WSAECONNABORTED, osdefs.WSAENETDOWN,
|
||||
osdefs.WSAENETRESET, osdefs.WSAETIMEDOUT:
|
||||
of WSAECONNRESET, WSAECONNABORTED, WSAENETDOWN,
|
||||
WSAENETRESET, WSAETIMEDOUT:
|
||||
server.apending = false
|
||||
retFuture.fail(getConnectionAbortedError(int(err)))
|
||||
retFuture.fail(getConnectionAbortedError(err))
|
||||
return retFuture
|
||||
else:
|
||||
server.apending = false
|
||||
|
@ -1284,7 +1296,8 @@ when defined(windows):
|
|||
server.apending = true
|
||||
if server.sock == asyncInvalidPipe:
|
||||
let err = server.errorCode
|
||||
if int32(err) == osdefs.ERROR_TOO_MANY_OPEN_FILES:
|
||||
case err
|
||||
of ERROR_TOO_MANY_OPEN_FILES:
|
||||
retFuture.fail(getTransportTooManyError())
|
||||
else:
|
||||
retFuture.fail(getTransportOsError(err))
|
||||
|
@ -1297,12 +1310,12 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr server.aovl))
|
||||
if res == 0:
|
||||
let err = osLastError()
|
||||
if int32(err) == osdefs.ERROR_OPERATION_ABORTED:
|
||||
case err
|
||||
of ERROR_OPERATION_ABORTED:
|
||||
server.apending = false
|
||||
retFuture.fail(getServerUseClosedError())
|
||||
return retFuture
|
||||
elif int32(err) in {osdefs.ERROR_IO_PENDING,
|
||||
osdefs.ERROR_PIPE_CONNECTED}:
|
||||
of ERROR_IO_PENDING, ERROR_PIPE_CONNECTED:
|
||||
discard
|
||||
else:
|
||||
server.apending = false
|
||||
|
@ -1317,7 +1330,7 @@ else:
|
|||
import ../sendfile
|
||||
|
||||
proc isConnResetError(err: OSErrorCode): bool {.inline.} =
|
||||
(err == OSErrorCode(ECONNRESET)) or (err == OSErrorCode(EPIPE))
|
||||
(err == oserrno.ECONNRESET) or (err == oserrno.EPIPE)
|
||||
|
||||
proc writeStreamLoop(udata: pointer) =
|
||||
if isNil(udata):
|
||||
|
@ -1345,33 +1358,32 @@ else:
|
|||
while len(transp.queue) > 0:
|
||||
template handleError() =
|
||||
let err = osLastError()
|
||||
|
||||
if cint(err) == EINTR:
|
||||
case err
|
||||
of oserrno.EINTR:
|
||||
# Signal happened while writing - try again with all data
|
||||
transp.queue.addFirst(vector)
|
||||
continue
|
||||
|
||||
if cint(err) in [EWOULDBLOCK, EAGAIN]:
|
||||
of oserrno.EWOULDBLOCK:
|
||||
# Socket buffer is full - wait until next write notification - in
|
||||
# particular, ensure removeWriter is not called
|
||||
transp.queue.addFirst(vector)
|
||||
return
|
||||
|
||||
# The errors below will clear the write queue, meaning we'll exit the
|
||||
# loop
|
||||
if isConnResetError(err):
|
||||
# Soft error happens which indicates that remote peer got
|
||||
# disconnected, complete all pending writes in queue with 0.
|
||||
transp.state.incl({WriteEof})
|
||||
if not(vector.writer.finished()):
|
||||
vector.writer.complete(0)
|
||||
completePendingWriteQueue(transp.queue, 0)
|
||||
else:
|
||||
transp.state.incl({WriteError})
|
||||
let error = getTransportOsError(err)
|
||||
if not(vector.writer.finished()):
|
||||
vector.writer.fail(error)
|
||||
failPendingWriteQueue(transp.queue, error)
|
||||
# The errors below will clear the write queue, meaning we'll exit the
|
||||
# loop
|
||||
if isConnResetError(err):
|
||||
# Soft error happens which indicates that remote peer got
|
||||
# disconnected, complete all pending writes in queue with 0.
|
||||
transp.state.incl({WriteEof})
|
||||
if not(vector.writer.finished()):
|
||||
vector.writer.complete(0)
|
||||
completePendingWriteQueue(transp.queue, 0)
|
||||
else:
|
||||
transp.state.incl({WriteError})
|
||||
let error = getTransportOsError(err)
|
||||
if not(vector.writer.finished()):
|
||||
vector.writer.fail(error)
|
||||
failPendingWriteQueue(transp.queue, error)
|
||||
|
||||
var vector = transp.queue.popFirst()
|
||||
case vector.kind
|
||||
|
@ -1443,7 +1455,8 @@ else:
|
|||
len(transp.buffer) - transp.offset, cint(0)))
|
||||
if res < 0:
|
||||
let err = osLastError()
|
||||
if int(err) == ECONNRESET:
|
||||
case err
|
||||
of oserrno.ECONNRESET:
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
let rres = removeReader2(transp.fd)
|
||||
if rres.isErr():
|
||||
|
@ -1553,7 +1566,8 @@ else:
|
|||
proto)
|
||||
if sock == asyncInvalidSocket:
|
||||
let err = osLastError()
|
||||
if int(err) == EMFILE:
|
||||
case err
|
||||
of oserrno.EMFILE:
|
||||
retFuture.fail(getTransportTooManyError())
|
||||
else:
|
||||
retFuture.fail(getTransportOsError(err))
|
||||
|
@ -1641,7 +1655,8 @@ else:
|
|||
# and the connection shall be established asynchronously.
|
||||
#
|
||||
# http://www.madore.org/~david/computers/connect-intr.html
|
||||
if (errorCode == EINPROGRESS) or (errorCode == EINTR):
|
||||
case errorCode
|
||||
of oserrno.EINPROGRESS, oserrno.EINTR:
|
||||
let res = addWriter2(sock, continuation)
|
||||
if res.isErr():
|
||||
discard unregisterAndCloseFd(sock)
|
||||
|
@ -1692,7 +1707,7 @@ else:
|
|||
discard closeFd(cint(sock))
|
||||
else:
|
||||
let errorCode = sres.error()
|
||||
if errorCode != EAGAIN:
|
||||
if errorCode != oserrno.EAGAIN:
|
||||
# This EAGAIN error appears only when server get closed, while
|
||||
# acceptLoop() reader callback is already scheduled.
|
||||
raiseOsDefect(errorCode, "acceptLoop(): Unable to accept connection")
|
||||
|
@ -1745,14 +1760,15 @@ else:
|
|||
addr slen, flags)
|
||||
if sres.isErr():
|
||||
let errorCode = sres.error()
|
||||
if errorCode == EAGAIN:
|
||||
case errorCode
|
||||
of oserrno.EAGAIN:
|
||||
# This error appears only when server get closed, while accept()
|
||||
# continuation is already scheduled.
|
||||
retFuture.fail(getServerUseClosedError())
|
||||
elif cint(errorCode) in {EMFILE, ENFILE, ENOBUFS, ENOMEM}:
|
||||
retFuture.fail(getTransportTooManyError(cint(errorCode)))
|
||||
elif cint(errorCode) in {ECONNABORTED, EPERM, ETIMEDOUT}:
|
||||
retFuture.fail(getConnectionAbortedError(cint(errorCode)))
|
||||
of oserrno.EMFILE, oserrno.ENFILE, oserrno.ENOBUFS, oserrno.ENOMEM:
|
||||
retFuture.fail(getTransportTooManyError(errorCode))
|
||||
of oserrno.ECONNABORTED, oserrno.EPERM, oserrno.ETIMEDOUT:
|
||||
retFuture.fail(getConnectionAbortedError(errorCode))
|
||||
else:
|
||||
retFuture.fail(getTransportOsError(errorCode))
|
||||
# Error is already happened so we ignore removeReader2() errors.
|
||||
|
@ -1933,15 +1949,13 @@ proc createStreamServer*(host: TransportAddress,
|
|||
serverSocket = sock
|
||||
# SO_REUSEADDR is not useful for Unix domain sockets.
|
||||
if ServerFlags.ReuseAddr in flags:
|
||||
if not(setSockOpt(serverSocket, osdefs.SOL_SOCKET,
|
||||
osdefs.SO_REUSEADDR, 1)):
|
||||
if not(setSockOpt(serverSocket, SOL_SOCKET, SO_REUSEADDR, 1)):
|
||||
let err = osLastError()
|
||||
if sock == asyncInvalidSocket:
|
||||
discard closeFd(SocketHandle(serverSocket))
|
||||
raiseTransportOsError(err)
|
||||
if ServerFlags.ReusePort in flags:
|
||||
if not(setSockOpt(serverSocket, osdefs.SOL_SOCKET,
|
||||
osdefs.SO_REUSEPORT, 1)):
|
||||
if not(setSockOpt(serverSocket, SOL_SOCKET, SO_REUSEPORT, 1)):
|
||||
let err = osLastError()
|
||||
if sock == asyncInvalidSocket:
|
||||
discard closeFd(SocketHandle(serverSocket))
|
||||
|
@ -1955,8 +1969,8 @@ proc createStreamServer*(host: TransportAddress,
|
|||
discard closeFd(SocketHandle(serverSocket))
|
||||
raiseTransportOsError(err)
|
||||
host.toSAddr(saddr, slen)
|
||||
if osdefs.bindSocket(SocketHandle(serverSocket),
|
||||
cast[ptr SockAddr](addr saddr), slen) != 0:
|
||||
if bindSocket(SocketHandle(serverSocket),
|
||||
cast[ptr SockAddr](addr saddr), slen) != 0:
|
||||
let err = osLastError()
|
||||
if sock == asyncInvalidSocket:
|
||||
discard closeFd(SocketHandle(serverSocket))
|
||||
|
@ -2165,21 +2179,21 @@ template fastWrite(transp: auto, pbytes: var ptr byte, rbytes: var int,
|
|||
# Not all bytes written - keep going
|
||||
else:
|
||||
let err = osLastError()
|
||||
if cint(err) in [EAGAIN, EWOULDBLOCK]:
|
||||
case err
|
||||
of oserrno.EWOULDBLOCK:
|
||||
break # No bytes written, add to queue
|
||||
|
||||
if cint(err) == EINTR:
|
||||
of oserrno.EINTR:
|
||||
continue
|
||||
|
||||
if isConnResetError(err):
|
||||
transp.state.incl({WriteEof})
|
||||
retFuture.complete(0)
|
||||
return retFuture
|
||||
else:
|
||||
transp.state.incl({WriteError})
|
||||
let error = getTransportOsError(err)
|
||||
retFuture.fail(error)
|
||||
return retFuture
|
||||
if isConnResetError(err):
|
||||
transp.state.incl({WriteEof})
|
||||
retFuture.complete(0)
|
||||
return retFuture
|
||||
else:
|
||||
transp.state.incl({WriteError})
|
||||
let error = getTransportOsError(err)
|
||||
retFuture.fail(error)
|
||||
return retFuture
|
||||
|
||||
proc write*(transp: StreamTransport, pbytes: pointer,
|
||||
nbytes: int): Future[int] =
|
||||
|
@ -2340,7 +2354,7 @@ template readLoop(name, body: untyped): untyped =
|
|||
raiseOsDefect(errorCode, "readLoop(): Unable to resume reading")
|
||||
else:
|
||||
transp.reader.complete()
|
||||
if errorCode == ESRCH:
|
||||
if errorCode == oserrno.ESRCH:
|
||||
# ESRCH 3 "No such process"
|
||||
# This error could be happened on pipes only, when process which
|
||||
# owns and communicates through this pipe (stdin, stdout, stderr) is
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# MIT license (LICENSE-MIT)
|
||||
import std/[strutils, os]
|
||||
import unittest2
|
||||
import ".."/chronos, ".."/chronos/osdefs
|
||||
import ".."/chronos, ".."/chronos/[osdefs, oserrno]
|
||||
|
||||
{.used.}
|
||||
|
||||
|
@ -639,12 +639,11 @@ suite "Stream Transport test suite":
|
|||
var transp = await connect(address)
|
||||
doAssert(isNil(transp))
|
||||
except TransportOsError as e:
|
||||
let ecode = int(e.code)
|
||||
when defined(windows):
|
||||
result = (ecode == ERROR_FILE_NOT_FOUND) or
|
||||
(ecode == ERROR_CONNECTION_REFUSED)
|
||||
return (e.code == ERROR_FILE_NOT_FOUND) or
|
||||
(e.code == ERROR_CONNECTION_REFUSED)
|
||||
else:
|
||||
result = (ecode == ECONNREFUSED) or (ecode == ENOENT)
|
||||
return (e.code == oserrno.ECONNREFUSED) or (e.code == oserrno.ENOENT)
|
||||
|
||||
proc serveClient16(server: StreamServer, transp: StreamTransport) {.async.} =
|
||||
var res = await transp.write(BigMessagePattern)
|
||||
|
|
Loading…
Reference in New Issue