Deprecated OSError, and modified it to require an explicit OS error code.

The deprecated functions include the OSError and OSErrorMsg, the name did not change however the signature of the new functions did. They now require a TOSErrorCode value be passed to them. This value can be retrieved using OSLastError. The reason this was done is because on Windows any win api call can reset the last error code to 0, this change allows the user to immediately grab the error code and worry about the string representation later if needs be.
This commit is contained in:
Dominik Picheta 2013-06-25 20:10:28 +01:00
commit bacb20a379
5 changed files with 196 additions and 126 deletions

View file

@ -167,7 +167,7 @@ proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
result = newAsyncSocket() result = newAsyncSocket()
result.socket = socket(domain, typ, protocol, buffered) result.socket = socket(domain, typ, protocol, buffered)
result.proto = protocol result.proto = protocol
if result.socket == InvalidSocket: OSError() if result.socket == InvalidSocket: OSError(OSLastError())
result.socket.setBlocking(false) result.socket.setBlocking(false)
proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket = proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
@ -349,7 +349,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
client.sslNeedAccept = false client.sslNeedAccept = false
client.info = SockConnected client.info = SockConnected
if c == InvalidSocket: OSError() if c == InvalidSocket: SocketError(server.socket)
c.setBlocking(false) # TODO: Needs to be tested. c.setBlocking(false) # TODO: Needs to be tested.
# deleg.open is set in ``toDelegate``. # deleg.open is set in ``toDelegate``.
@ -642,8 +642,7 @@ when isMainModule:
proc testRead(s: PAsyncSocket, no: int) = proc testRead(s: PAsyncSocket, no: int) =
echo("Reading! " & $no) echo("Reading! " & $no)
var data = "" var data = ""
if not s.readLine(data): if not s.readLine(data): return
OSError()
if data == "": if data == "":
echo("Closing connection. " & $no) echo("Closing connection. " & $no)
s.close() s.close()

View file

@ -39,6 +39,8 @@ type
FWriteDir* = object of FWriteIO ## effect that denotes a write operation to FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
## the directory structure ## the directory structure
TOSErrorCode* = distinct int32 ## Specifies an OS Error Code.
const const
doslike = defined(windows) or defined(OS2) or defined(DOS) doslike = defined(windows) or defined(OS2) or defined(DOS)
# DOS-like filesystem # DOS-like filesystem
@ -171,10 +173,13 @@ const
## The character which separates the base filename from the extension; ## The character which separates the base filename from the extension;
## for example, the '.' in ``os.nim``. ## for example, the '.' in ``os.nim``.
proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} = proc OSErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
## Retrieves the operating system's error flag, ``errno``. ## Retrieves the operating system's error flag, ``errno``.
## On Windows ``GetLastError`` is checked before ``errno``. ## On Windows ``GetLastError`` is checked before ``errno``.
## Returns "" if no error occured. ## Returns "" if no error occured.
##
## **Deprecated since version 0.9.4**: use the other ``OSErrorMsg`` proc.
result = "" result = ""
when defined(Windows): when defined(Windows):
var err = GetLastError() var err = GetLastError()
@ -194,17 +199,89 @@ proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
if errno != 0'i32: if errno != 0'i32:
result = $os.strerror(errno) result = $os.strerror(errno)
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} = {.push warning[deprecated]: off.}
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} =
## raises an EOS exception with the given message ``msg``. ## raises an EOS exception with the given message ``msg``.
## If ``msg == ""``, the operating system's error flag ## If ``msg == ""``, the operating system's error flag
## (``errno``) is converted to a readable error message. On Windows ## (``errno``) is converted to a readable error message. On Windows
## ``GetLastError`` is checked before ``errno``. ## ``GetLastError`` is checked before ``errno``.
## If no error flag is set, the message ``unknown OS error`` is used. ## If no error flag is set, the message ``unknown OS error`` is used.
##
## **Deprecated since version 0.9.4**: use the other ``OSError`` proc.
if len(msg) == 0: if len(msg) == 0:
var m = OSErrorMsg() var m = OSErrorMsg()
raise newException(EOS, if m.len > 0: m else: "unknown OS error") raise newException(EOS, if m.len > 0: m else: "unknown OS error")
else: else:
raise newException(EOS, msg) raise newException(EOS, msg)
{.pop.}
proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.}
proc `$`*(err: TOSErrorCode): string {.borrow.}
proc OSErrorMsg*(errorCode: TOSErrorCode): string =
## Converts an OS error code into a human readable string.
##
## The error code can be retrieved using the ``OSLastError`` proc.
##
## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be
## returned.
##
## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to
## make this procedure use the non-unicode Win API calls to retrieve the
## message.
result = ""
when defined(Windows):
if errorCode != TOSErrorCode(0'i32):
when useWinUnicode:
var msgbuf: widecstring
if FormatMessageW(0x00000100 or 0x00001000 or 0x00000200,
nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
result = $msgbuf
if msgbuf != nil: LocalFree(cast[pointer](msgbuf))
else:
var msgbuf: cstring
if FormatMessageA(0x00000100 or 0x00001000 or 0x00000200,
nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
result = $msgbuf
if msgbuf != nil: LocalFree(msgbuf)
else:
if errorCode != TOSErrorCode(0'i32):
result = $os.strerror(errorCode.int32)
proc OSError*(errorCode: TOSErrorCode) =
## Raises an ``EOS`` exception. The ``errorCode`` will determine the
## message, ``OSErrorMsg`` will be used to get this message.
##
## The error code can be retrieved using the ``OSLastError`` proc.
##
## If the error code is ``0`` or an error message could not be retrieved,
## the message ``unknown OS error`` will be used.
let msg = OSErrorMsg(errorCode)
if msg == "":
raise newException(EOS, "unknown OS error")
else:
raise newException(EOS, msg)
{.push stackTrace:off.}
proc OSLastError*(): TOSErrorCode =
## Retrieves the last operating system error code.
##
## This procedure is useful in the event when an OS call fails. In that case
## this procedure will return the error code describing the reason why the
## OS call failed. The ``OSErrorMsg`` procedure can then be used to convert
## this code into a string.
##
## **Warning**:
## The behaviour of this procedure varies between Windows and POSIX systems.
## On Windows some OS calls can reset the error code to ``0`` causing this
## procedure to return ``0``. It is therefore advised to call this procedure
## immediately after an OS call fails. On POSIX systems this is not a problem.
when defined(windows):
result = TOSErrorCode(GetLastError())
else:
result = TOSErrorCode(errno)
{.pop.}
proc UnixToNativePath*(path: string): string {. proc UnixToNativePath*(path: string): string {.
noSideEffect, rtl, extern: "nos$1".} = noSideEffect, rtl, extern: "nos$1".} =
@ -311,12 +388,12 @@ proc getLastModificationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
## Returns the `file`'s last modification time. ## Returns the `file`'s last modification time.
when defined(posix): when defined(posix):
var res: TStat var res: TStat
if stat(file, res) < 0'i32: OSError() if stat(file, res) < 0'i32: OSError(OSLastError())
return res.st_mtime return res.st_mtime
else: else:
var f: TWIN32_Find_Data var f: TWIN32_Find_Data
var h = findfirstFile(file, f) var h = findfirstFile(file, f)
if h == -1'i32: OSError() if h == -1'i32: OSError(OSLastError())
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime)) result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
findclose(h) findclose(h)
@ -324,12 +401,12 @@ proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} =
## Returns the `file`'s last read or write access time. ## Returns the `file`'s last read or write access time.
when defined(posix): when defined(posix):
var res: TStat var res: TStat
if stat(file, res) < 0'i32: OSError() if stat(file, res) < 0'i32: OSError(OSLastError())
return res.st_atime return res.st_atime
else: else:
var f: TWIN32_Find_Data var f: TWIN32_Find_Data
var h = findfirstFile(file, f) var h = findfirstFile(file, f)
if h == -1'i32: OSError() if h == -1'i32: OSError(OSLastError())
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime)) result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
findclose(h) findclose(h)
@ -337,12 +414,12 @@ proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
## Returns the `file`'s creation time. ## Returns the `file`'s creation time.
when defined(posix): when defined(posix):
var res: TStat var res: TStat
if stat(file, res) < 0'i32: OSError() if stat(file, res) < 0'i32: OSError(OSLastError())
return res.st_ctime return res.st_ctime
else: else:
var f: TWIN32_Find_Data var f: TWIN32_Find_Data
var h = findfirstFile(file, f) var h = findfirstFile(file, f)
if h == -1'i32: OSError() if h == -1'i32: OSError(OSLastError())
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime)) result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
findclose(h) findclose(h)
@ -358,30 +435,30 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
when useWinUnicode: when useWinUnicode:
var res = newWideCString("", bufsize) var res = newWideCString("", bufsize)
var L = GetCurrentDirectoryW(bufsize, res) var L = GetCurrentDirectoryW(bufsize, res)
if L == 0'i32: OSError() if L == 0'i32: OSError(OSLastError())
result = res$L result = res$L
else: else:
result = newString(bufsize) result = newString(bufsize)
var L = GetCurrentDirectoryA(bufsize, result) var L = GetCurrentDirectoryA(bufsize, result)
if L == 0'i32: OSError() if L == 0'i32: OSError(OSLastError())
setLen(result, L) setLen(result, L)
else: else:
result = newString(bufsize) result = newString(bufsize)
if getcwd(result, bufsize) != nil: if getcwd(result, bufsize) != nil:
setlen(result, c_strlen(result)) setlen(result, c_strlen(result))
else: else:
OSError() OSError(OSLastError())
proc setCurrentDir*(newDir: string) {.inline, tags: [].} = proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
## Sets the `current working directory`:idx:; `EOS` is raised if ## Sets the `current working directory`:idx:; `EOS` is raised if
## `newDir` cannot been set. ## `newDir` cannot been set.
when defined(Windows): when defined(Windows):
when useWinUnicode: when useWinUnicode:
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError() if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError(OSLastError())
else: else:
if SetCurrentDirectoryA(newDir) == 0'i32: OSError() if SetCurrentDirectoryA(newDir) == 0'i32: OSError(OSLastError())
else: else:
if chdir(newDir) != 0'i32: OSError() if chdir(newDir) != 0'i32: OSError(OSLastError())
proc JoinPath*(head, tail: string): string {. proc JoinPath*(head, tail: string): string {.
noSideEffect, rtl, extern: "nos$1".} = noSideEffect, rtl, extern: "nos$1".} =
@ -571,23 +648,23 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
var res = newWideCString("", bufsize div 2) var res = newWideCString("", bufsize div 2)
var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused) var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
if L <= 0'i32 or L >= bufsize: if L <= 0'i32 or L >= bufsize:
OSError() OSError(OSLastError())
result = res$L result = res$L
else: else:
var unused: cstring var unused: cstring
result = newString(bufsize) result = newString(bufsize)
var L = GetFullPathNameA(filename, bufsize, result, unused) var L = GetFullPathNameA(filename, bufsize, result, unused)
if L <= 0'i32 or L >= bufsize: OSError() if L <= 0'i32 or L >= bufsize: OSError(OSLastError())
setLen(result, L) setLen(result, L)
elif defined(macosx) or defined(bsd): elif defined(macosx) or defined(bsd):
# On Mac OS X 10.5, realpath does not allocate the buffer on its own # On Mac OS X 10.5, realpath does not allocate the buffer on its own
var pathBuffer: cstring = newString(pathMax) var pathBuffer: cstring = newString(pathMax)
var resultBuffer = realpath(filename, pathBuffer) var resultBuffer = realpath(filename, pathBuffer)
if resultBuffer == nil: OSError() if resultBuffer == nil: OSError(OSLastError())
result = $resultBuffer result = $resultBuffer
else: else:
var res = realpath(filename, nil) var res = realpath(filename, nil)
if res == nil: OSError() if res == nil: OSError(OSLastError())
result = $res result = $res
c_free(res) c_free(res)
@ -677,6 +754,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
var f1 = OpenHandle(path1) var f1 = OpenHandle(path1)
var f2 = OpenHandle(path2) var f2 = OpenHandle(path2)
var lastErr: TOSErrorCode
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE: if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
@ -685,17 +763,21 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
fi1.nFileIndexHigh == fi2.nFileIndexHigh and fi1.nFileIndexHigh == fi2.nFileIndexHigh and
fi1.nFileIndexLow == fi2.nFileIndexLow fi1.nFileIndexLow == fi2.nFileIndexLow
else: success = false else:
else: success = false lastErr = OSLastError()
success = false
else:
lastErr = OSLastError()
success = false
discard CloseHandle(f1) discard CloseHandle(f1)
discard CloseHandle(f2) discard CloseHandle(f2)
if not success: OSError() if not success: OSError(lastErr)
else: else:
var a, b: TStat var a, b: TStat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32: if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
OSError() OSError(OSLastError())
else: else:
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
@ -738,17 +820,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
when useWinUnicode: when useWinUnicode:
let s = newWideCString(source) let s = newWideCString(source)
let d = newWideCString(dest) let d = newWideCString(dest)
if CopyFileW(s, d, 0'i32) == 0'i32: OSError() if CopyFileW(s, d, 0'i32) == 0'i32: OSError(OSLastError())
else: else:
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError() if CopyFileA(source, dest, 0'i32) == 0'i32: OSError(OSLastError())
else: else:
# generic version of copyFile which works for any platform: # generic version of copyFile which works for any platform:
const bufSize = 8000 # better for memory manager const bufSize = 8000 # better for memory manager
var d, s: TFile var d, s: TFile
if not open(s, source): OSError() if not open(s, source): OSError(OSLastError())
if not open(d, dest, fmWrite): if not open(d, dest, fmWrite):
close(s) close(s)
OSError() OSError(OSLastError())
var buf = alloc(bufsize) var buf = alloc(bufsize)
while True: while True:
var bytesread = readBuffer(s, buf, bufsize) var bytesread = readBuffer(s, buf, bufsize)
@ -758,7 +840,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
dealloc(buf) dealloc(buf)
close(s) close(s)
close(d) close(d)
OSError() OSError(OSLastError())
if bytesread != bufSize: break if bytesread != bufSize: break
dealloc(buf) dealloc(buf)
close(s) close(s)
@ -767,7 +849,8 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
tags: [FReadIO, FWriteIO].} = tags: [FReadIO, FWriteIO].} =
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised. ## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
if crename(source, dest) != 0'i32: OSError() if crename(source, dest) != 0'i32:
raise newException(EOS, $strerror(errno))
when not defined(ENOENT): when not defined(ENOENT):
var ENOENT {.importc, header: "<errno.h>".}: cint var ENOENT {.importc, header: "<errno.h>".}: cint
@ -775,7 +858,8 @@ when not defined(ENOENT):
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
## Removes the `file`. If this fails, `EOS` is raised. This does not fail ## Removes the `file`. If this fails, `EOS` is raised. This does not fail
## if the file never existed in the first place. ## if the file never existed in the first place.
if cremove(file) != 0'i32 and errno != ENOENT: OSError() if cremove(file) != 0'i32 and errno != ENOENT:
raise newException(EOS, $strerror(errno))
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
tags: [FExecIO].} = tags: [FExecIO].} =
@ -907,14 +991,14 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
indx = high(environment) indx = high(environment)
when defined(unix): when defined(unix):
if cputenv(environment[indx]) != 0'i32: if cputenv(environment[indx]) != 0'i32:
OSError() OSError(OSLastError())
else: else:
when useWinUnicode: when useWinUnicode:
var k = newWideCString(key) var k = newWideCString(key)
var v = newWideCString(val) var v = newWideCString(val)
if SetEnvironmentVariableW(k, v) == 0'i32: OSError() if SetEnvironmentVariableW(k, v) == 0'i32: OSError(OSLastError())
else: else:
if SetEnvironmentVariableA(key, val) == 0'i32: OSError() if SetEnvironmentVariableA(key, val) == 0'i32: OSError(OSLastError())
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} = iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
## Iterate over all `environments variables`:idx:. In the first component ## Iterate over all `environments variables`:idx:. In the first component
@ -1044,10 +1128,12 @@ proc rawRemoveDir(dir: string) =
wrapUnary(res, RemoveDirectoryW, dir) wrapUnary(res, RemoveDirectoryW, dir)
else: else:
var res = RemoveDirectoryA(dir) var res = RemoveDirectoryA(dir)
if res == 0'i32 and GetLastError() != 3'i32 and let lastError = OSLastError()
GetLastError() != 18'i32: OSError() if res == 0'i32 and lastError.int32 != 3'i32 and
lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
OSError(lastError)
else: else:
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError() if rmdir(dir) != 0'i32 and errno != ENOENT: OSError(OSLastError())
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
FWriteDir, FReadDir].} = FWriteDir, FReadDir].} =
@ -1065,14 +1151,14 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
proc rawCreateDir(dir: string) = proc rawCreateDir(dir: string) =
when defined(unix): when defined(unix):
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST: if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
OSError() OSError(OSLastError())
else: else:
when useWinUnicode: when useWinUnicode:
wrapUnary(res, CreateDirectoryW, dir) wrapUnary(res, CreateDirectoryW, dir)
else: else:
var res = CreateDirectoryA(dir) var res = CreateDirectoryA(dir)
if res == 0'i32 and GetLastError() != 183'i32: if res == 0'i32 and GetLastError() != 183'i32:
OSError() OSError(OSLastError())
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
## Creates the `directory`:idx: `dir`. ## Creates the `directory`:idx: `dir`.
@ -1213,7 +1299,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
## permission is available in any case. ## permission is available in any case.
when defined(posix): when defined(posix):
var a: TStat var a: TStat
if stat(filename, a) < 0'i32: OSError() if stat(filename, a) < 0'i32: OSError(OSLastError())
result = {} result = {}
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead) if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite) if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
@ -1231,7 +1317,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
wrapUnary(res, GetFileAttributesW, filename) wrapUnary(res, GetFileAttributesW, filename)
else: else:
var res = GetFileAttributesA(filename) var res = GetFileAttributesA(filename)
if res == -1'i32: OSError() if res == -1'i32: OSError(OSLastError())
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32: if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
fpOthersExec, fpOthersRead} fpOthersExec, fpOthersRead}
@ -1257,13 +1343,13 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
if fpOthersWrite in permissions: p = p or S_IWOTH if fpOthersWrite in permissions: p = p or S_IWOTH
if fpOthersExec in permissions: p = p or S_IXOTH if fpOthersExec in permissions: p = p or S_IXOTH
if chmod(filename, p) != 0: OSError() if chmod(filename, p) != 0: OSError(OSLastError())
else: else:
when useWinUnicode: when useWinUnicode:
wrapUnary(res, GetFileAttributesW, filename) wrapUnary(res, GetFileAttributesW, filename)
else: else:
var res = GetFileAttributesA(filename) var res = GetFileAttributesA(filename)
if res == -1'i32: OSError() if res == -1'i32: OSError(OSLastError())
if fpUserWrite in permissions: if fpUserWrite in permissions:
res = res and not FILE_ATTRIBUTE_READONLY res = res and not FILE_ATTRIBUTE_READONLY
else: else:
@ -1272,7 +1358,7 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
wrapBinary(res2, SetFileAttributesW, filename, res) wrapBinary(res2, SetFileAttributesW, filename, res)
else: else:
var res2 = SetFileAttributesA(filename, res) var res2 = SetFileAttributesA(filename, res)
if res2 == - 1'i32: OSError() if res2 == - 1'i32: OSError(OSLastError())
proc inclFilePermissions*(filename: string, proc inclFilePermissions*(filename: string,
permissions: set[TFilePermission]) {. permissions: set[TFilePermission]) {.
@ -1448,7 +1534,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
when defined(windows): when defined(windows):
var a: TWin32FindData var a: TWin32FindData
var resA = findfirstFile(file, a) var resA = findfirstFile(file, a)
if resA == -1: OSError() if resA == -1: OSError(OSLastError())
result = rdFileSize(a) result = rdFileSize(a)
findclose(resA) findclose(resA)
else: else:
@ -1456,7 +1542,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
if open(f, file): if open(f, file):
result = getFileSize(f) result = getFileSize(f)
close(f) close(f)
else: OSError() else: OSError(OSLastError())
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} = proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
## Searches for `exe` in the current working directory and then ## Searches for `exe` in the current working directory and then

View file

@ -370,6 +370,7 @@ when defined(Windows) and not defined(useNimRtl):
else: else:
success = winlean.CreateProcessA(nil, success = winlean.CreateProcessA(nil,
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo) cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
let lastError = OSLastError()
if poParentStreams notin options: if poParentStreams notin options:
FileClose(si.hStdInput) FileClose(si.hStdInput)
@ -379,7 +380,7 @@ when defined(Windows) and not defined(useNimRtl):
if e != nil: dealloc(e) if e != nil: dealloc(e)
dealloc(cmdl) dealloc(cmdl)
if success == 0: OSError() if success == 0: OSError(lastError)
# Close the handle now so anyone waiting is woken: # Close the handle now so anyone waiting is woken:
discard closeHandle(procInfo.hThread) discard closeHandle(procInfo.hThread)
result.FProcessHandle = procInfo.hProcess result.FProcessHandle = procInfo.hProcess
@ -450,7 +451,7 @@ when defined(Windows) and not defined(useNimRtl):
var res = winlean.CreateProcessA(nil, command, nil, nil, 0, var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo) NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
if res == 0: if res == 0:
OSError() OSError(OSLastError())
else: else:
Process = ProcInfo.hProcess Process = ProcInfo.hProcess
discard CloseHandle(ProcInfo.hThread) discard CloseHandle(ProcInfo.hThread)

View file

@ -231,7 +231,7 @@ when defined(ssl):
if err == 0: if err == 0:
raise newException(ESSL, "No error reported.") raise newException(ESSL, "No error reported.")
if err == -1: if err == -1:
OSError() OSError(OSLastError())
var errStr = ErrErrorString(err, nil) var errStr = ErrErrorString(err, nil)
raise newException(ESSL, $errStr) raise newException(ESSL, $errStr)
@ -347,24 +347,23 @@ proc SocketError*(socket: TSocket, err: int = -1, async = false) =
else: SSLError("Unknown Error") else: SSLError("Unknown Error")
if err == -1 and not (when defined(ssl): socket.isSSL else: false): if err == -1 and not (when defined(ssl): socket.isSSL else: false):
let lastError = OSLastError()
if async: if async:
when defined(windows): when defined(windows):
# TODO: Test on Windows if lastError.int32 == WSAEWOULDBLOCK:
var err = WSAGetLastError()
if err == WSAEWOULDBLOCK:
return return
else: OSError() else: OSError(lastError)
else: else:
if errno == EAGAIN or errno == EWOULDBLOCK: if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
return return
else: OSError() else: OSError(lastError)
else: OSError() else: OSError(lastError)
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} = proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
## Marks ``socket`` as accepting connections. ## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the ## ``Backlog`` specifies the maximum length of the
## queue of pending connections. ## queue of pending connections.
if listen(socket.fd, cint(backlog)) < 0'i32: OSError() if listen(socket.fd, cint(backlog)) < 0'i32: OSError(OSLastError())
proc invalidIp4(s: string) {.noreturn, noinline.} = proc invalidIp4(s: string) {.noreturn, noinline.} =
raise newException(EInvalidValue, "invalid ip4 address: " & s) raise newException(EInvalidValue, "invalid ip4 address: " & s)
@ -403,7 +402,7 @@ template gaiNim(a, p, h, list: expr): stmt =
var gaiResult = getAddrInfo(a, $p, addr(h), list) var gaiResult = getAddrInfo(a, $p, addr(h), list)
if gaiResult != 0'i32: if gaiResult != 0'i32:
when defined(windows): when defined(windows):
OSError() OSError(OSLastError())
else: else:
OSError($gai_strerror(gaiResult)) OSError($gai_strerror(gaiResult))
@ -423,7 +422,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY) name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)), if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
sizeof(name).TSockLen) < 0'i32: sizeof(name).TSockLen) < 0'i32:
OSError() OSError(OSLastError())
else: else:
var hints: TAddrInfo var hints: TAddrInfo
var aiList: ptr TAddrInfo = nil var aiList: ptr TAddrInfo = nil
@ -432,21 +431,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
hints.ai_protocol = toInt(IPPROTO_TCP) hints.ai_protocol = toInt(IPPROTO_TCP)
gaiNim(address, port, hints, aiList) gaiNim(address, port, hints, aiList)
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32: if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
OSError() OSError(OSLastError())
when false:
proc bindAddr*(socket: TSocket, port = TPort(0)) =
## binds a port number to a socket.
var name: Tsockaddr_in
when defined(Windows):
name.sin_family = int16(ord(AF_INET))
else:
name.sin_family = posix.AF_INET
name.sin_port = sockets.htons(int16(port))
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)),
sizeof(name).TSockLen) < 0'i32:
OSError()
proc getSockName*(socket: TSocket): TPort = proc getSockName*(socket: TSocket): TPort =
## returns the socket's associated port number. ## returns the socket's associated port number.
@ -460,7 +445,7 @@ proc getSockName*(socket: TSocket): TPort =
var namelen = sizeof(name).TSockLen var namelen = sizeof(name).TSockLen
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)), if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
addr(namelen)) == -1'i32: addr(namelen)) == -1'i32:
OSError() OSError(OSLastError())
result = TPort(sockets.ntohs(name.sin_port)) result = TPort(sockets.ntohs(name.sin_port))
template acceptAddrPlain(noClientRet, successRet: expr, template acceptAddrPlain(noClientRet, successRet: expr,
@ -472,26 +457,25 @@ template acceptAddrPlain(noClientRet, successRet: expr,
addr(addrLen)) addr(addrLen))
if sock < 0: if sock < 0:
# TODO: Test on Windows. let err = OSLastError()
when defined(windows): when defined(windows):
var err = WSAGetLastError() if err.int32 == WSAEINPROGRESS:
if err == WSAEINPROGRESS:
client = InvalidSocket client = InvalidSocket
address = "" address = ""
when noClientRet.int == -1: when noClientRet.int == -1:
return return
else: else:
return noClientRet return noClientRet
else: OSError() else: OSError(err)
else: else:
if errno == EAGAIN or errno == EWOULDBLOCK: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
client = InvalidSocket client = InvalidSocket
address = "" address = ""
when noClientRet.int == -1: when noClientRet.int == -1:
return return
else: else:
return noClientRet return noClientRet
else: OSError() else: OSError(err)
else: else:
client.fd = sock client.fd = sock
client.isBuffered = server.isBuffered client.isBuffered = server.isBuffered
@ -644,7 +628,7 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
var s = winlean.getservbyname(name, proto) var s = winlean.getservbyname(name, proto)
else: else:
var s = posix.getservbyname(name, proto) var s = posix.getservbyname(name, proto)
if s == nil: OSError() if s == nil: OSError(OSLastError())
result.name = $s.s_name result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases) result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port) result.port = TPort(s.s_port)
@ -656,7 +640,7 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
var s = winlean.getservbyport(ze(int16(port)).cint, proto) var s = winlean.getservbyport(ze(int16(port)).cint, proto)
else: else:
var s = posix.getservbyport(ze(int16(port)).cint, proto) var s = posix.getservbyport(ze(int16(port)).cint, proto)
if s == nil: OSError() if s == nil: OSError(OSLastError())
result.name = $s.s_name result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases) result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port) result.port = TPort(s.s_port)
@ -670,7 +654,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
when defined(windows): when defined(windows):
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
cint(sockets.AF_INET)) cint(sockets.AF_INET))
if s == nil: OSError() if s == nil: OSError(OSLastError())
else: else:
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen, var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
cint(posix.AF_INET)) cint(posix.AF_INET))
@ -687,7 +671,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
elif s.h_addrtype == posix.AF_INET6: elif s.h_addrtype == posix.AF_INET6:
result.addrType = AF_INET6 result.addrType = AF_INET6
else: else:
OSError("unknown h_addrtype") raise newException(EOS, "unknown h_addrtype")
result.addrList = cstringArrayToSeq(s.h_addr_list) result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length) result.length = int(s.h_length)
@ -697,7 +681,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
var s = winlean.gethostbyname(name) var s = winlean.gethostbyname(name)
else: else:
var s = posix.gethostbyname(name) var s = posix.gethostbyname(name)
if s == nil: OSError() if s == nil: OSError(OSLastError())
result.name = $s.h_name result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases) result.aliases = cstringArrayToSeq(s.h_aliases)
when defined(windows): when defined(windows):
@ -708,7 +692,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
elif s.h_addrtype == posix.AF_INET6: elif s.h_addrtype == posix.AF_INET6:
result.addrType = AF_INET6 result.addrType = AF_INET6
else: else:
OSError("unknown h_addrtype") raise newException(EOS, "unknown h_addrtype")
result.addrList = cstringArrayToSeq(s.h_addr_list) result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length) result.length = int(s.h_length)
@ -719,7 +703,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
var size = sizeof(res).TSockLen var size = sizeof(res).TSockLen
if getsockopt(socket.fd, cint(level), cint(optname), if getsockopt(socket.fd, cint(level), cint(optname),
addr(res), addr(size)) < 0'i32: addr(res), addr(size)) < 0'i32:
OSError() OSError(OSLastError())
result = int(res) result = int(res)
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {. proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
@ -728,7 +712,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
var value = cint(optval) var value = cint(optval)
if setsockopt(socket.fd, cint(level), cint(optname), addr(value), if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
sizeof(value).TSockLen) < 0'i32: sizeof(value).TSockLen) < 0'i32:
OSError() OSError(OSLastError())
proc connect*(socket: TSocket, address: string, port = TPort(0), proc connect*(socket: TSocket, address: string, port = TPort(0),
af: TDomain = AF_INET) {.tags: [FReadIO].} = af: TDomain = AF_INET) {.tags: [FReadIO].} =
@ -746,15 +730,17 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
gaiNim(address, port, hints, aiList) gaiNim(address, port, hints, aiList)
# try all possibilities: # try all possibilities:
var success = false var success = false
var lastError: TOSErrorCode
var it = aiList var it = aiList
while it != nil: while it != nil:
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32: if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
success = true success = true
break break
else: lastError = OSLastError()
it = it.ai_next it = it.ai_next
freeaddrinfo(aiList) freeaddrinfo(aiList)
if not success: OSError() if not success: OSError(lastError)
when defined(ssl): when defined(ssl):
if socket.isSSL: if socket.isSSL:
@ -807,6 +793,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
gaiNim(name, port, hints, aiList) gaiNim(name, port, hints, aiList)
# try all possibilities: # try all possibilities:
var success = false var success = false
var lastError: TOSErrorCode
var it = aiList var it = aiList
while it != nil: while it != nil:
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
@ -814,22 +801,21 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
success = true success = true
break break
else: else:
# TODO: Test on Windows. lastError = OSLastError()
when defined(windows): when defined(windows):
var err = WSAGetLastError()
# Windows EINTR doesn't behave same as POSIX. # Windows EINTR doesn't behave same as POSIX.
if err == WSAEWOULDBLOCK: if lastError.int32 == WSAEWOULDBLOCK:
success = true success = true
break break
else: else:
if errno == EINTR or errno == EINPROGRESS: if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
success = true success = true
break break
it = it.ai_next it = it.ai_next
freeaddrinfo(aiList) freeaddrinfo(aiList)
if not success: OSError() if not success: OSError(lastError)
when defined(ssl): when defined(ssl):
if socket.isSSL: if socket.isSSL:
socket.sslNoHandshake = true socket.sslNoHandshake = true
@ -1110,7 +1096,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
var s = @[socket] var s = @[socket]
var startTime = epochTime() var startTime = epochTime()
let selRet = select(s, timeout - int(waited * 1000.0)) let selRet = select(s, timeout - int(waited * 1000.0))
if selRet < 0: OSError() if selRet < 0: OSError(OSLastError())
if selRet != 1: if selRet != 1:
raise newException(ETimeout, "Call to '" & funcName & "' timed out.") raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
waited += (epochTime() - startTime) waited += (epochTime() - startTime)
@ -1259,14 +1245,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
var c: char var c: char
discard waitFor(socket, waited, timeout, 1, "readLine") discard waitFor(socket, waited, timeout, 1, "readLine")
var n = recv(socket, addr(c), 1) var n = recv(socket, addr(c), 1)
if n < 0: OSError() if n < 0: OSError(OSLastError())
elif n == 0: return elif n == 0: return
if c == '\r': if c == '\r':
discard waitFor(socket, waited, timeout, 1, "readLine") discard waitFor(socket, waited, timeout, 1, "readLine")
n = peekChar(socket, c) n = peekChar(socket, c)
if n > 0 and c == '\L': if n > 0 and c == '\L':
discard recv(socket, addr(c), 1) discard recv(socket, addr(c), 1)
elif n <= 0: OSError() elif n <= 0: OSError(OSLastError())
addNlIfEmpty() addNlIfEmpty()
return return
elif c == '\L': elif c == '\L':
@ -1326,6 +1312,7 @@ proc readLineAsync*(socket: TSocket,
while true: while true:
var c: char var c: char
var n = recv(socket, addr(c), 1) var n = recv(socket, addr(c), 1)
#echo(n)
if n < 0: if n < 0:
if line.len == 0: errorOrNone else: return ReadPartialLine if line.len == 0: errorOrNone else: return ReadPartialLine
elif n == 0: elif n == 0:
@ -1352,7 +1339,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
var pos = 0 var pos = 0
while true: while true:
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1) var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
if bytesRead == -1: OSError() if bytesRead == -1: OSError(OSLastError())
setLen(result.string, pos + bytesRead) setLen(result.string, pos + bytesRead)
if bytesRead != bufSize-1: break if bytesRead != bufSize-1: break
# increase capacity: # increase capacity:
@ -1364,7 +1351,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
while true: while true:
var bytesRead = recv(socket, cstring(buf), bufSize-1) var bytesRead = recv(socket, cstring(buf), bufSize-1)
# Error # Error
if bytesRead == -1: OSError() if bytesRead == -1: OSError(OSLastError())
buf[bytesRead] = '\0' # might not be necessary buf[bytesRead] = '\0' # might not be necessary
setLen(buf, bytesRead) setLen(buf, bytesRead)
@ -1421,16 +1408,15 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
else: SSLError("Unknown Error") else: SSLError("Unknown Error")
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false): if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
let err = OSLastError()
when defined(windows): when defined(windows):
# TODO: Test on Windows if err.int32 == WSAEWOULDBLOCK:
var err = WSAGetLastError()
if err == WSAEWOULDBLOCK:
return False return False
else: OSError() else: OSError(err)
else: else:
if errno == EAGAIN or errno == EWOULDBLOCK: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return False return False
else: OSError() else: OSError(err)
setLen(s.string, pos + bytesRead) setLen(s.string, pos + bytesRead)
if bytesRead != bufSize-1: break if bytesRead != bufSize-1: break
@ -1475,16 +1461,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
result = true result = true
var callRes = recvFrom(socket, data, length, address, port, flags) var callRes = recvFrom(socket, data, length, address, port, flags)
if callRes < 0: if callRes < 0:
let err = OSLastError()
when defined(windows): when defined(windows):
# TODO: Test on Windows if err.int32 == WSAEWOULDBLOCK:
var err = WSAGetLastError()
if err == WSAEWOULDBLOCK:
return False return False
else: OSError() else: OSError(err)
else: else:
if errno == EAGAIN or errno == EWOULDBLOCK: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return False return False
else: OSError() else: OSError(err)
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} = proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
## skips all the data that is pending for the socket ## skips all the data that is pending for the socket
@ -1531,7 +1516,7 @@ proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} =
if socket.isSSL: if socket.isSSL:
SSLError() SSLError()
OSError() OSError(OSLastError())
proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} = proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
## sends data to a non-blocking socket. ## sends data to a non-blocking socket.
@ -1561,16 +1546,15 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
else: else:
return return
if result == -1: if result == -1:
let err = OSLastError()
when defined(windows): when defined(windows):
var err = WSAGetLastError() if err.int32 == WSAEINPROGRESS:
# TODO: Test on windows.
if err == WSAEINPROGRESS:
return 0 return 0
else: OSError() else: OSError(err)
else: else:
if errno == EAGAIN or errno == EWOULDBLOCK: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return 0 return 0
else: OSError() else: OSError(err)
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} = proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
@ -1626,15 +1610,15 @@ proc setBlocking(s: TSocket, blocking: bool) =
when defined(Windows): when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1: if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
OSError() OSError(OSLastError())
else: # BSD sockets else: # BSD sockets
var x: int = fcntl(s.fd, F_GETFL, 0) var x: int = fcntl(s.fd, F_GETFL, 0)
if x == -1: if x == -1:
OSError() OSError(OSLastError())
else: else:
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
if fcntl(s.fd, F_SETFL, mode) == -1: if fcntl(s.fd, F_SETFL, mode) == -1:
OSError() OSError(OSLastError())
s.nonblocking = not blocking s.nonblocking = not blocking
proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int, proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
@ -1665,6 +1649,6 @@ proc getFD*(socket: TSocket): cint = return socket.fd
when defined(Windows): when defined(Windows):
var wsa: TWSADATA var wsa: TWSADATA
if WSAStartup(0x0101'i16, wsa) != 0: OSError() if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())

View file

@ -489,7 +489,7 @@ proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
proc FD_ZERO*(FDSet: var TFDSet) = proc FD_ZERO*(FDSet: var TFDSet) =
FDSet.fd_count = 0 FDSet.fd_count = 0
proc WSAStartup*(wVersionRequired: int16, WSData: var TWSAData): cint {. proc WSAStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {.
stdcall, importc: "WSAStartup", dynlib: ws2dll.} stdcall, importc: "WSAStartup", dynlib: ws2dll.}
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo, proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,