nim-chronos/chronos/handles.nim

117 lines
3.8 KiB
Nim
Raw Normal View History

2018-05-16 08:22:34 +00:00
#
# Chronos Handles
# (c) Copyright 2018-Present
2018-05-16 08:22:34 +00:00
# Status Research & Development GmbH
#
# Licensed under either of
# Apache License, version 2.0, (LICENSE-APACHEv2)
# MIT license (LICENSE-MIT)
import net, nativesockets, asyncloop
when defined(windows):
import winlean
const
2018-05-21 21:52:57 +00:00
asyncInvalidSocket* = AsyncFD(-1)
TCP_NODELAY* = 1
IPPROTO_TCP* = 6
2018-05-16 08:22:34 +00:00
else:
import posix
const
asyncInvalidSocket* = AsyncFD(posix.INVALID_SOCKET)
TCP_NODELAY* = 1
IPPROTO_TCP* = 6
2018-05-16 08:22:34 +00:00
proc setSocketBlocking*(s: SocketHandle, blocking: bool): bool =
## Sets blocking mode on socket.
when defined(windows):
result = true
var mode = clong(ord(not blocking))
if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
result = false
else:
result = true
var x: int = fcntl(s, F_GETFL, 0)
if x == -1:
result = false
else:
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
if fcntl(s, F_SETFL, mode) == -1:
result = false
2018-05-21 21:52:57 +00:00
proc setSockOpt*(socket: AsyncFD, level, optname, optval: int): bool =
2018-05-16 08:22:34 +00:00
## `setsockopt()` for integer options.
## Returns ``true`` on success, ``false`` on error.
result = true
var value = cint(optval)
if setsockopt(SocketHandle(socket), cint(level), cint(optname), addr(value),
sizeof(value).SockLen) < 0'i32:
result = false
proc setSockOpt*(socket: AsyncFD, level, optname: int, value: pointer,
valuelen: int): bool =
## `setsockopt()` for custom options (pointer and length).
## Returns ``true`` on success, ``false`` on error.
result = true
if setsockopt(SocketHandle(socket), cint(level), cint(optname), value,
Socklen(valuelen)) < 0'i32:
result = false
2018-05-21 21:52:57 +00:00
proc getSockOpt*(socket: AsyncFD, level, optname: int, value: var int): bool =
2018-05-16 08:22:34 +00:00
## `getsockopt()` for integer options.
## Returns ``true`` on success, ``false`` on error.
2018-05-16 08:22:34 +00:00
var res: cint
var size = sizeof(res).SockLen
result = true
if getsockopt(SocketHandle(socket), cint(level), cint(optname),
addr(res), addr(size)) < 0'i32:
return false
value = int(res)
proc getSockOpt*(socket: AsyncFD, level, optname: int, value: pointer,
valuelen: var int): bool =
## `getsockopt()` for custom options (pointer and length).
## Returns ``true`` on success, ``false`` on error.
var res: cint
result = true
if getsockopt(SocketHandle(socket), cint(level), cint(optname),
value, cast[ptr Socklen](addr valuelen)) < 0'i32:
result = false
2018-05-21 21:52:57 +00:00
proc getSocketError*(socket: AsyncFD, err: var int): bool =
## Recover error code associated with socket handle ``socket``.
2018-05-16 08:22:34 +00:00
if not getSockOpt(socket, cint(SOL_SOCKET), cint(SO_ERROR), err):
result = false
else:
result = true
proc createAsyncSocket*(domain: Domain, sockType: SockType,
protocol: Protocol): AsyncFD =
## Creates new asynchronous socket.
## Returns ``asyncInvalidSocket`` on error.
let handle = createNativeSocket(domain, sockType, protocol)
if handle == osInvalidSocket:
return asyncInvalidSocket
if not setSocketBlocking(handle, false):
close(handle)
return asyncInvalidSocket
when defined(macosx) and not defined(nimdoc):
2018-05-21 21:52:57 +00:00
if not setSockOpt(AsyncFD(handle), SOL_SOCKET, SO_NOSIGPIPE, 1):
2018-05-16 08:22:34 +00:00
close(handle)
return asyncInvalidSocket
result = AsyncFD(handle)
register(result)
proc wrapAsyncSocket*(sock: SocketHandle): AsyncFD =
2018-05-21 21:52:57 +00:00
## Wraps socket to asynchronous socket handle.
2018-05-16 08:22:34 +00:00
## Return ``asyncInvalidSocket`` on error.
if not setSocketBlocking(sock, false):
close(sock)
return asyncInvalidSocket
when defined(macosx) and not defined(nimdoc):
2018-05-21 21:52:57 +00:00
if not setSockOpt(AsyncFD(sock), SOL_SOCKET, SO_NOSIGPIPE, 1):
2018-05-16 08:22:34 +00:00
close(sock)
return asyncInvalidSocket
result = AsyncFD(sock)
register(result)