Merge pull request #1653 from def-/name-fixes-2

Fix some deprecation warnings caused by renames
This commit is contained in:
Andreas Rumpf
2014-11-13 22:09:02 +01:00
12 changed files with 237 additions and 236 deletions

View File

@@ -9,7 +9,7 @@
{.deadCodeElim:on.}
from posix import TSocketHandle
from posix import SocketHandle
const
EPOLLIN* = 0x00000001
@@ -58,7 +58,7 @@ proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1",
## Same as epoll_create but with an FLAGS parameter. The unused SIZE
## parameter has been dropped.
proc epoll_ctl*(epfd: cint; op: cint; fd: cint | TSocketHandle; event: ptr epoll_event): cint {.
proc epoll_ctl*(epfd: cint; op: cint; fd: cint | SocketHandle; event: ptr epoll_event): cint {.
importc: "epoll_ctl", header: "<sys/epoll.h>".}
## Manipulate an epoll instance "epfd". Returns 0 in case of success,
## -1 in case of error ( the "errno" variable will contain the

View File

@@ -242,7 +242,7 @@ proc echoOriginalStackTrace[T](future: Future[T]) =
proc read*[T](future: Future[T]): T =
## Retrieves the value of ``future``. Future must be finished otherwise
## this function will fail with a ``EInvalidValue`` exception.
## this function will fail with a ``ValueError`` exception.
##
## If the result of the future is an error then that error will be raised.
if future.finished:
@@ -808,13 +808,13 @@ else:
TAsyncFD* = distinct cint
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
PData* = ref object of PObject
PData* = ref object of RootRef
fd: TAsyncFD
readCBs: seq[TCallback]
writeCBs: seq[TCallback]
PDispatcher* = ref object of PDispatcherBase
selector: PSelector
selector: Selector
proc `==`*(x, y: TAsyncFD): bool {.borrow.}
@@ -828,7 +828,7 @@ else:
if gDisp.isNil: gDisp = newDispatcher()
result = gDisp
proc update(fd: TAsyncFD, events: set[TEvent]) =
proc update(fd: TAsyncFD, events: set[Event]) =
let p = getGlobalDispatcher()
assert fd.SocketHandle in p.selector
discard p.selector.update(fd.SocketHandle, events)
@@ -836,16 +836,16 @@ else:
proc register*(fd: TAsyncFD) =
let p = getGlobalDispatcher()
var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
p.selector.register(fd.SocketHandle, {}, data.PObject)
p.selector.register(fd.SocketHandle, {}, data.RootRef)
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false)
register(result)
proc newAsyncRawSocket*(domain: TDomain = AF_INET,
typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP): TAsyncFD =
proc newAsyncRawSocket*(domain: Domain = AF_INET,
typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false)
register(result)
@@ -861,14 +861,14 @@ else:
proc addRead*(fd: TAsyncFD, cb: TCallback) =
let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector:
raise newException(EInvalidValue, "File descriptor not registered.")
raise newException(ValueError, "File descriptor not registered.")
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
update(fd, p.selector[fd.SocketHandle].events + {EvRead})
proc addWrite*(fd: TAsyncFD, cb: TCallback) =
let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector:
raise newException(EInvalidValue, "File descriptor not registered.")
raise newException(ValueError, "File descriptor not registered.")
p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
@@ -898,7 +898,7 @@ else:
data.writeCBs.add(cb)
if info.key in p.selector:
var newEvents: set[TEvent]
var newEvents: set[Event]
if data.readCBs.len != 0: newEvents = {EvRead}
if data.writeCBs.len != 0: newEvents = newEvents + {EvWrite}
if newEvents != info.key.events:
@@ -910,7 +910,7 @@ else:
processTimers(p)
proc connect*(socket: TAsyncFD, address: string, port: TPort,
proc connect*(socket: TAsyncFD, address: string, port: Port,
af = AF_INET): Future[void] =
var retFuture = newFuture[void]("connect")
@@ -921,7 +921,7 @@ else:
var aiList = getAddrInfo(address, port, af)
var success = false
var lastError: TOSErrorCode
var lastError: OSErrorCode
var it = aiList
while it != nil:
var ret = connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen)
@@ -942,11 +942,11 @@ else:
dealloc(aiList)
if not success:
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
return retFuture
proc recv*(socket: TAsyncFD, size: int,
flags = {TSocketFlags.SafeDisconn}): Future[string] =
flags = {SocketFlag.SafeDisconn}): Future[string] =
var retFuture = newFuture[string]("recv")
var readBuffer = newString(size)
@@ -962,7 +962,7 @@ else:
if flags.isDisconnectionError(lastError):
retFuture.complete("")
else:
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
else:
result = false # We still want this callback to be called.
elif res == 0:
@@ -977,7 +977,7 @@ else:
return retFuture
proc send*(socket: TAsyncFD, data: string,
flags = {TSocketFlags.SafeDisconn}): Future[void] =
flags = {SocketFlag.SafeDisconn}): Future[void] =
var retFuture = newFuture[void]("send")
var written = 0
@@ -994,7 +994,7 @@ else:
if flags.isDisconnectionError(lastError):
retFuture.complete()
else:
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
else:
result = false # We still want this callback to be called.
else:
@@ -1008,7 +1008,7 @@ else:
addWrite(socket, cb)
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}):
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: TAsyncFD]] =
var retFuture = newFuture[tuple[address: string,
client: TAsyncFD]]("acceptAddr")
@@ -1027,7 +1027,7 @@ else:
if flags.isDisconnectionError(lastError):
return false
else:
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
else:
register(client.TAsyncFD)
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.TAsyncFD))
@@ -1302,7 +1302,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
outerProcBody.add(closureIterator)
# -> createCb(retFuture)
var cbName = newIdentNode("cb")
#var cbName = newIdentNode("cb")
var procCb = newCall(bindSym"createCb", retFutureSym, iteratorNameSym,
newStrLitNode(prc[0].getName))
outerProcBody.add procCb
@@ -1372,7 +1372,7 @@ proc runForever*() =
while true:
poll()
proc waitFor*[T](fut: PFuture[T]): T =
proc waitFor*[T](fut: Future[T]): T =
## **Blocks** the current thread until the specified future completes.
while not fut.finished:
poll()

View File

@@ -180,10 +180,10 @@ proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
if result.socket == invalidSocket: raiseOSError(osLastError())
result.socket.setBlocking(false)
proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSocket =
## Wraps an already initialized ``TSocket`` into a PAsyncSocket.
proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): AsyncSocket =
## Wraps an already initialized ``TSocket`` into a AsyncSocket.
## This is useful if you want to use an already connected TSocket as an
## asynchronous PAsyncSocket in asyncio's event loop.
## asynchronous AsyncSocket in asyncio's event loop.
##
## ``state`` may be overriden, i.e. if ``sock`` is not connected it should be
## adjusted properly. By default it will be assumed that the socket is
@@ -201,7 +201,7 @@ proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSo
## SockUDPBound Socket is a UDP socket which is listening for data.
## ================ ================================================================
##
## **Warning**: If ``state`` is set incorrectly the resulting ``PAsyncSocket``
## **Warning**: If ``state`` is set incorrectly the resulting ``AsyncSocket``
## object may not work properly.
##
## **Note**: This will set ``sock`` to be non-blocking.
@@ -213,8 +213,8 @@ proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSo
proc asyncSockHandleRead(h: RootRef) =
when defined(ssl):
if PAsyncSocket(h).socket.isSSL and not
PAsyncSocket(h).socket.gotHandshake:
if AsyncSocket(h).socket.isSSL and not
AsyncSocket(h).socket.gotHandshake:
return
if AsyncSocket(h).info != SockListening:
@@ -226,8 +226,8 @@ proc asyncSockHandleRead(h: RootRef) =
proc close*(sock: AsyncSocket) {.gcsafe.}
proc asyncSockHandleWrite(h: RootRef) =
when defined(ssl):
if PAsyncSocket(h).socket.isSSL and not
PAsyncSocket(h).socket.gotHandshake:
if AsyncSocket(h).socket.isSSL and not
AsyncSocket(h).socket.gotHandshake:
return
if AsyncSocket(h).info == SockConnecting:
@@ -266,17 +266,17 @@ proc asyncSockHandleWrite(h: RootRef) =
when defined(ssl):
proc asyncSockDoHandshake(h: PObject) {.gcsafe.} =
if PAsyncSocket(h).socket.isSSL and not
PAsyncSocket(h).socket.gotHandshake:
if PAsyncSocket(h).sslNeedAccept:
if AsyncSocket(h).socket.isSSL and not
AsyncSocket(h).socket.gotHandshake:
if AsyncSocket(h).sslNeedAccept:
var d = ""
let ret = PAsyncSocket(h).socket.acceptAddrSSL(PAsyncSocket(h).socket, d)
let ret = AsyncSocket(h).socket.acceptAddrSSL(AsyncSocket(h).socket, d)
assert ret != AcceptNoClient
if ret == AcceptSuccess:
PAsyncSocket(h).info = SockConnected
AsyncSocket(h).info = SockConnected
else:
# handshake will set socket's ``sslNoHandshake`` field.
discard PAsyncSocket(h).socket.handshake()
discard AsyncSocket(h).socket.handshake()
proc asyncSockTask(h: RootRef) =
@@ -453,7 +453,7 @@ proc setHandleWrite*(s: AsyncSocket,
##
## To remove this event you should use the ``delHandleWrite`` function.
## It is advised to use that function instead of just setting the event to
## ``proc (s: PAsyncSocket) = nil`` as that would mean that that function
## ``proc (s: AsyncSocket) = nil`` as that would mean that that function
## would be called constantly.
s.deleg.mode = fmReadWrite
s.handleWrite = handleWrite
@@ -655,10 +655,10 @@ proc len*(disp: Dispatcher): int =
when isMainModule:
proc testConnect(s: PAsyncSocket, no: int) =
proc testConnect(s: AsyncSocket, no: int) =
echo("Connected! " & $no)
proc testRead(s: PAsyncSocket, no: int) =
proc testRead(s: AsyncSocket, no: int) =
echo("Reading! " & $no)
var data = ""
if not s.readLine(data): return
@@ -668,15 +668,15 @@ when isMainModule:
echo(data)
echo("Finished reading! " & $no)
proc testAccept(s: PAsyncSocket, disp: PDispatcher, no: int) =
proc testAccept(s: AsyncSocket, disp: PDispatcher, no: int) =
echo("Accepting client! " & $no)
var client: PAsyncSocket
var client: AsyncSocket
new(client)
var address = ""
s.acceptAddr(client, address)
echo("Accepted ", address)
client.handleRead =
proc (s: PAsyncSocket) =
proc (s: AsyncSocket) =
testRead(s, 2)
disp.register(client)
@@ -686,16 +686,16 @@ when isMainModule:
var s = asyncSocket()
s.connect("amber.tenthbit.net", TPort(6667))
s.handleConnect =
proc (s: PAsyncSocket) =
proc (s: AsyncSocket) =
testConnect(s, 1)
s.handleRead =
proc (s: PAsyncSocket) =
proc (s: AsyncSocket) =
testRead(s, 1)
d.register(s)
var server = asyncSocket()
server.handleAccept =
proc (s: PAsyncSocket) =
proc (s: AsyncSocket) =
testAccept(s, d, 78)
server.bindAddr(TPort(5555))
server.listen()

View File

@@ -67,7 +67,7 @@ when defined(ssl):
type
# TODO: I would prefer to just do:
# PAsyncSocket* {.borrow: `.`.} = distinct PSocket. But that doesn't work.
# AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
AsyncSocketDesc = object
fd*: SocketHandle
closed*: bool ## determines whether this socket has been closed
@@ -91,7 +91,7 @@ type
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket =
proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket =
assert fd != osInvalidSocket.TAsyncFD
new(result)
result.fd = fd.SocketHandle
@@ -99,12 +99,12 @@ proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket =
if isBuff:
result.currPos = 0
proc newAsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP, buffered = true): PAsyncSocket =
proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
## Creates a new asynchronous socket.
result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): PAsyncSocket =
proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
## Creates a new asynchronous socket.
result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
@@ -126,7 +126,7 @@ when defined(ssl):
else: raiseSSLError("Unknown Error")
proc sendPendingSslData(socket: AsyncSocket,
flags: set[TSocketFlags]) {.async.} =
flags: set[SocketFlag]) {.async.} =
let len = bioCtrlPending(socket.bioOut)
if len > 0:
var data = newStringOfCap(len)
@@ -137,7 +137,7 @@ when defined(ssl):
data.setLen(read)
await socket.fd.TAsyncFd.send(data, flags)
proc appeaseSsl(socket: AsyncSocket, flags: set[TSocketFlags],
proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
sslError: cint) {.async.} =
case sslError
of SSL_ERROR_WANT_WRITE:
@@ -150,7 +150,7 @@ when defined(ssl):
else:
raiseSSLError("Cannot appease SSL.")
template sslLoop(socket: AsyncSocket, flags: set[TSocketFlags],
template sslLoop(socket: AsyncSocket, flags: set[SocketFlag],
op: expr) =
var opResult {.inject.} = -1.cint
while opResult < 0:
@@ -162,21 +162,21 @@ when defined(ssl):
let err = getSslError(socket.sslHandle, opResult.cint)
yield appeaseSsl(socket, flags, err.cint)
proc connect*(socket: PAsyncSocket, address: string, port: TPort,
proc connect*(socket: AsyncSocket, address: string, port: Port,
af = AF_INET) {.async.} =
## Connects ``socket`` to server at ``address:port``.
##
## Returns a ``Future`` which will complete when the connection succeeds
## or an error occurs.
await connect(socket.fd.TAsyncFD, address, port, af)
let flags = {TSocketFlags.SafeDisconn}
if socket.isSsl:
when defined(ssl):
let flags = {SocketFlag.SafeDisconn}
sslSetConnectState(socket.sslHandle)
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
proc readInto(buf: cstring, size: int, socket: PAsyncSocket,
flags: set[TSocketFlags]): Future[int] {.async.} =
proc readInto(buf: cstring, size: int, socket: AsyncSocket,
flags: set[SocketFlag]): Future[int] {.async.} =
if socket.isSsl:
when defined(ssl):
# SSL mode.
@@ -190,14 +190,14 @@ proc readInto(buf: cstring, size: int, socket: PAsyncSocket,
# Not in SSL mode.
result = data.len
proc readIntoBuf(socket: PAsyncSocket,
flags: set[TSocketFlags]): Future[int] {.async.} =
proc readIntoBuf(socket: AsyncSocket,
flags: set[SocketFlag]): Future[int] {.async.} =
result = await readInto(addr socket.buffer[0], BufferSize, socket, flags)
socket.currPos = 0
socket.bufLen = result
proc recv*(socket: PAsyncSocket, size: int,
flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} =
proc recv*(socket: AsyncSocket, size: int,
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
## Reads **up to** ``size`` bytes from ``socket``.
##
## For buffered sockets this function will attempt to read all the requested
@@ -218,7 +218,7 @@ proc recv*(socket: PAsyncSocket, size: int,
let originalBufPos = socket.currPos
if socket.bufLen == 0:
let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek})
let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
if res == 0:
result.setLen(0)
return
@@ -226,10 +226,10 @@ proc recv*(socket: PAsyncSocket, size: int,
var read = 0
while read < size:
if socket.currPos >= socket.bufLen:
if TSocketFlags.Peek in flags:
if SocketFlag.Peek in flags:
# We don't want to get another buffer if we're peeking.
break
let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek})
let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
if res == 0:
break
@@ -238,7 +238,7 @@ proc recv*(socket: PAsyncSocket, size: int,
read.inc(chunk)
socket.currPos.inc(chunk)
if TSocketFlags.Peek in flags:
if SocketFlag.Peek in flags:
# Restore old buffer cursor position.
socket.currPos = originalBufPos
result.setLen(read)
@@ -247,8 +247,8 @@ proc recv*(socket: PAsyncSocket, size: int,
let read = await readInto(addr result[0], size, socket, flags)
result.setLen(read)
proc send*(socket: PAsyncSocket, data: string,
flags = {TSocketFlags.SafeDisconn}) {.async.} =
proc send*(socket: AsyncSocket, data: string,
flags = {SocketFlag.SafeDisconn}) {.async.} =
## Sends ``data`` to ``socket``. The returned future will complete once all
## data has been sent.
assert socket != nil
@@ -261,12 +261,12 @@ proc send*(socket: PAsyncSocket, data: string,
else:
await send(socket.fd.TAsyncFD, data, flags)
proc acceptAddr*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}):
Future[tuple[address: string, client: PAsyncSocket]] =
proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncSocket]] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
var retFuture = newFuture[tuple[address: string, client: PAsyncSocket]]("asyncnet.acceptAddr")
var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
var fut = acceptAddr(socket.fd.TAsyncFD, flags)
fut.callback =
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
@@ -279,15 +279,15 @@ proc acceptAddr*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}):
retFuture.complete(resultTup)
return retFuture
proc accept*(socket: PAsyncSocket,
flags = {TSocketFlags.SafeDisconn}): Future[PAsyncSocket] =
proc accept*(socket: AsyncSocket,
flags = {SocketFlag.SafeDisconn}): Future[AsyncSocket] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection.
## The future will complete when the connection is successfully accepted.
var retFut = newFuture[PAsyncSocket]("asyncnet.accept")
var retFut = newFuture[AsyncSocket]("asyncnet.accept")
var fut = acceptAddr(socket, flags)
fut.callback =
proc (future: Future[tuple[address: string, client: PAsyncSocket]]) =
proc (future: Future[tuple[address: string, client: AsyncSocket]]) =
assert future.finished
if future.failed:
retFut.fail(future.readError)
@@ -295,8 +295,8 @@ proc accept*(socket: PAsyncSocket,
retFut.complete(future.read.client)
return retFut
proc recvLine*(socket: PAsyncSocket,
flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} =
proc recvLine*(socket: AsyncSocket,
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
## Reads a line of data from ``socket``. Returned future will complete once
## a full line is read or an error occurs.
##
@@ -317,7 +317,7 @@ proc recvLine*(socket: PAsyncSocket,
template addNLIfEmpty(): stmt =
if result.len == 0:
result.add("\c\L")
assert TSocketFlags.Peek notin flags ## TODO:
assert SocketFlag.Peek notin flags ## TODO:
if socket.isBuffered:
result = ""
if socket.bufLen == 0:
@@ -365,7 +365,7 @@ proc recvLine*(socket: PAsyncSocket,
return
add(result.string, c)
proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the
## queue of pending connections.
@@ -373,7 +373,7 @@ proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].}
## Raises an EOS error upon failure.
if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError())
proc bindAddr*(socket: PAsyncSocket, port = Port(0), address = "") {.
proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
tags: [ReadIOEffect].} =
## Binds ``address``:``port`` to the socket.
##
@@ -397,7 +397,7 @@ proc bindAddr*(socket: PAsyncSocket, port = Port(0), address = "") {.
raiseOSError(osLastError())
dealloc(aiList)
proc close*(socket: PAsyncSocket) =
proc close*(socket: AsyncSocket) =
## Closes the socket.
socket.fd.TAsyncFD.closeSocket()
when defined(ssl):
@@ -419,7 +419,7 @@ when defined(ssl):
## prone to security vulnerabilities.
socket.isSsl = true
socket.sslContext = ctx
socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
if socket.sslHandle == nil:
raiseSslError()
@@ -449,7 +449,7 @@ when isMainModule:
when test == HighClient:
proc main() {.async.} =
var sock = newAsyncSocket()
await sock.connect("irc.freenode.net", TPort(6667))
await sock.connect("irc.freenode.net", Port(6667))
while true:
let line = await sock.recvLine()
if line == "":
@@ -460,7 +460,7 @@ when isMainModule:
asyncCheck main()
elif test == LowClient:
var sock = newAsyncSocket()
var f = connect(sock, "irc.freenode.net", TPort(6667))
var f = connect(sock, "irc.freenode.net", Port(6667))
f.callback =
proc (future: Future[void]) =
echo("Connected in future!")
@@ -471,9 +471,9 @@ when isMainModule:
echo("Read ", future.read.len, ": ", future.read.repr)
elif test == LowServer:
var sock = newAsyncSocket()
sock.bindAddr(TPort(6667))
sock.bindAddr(Port(6667))
sock.listen()
proc onAccept(future: Future[PAsyncSocket]) =
proc onAccept(future: Future[AsyncSocket]) =
let client = future.read
echo "Accepted ", client.fd.cint
var t = send(client, "test\c\L")

View File

@@ -18,17 +18,17 @@ type
{.deprecated: [TQueue: Queue].}
proc initQueue*[T](initialSize=4): TQueue[T] =
proc initQueue*[T](initialSize=4): Queue[T] =
## creates a new queue. `initialSize` needs to be a power of 2.
assert isPowerOfTwo(initialSize)
result.mask = initialSize-1
newSeq(result.data, initialSize)
proc len*[T](q: TQueue[T]): int =
proc len*[T](q: Queue[T]): int =
## returns the number of elements of `q`.
result = q.count
iterator items*[T](q: TQueue[T]): T =
iterator items*[T](q: Queue[T]): T =
## yields every element of `q`.
var i = q.rd
var c = q.count
@@ -37,7 +37,7 @@ iterator items*[T](q: TQueue[T]): T =
yield q.data[i]
i = (i + 1) and q.mask
proc add*[T](q: var TQueue[T], item: T) =
proc add*[T](q: var Queue[T], item: T) =
## adds an `item` to the end of the queue `q`.
var cap = q.mask+1
if q.count >= cap:
@@ -55,18 +55,18 @@ proc add*[T](q: var TQueue[T], item: T) =
q.data[q.wr] = item
q.wr = (q.wr + 1) and q.mask
proc enqueue*[T](q: var TQueue[T], item: T) =
proc enqueue*[T](q: var Queue[T], item: T) =
## alias for the ``add`` operation.
add(q, item)
proc dequeue*[T](q: var TQueue[T]): T =
proc dequeue*[T](q: var Queue[T]): T =
## removes and returns the first element of the queue `q`.
assert q.count > 0
dec q.count
result = q.data[q.rd]
q.rd = (q.rd + 1) and q.mask
proc `$`*[T](q: TQueue[T]): string =
proc `$`*[T](q: Queue[T]): string =
## turns a queue into its string representation.
result = "["
for x in items(q):

View File

@@ -57,7 +57,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
s.prevProcKernel = procKernel
s.prevProcUser = procUser
elif defined(linux):
proc fscanf(c: TFile, frmt: cstring) {.varargs, importc,
proc fscanf(c: File, frmt: cstring) {.varargs, importc,
header: "<stdio.h>".}
var f = open("/proc/loadavg")

View File

@@ -101,7 +101,7 @@ type
body: string]
Proxy* = ref object
url*: TUrl
url*: Url
auth*: string
ProtocolError* = object of IOError ## exception that is raised when server
@@ -130,7 +130,7 @@ proc fileError(msg: string) =
e.msg = msg
raise e
proc parseChunks(s: TSocket, timeout: int): string =
proc parseChunks(s: Socket, timeout: int): string =
result = ""
var ri = 0
while true:
@@ -168,7 +168,7 @@ proc parseChunks(s: TSocket, timeout: int): string =
# Trailer headers will only be sent if the request specifies that we want
# them: http://tools.ietf.org/html/rfc2616#section-3.6.1
proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string =
proc parseBody(s: Socket, headers: StringTableRef, timeout: int): string =
result = ""
if headers["Transfer-Encoding"] == "chunked":
result = parseChunks(s, timeout)
@@ -203,7 +203,7 @@ proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string =
buf.setLen(r)
result.add(buf)
proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse =
proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
var parsedStatus = false
var linei = 0
var fullyRead = false
@@ -272,20 +272,20 @@ type
{.deprecated: [THttpMethod: HttpMethod].}
when not defined(ssl):
type PSSLContext = ref object
let defaultSSLContext: PSSLContext = nil
type SSLContext = ref object
let defaultSSLContext: SSLContext = nil
else:
let defaultSSLContext = newContext(verifyMode = CVerifyNone)
proc newProxy*(url: string, auth = ""): PProxy =
proc newProxy*(url: string, auth = ""): Proxy =
## Constructs a new ``TProxy`` object.
result = PProxy(url: parseUrl(url), auth: auth)
result = Proxy(url: parseUrl(url), auth: auth)
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
body = "",
sslContext: PSSLContext = defaultSSLContext,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): TResponse =
proxy: Proxy = nil): Response =
## | Requests ``url`` with the specified ``httpMethod``.
## | Extra headers can be specified and must be seperated by ``\c\L``
## | An optional timeout can be specified in miliseconds, if reading from the
@@ -310,16 +310,16 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
var s = socket()
if s == invalidSocket: raiseOSError(osLastError())
var port = sockets.TPort(80)
var port = sockets.Port(80)
if r.scheme == "https":
when defined(ssl):
sslContext.wrapSocket(s)
port = sockets.TPort(443)
port = sockets.Port(443)
else:
raise newException(EHttpRequestErr,
raise newException(HttpRequestError,
"SSL support is not available. Cannot connect over SSL.")
if r.port != "":
port = sockets.TPort(r.port.parseInt)
port = sockets.Port(r.port.parseInt)
if timeout == -1:
s.connect(r.hostname, port)
@@ -338,7 +338,7 @@ proc redirection(status: string): bool =
if status.startsWith(i):
return true
proc getNewLocation(lastUrl: string, headers: PStringTable): string =
proc getNewLocation(lastUrl: string, headers: StringTableRef): string =
result = headers["Location"]
if result == "": httpError("location header expected")
# Relative URLs. (Not part of the spec, but soon will be.)
@@ -348,10 +348,10 @@ proc getNewLocation(lastUrl: string, headers: PStringTable): string =
result = origParsed.hostname & "/" & r.path
proc get*(url: string, extraHeaders = "", maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): TResponse =
## | GETs the ``url`` and returns a ``TResponse`` object
proxy: Proxy = nil): Response =
## | GETs the ``url`` and returns a ``Response`` object
## | This proc also handles redirection
## | Extra headers can be specified and must be separated by ``\c\L``.
## | An optional timeout can be specified in miliseconds, if reading from the
@@ -367,9 +367,9 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5,
lastUrl = redirectTo
proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): string =
proxy: Proxy = nil): string =
## | GETs the body and returns it as a string.
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
## | Extra headers can be specified and must be separated by ``\c\L``.
@@ -378,16 +378,16 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
proxy)
if r.status[0] in {'4','5'}:
raise newException(EHTTPRequestErr, r.status)
raise newException(HttpRequestError, r.status)
else:
return r.body
proc post*(url: string, extraHeaders = "", body = "",
maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): TResponse =
## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object.
proxy: Proxy = nil): Response =
## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
## | This proc adds the necessary Content-Length header.
## | This proc also handles redirection.
## | Extra headers can be specified and must be separated by ``\c\L``.
@@ -407,9 +407,9 @@ proc post*(url: string, extraHeaders = "", body = "",
proc postContent*(url: string, extraHeaders = "", body = "",
maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): string =
proxy: Proxy = nil): string =
## | POSTs ``body`` to ``url`` and returns the response's body as a string
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
## | Extra headers can be specified and must be separated by ``\c\L``.
@@ -418,18 +418,18 @@ proc postContent*(url: string, extraHeaders = "", body = "",
var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
userAgent, proxy)
if r.status[0] in {'4','5'}:
raise newException(EHTTPRequestErr, r.status)
raise newException(HttpRequestError, r.status)
else:
return r.body
proc downloadFile*(url: string, outputFilename: string,
sslContext: PSSLContext = defaultSSLContext,
sslContext: SSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil) =
proxy: Proxy = nil) =
## | Downloads ``url`` and saves it to ``outputFilename``
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var f: TFile
var f: File
if open(f, outputFilename, fmWrite):
f.write(getContent(url, sslContext = sslContext, timeout = timeout,
userAgent = userAgent, proxy = proxy))
@@ -437,8 +437,8 @@ proc downloadFile*(url: string, outputFilename: string,
else:
fileError("Unable to open file")
proc generateHeaders(r: TURL, httpMethod: THttpMethod,
headers: PStringTable): string =
proc generateHeaders(r: Url, httpMethod: HttpMethod,
headers: StringTableRef): string =
result = substr($httpMethod, len("http"))
# TODO: Proxies
result.add(" /" & r.path & r.query)
@@ -455,7 +455,7 @@ type
AsyncHttpClient* = ref object
socket: AsyncSocket
connected: bool
currentURL: TURL ## Where we are currently connected.
currentURL: Url ## Where we are currently connected.
headers*: StringTableRef
maxRedirects: int
userAgent: string
@@ -466,7 +466,7 @@ type
proc newAsyncHttpClient*(userAgent = defUserAgent,
maxRedirects = 5, sslContext = defaultSslContext): AsyncHttpClient =
## Creates a new PAsyncHttpClient instance.
## Creates a new AsyncHttpClient instance.
##
## ``userAgent`` specifies the user agent that will be used when making
## requests.
@@ -488,7 +488,7 @@ proc close*(client: AsyncHttpClient) =
client.socket.close()
client.connected = false
proc recvFull(socket: PAsyncSocket, size: int): Future[string] {.async.} =
proc recvFull(socket: AsyncSocket, size: int): Future[string] {.async.} =
## Ensures that all the data requested is read and returned.
result = ""
while true:
@@ -497,7 +497,7 @@ proc recvFull(socket: PAsyncSocket, size: int): Future[string] {.async.} =
if data == "": break # We've been disconnected.
result.add data
proc parseChunks(client: PAsyncHttpClient): Future[string] {.async.} =
proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
result = ""
var ri = 0
while true:
@@ -529,8 +529,8 @@ proc parseChunks(client: PAsyncHttpClient): Future[string] {.async.} =
# Trailer headers will only be sent if the request specifies that we want
# them: http://tools.ietf.org/html/rfc2616#section-3.6.1
proc parseBody(client: PAsyncHttpClient,
headers: PStringTable): Future[string] {.async.} =
proc parseBody(client: AsyncHttpClient,
headers: StringTableRef): Future[string] {.async.} =
result = ""
if headers["Transfer-Encoding"] == "chunked":
result = await parseChunks(client)
@@ -559,8 +559,8 @@ proc parseBody(client: PAsyncHttpClient,
if buf == "": break
result.add(buf)
proc parseResponse(client: PAsyncHttpClient,
getBody: bool): Future[TResponse] {.async.} =
proc parseResponse(client: AsyncHttpClient,
getBody: bool): Future[Response] {.async.} =
var parsedStatus = false
var linei = 0
var fullyRead = false
@@ -607,34 +607,34 @@ proc parseResponse(client: PAsyncHttpClient,
else:
result.body = ""
proc newConnection(client: PAsyncHttpClient, url: TURL) {.async.} =
proc newConnection(client: AsyncHttpClient, url: Url) {.async.} =
if client.currentURL.hostname != url.hostname or
client.currentURL.scheme != url.scheme:
if client.connected: client.close()
client.socket = newAsyncSocket()
# TODO: I should be able to write 'net.TPort' here...
# TODO: I should be able to write 'net.Port' here...
let port =
if url.port == "":
if url.scheme.toLower() == "https":
rawsockets.TPort(443)
rawsockets.Port(443)
else:
rawsockets.TPort(80)
else: rawsockets.TPort(url.port.parseInt)
rawsockets.Port(80)
else: rawsockets.Port(url.port.parseInt)
if url.scheme.toLower() == "https":
when defined(ssl):
client.sslContext.wrapSocket(client.socket)
else:
raise newException(EHttpRequestErr,
raise newException(HttpRequestError,
"SSL support is not available. Cannot connect over SSL.")
await client.socket.connect(url.hostname, port)
client.currentURL = url
client.connected = true
proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
body = ""): Future[TResponse] {.async.} =
proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
body = ""): Future[Response] {.async.} =
## Connects to the hostname specified by the URL and performs a request
## using the method specified.
##
@@ -657,7 +657,7 @@ proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET,
result = await parseResponse(client, httpMethod != httpHEAD)
proc get*(client: PAsyncHttpClient, url: string): Future[TResponse] {.async.} =
proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
## Connects to the hostname specified by the URL and performs a GET request.
##
## This procedure will follow redirects up to a maximum number of redirects

View File

@@ -15,12 +15,12 @@
## import strutils, sockets, httpserver
##
## var counter = 0
## proc handleRequest(client: TSocket, path, query: string): bool {.procvar.} =
## proc handleRequest(client: Socket, path, query: string): bool {.procvar.} =
## inc(counter)
## client.send("Hello for the $#th time." % $counter & wwwNL)
## return false # do not stop processing
##
## run(handleRequest, TPort(80))
## run(handleRequest, Port(80))
##
import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio
@@ -31,14 +31,14 @@ const
# --------------- output messages --------------------------------------------
proc sendTextContentType(client: TSocket) =
proc sendTextContentType(client: Socket) =
send(client, "Content-type: text/html" & wwwNL)
send(client, wwwNL)
proc sendStatus(client: TSocket, status: string) =
proc sendStatus(client: Socket, status: string) =
send(client, "HTTP/1.1 " & status & wwwNL)
proc badRequest(client: TSocket) =
proc badRequest(client: Socket) =
# Inform the client that a request it has made has a problem.
send(client, "HTTP/1.1 400 Bad Request" & wwwNL)
sendTextContentType(client)
@@ -46,18 +46,18 @@ proc badRequest(client: TSocket) =
"such as a POST without a Content-Length.</p>" & wwwNL)
when false:
proc cannotExec(client: TSocket) =
proc cannotExec(client: Socket) =
send(client, "HTTP/1.1 500 Internal Server Error" & wwwNL)
sendTextContentType(client)
send(client, "<P>Error prohibited CGI execution." & wwwNL)
proc headers(client: TSocket, filename: string) =
proc headers(client: Socket, filename: string) =
# XXX could use filename to determine file type
send(client, "HTTP/1.1 200 OK" & wwwNL)
send(client, ServerSig)
sendTextContentType(client)
proc notFound(client: TSocket) =
proc notFound(client: Socket) =
send(client, "HTTP/1.1 404 NOT FOUND" & wwwNL)
send(client, ServerSig)
sendTextContentType(client)
@@ -67,7 +67,7 @@ proc notFound(client: TSocket) =
send(client, "is unavailable or nonexistent.</p>" & wwwNL)
send(client, "</body></html>" & wwwNL)
proc unimplemented(client: TSocket) =
proc unimplemented(client: Socket) =
send(client, "HTTP/1.1 501 Method Not Implemented" & wwwNL)
send(client, ServerSig)
sendTextContentType(client)
@@ -79,11 +79,11 @@ proc unimplemented(client: TSocket) =
# ----------------- file serving ---------------------------------------------
when false:
proc discardHeaders(client: TSocket) = skip(client)
proc discardHeaders(client: Socket) = skip(client)
proc serveFile*(client: TSocket, filename: string) =
proc serveFile*(client: Socket, filename: string) =
## serves a file to the client.
var f: TFile
var f: File
if open(f, filename):
headers(client, filename)
const bufSize = 8000 # != 8K might be good for memory manager
@@ -108,7 +108,7 @@ when false:
type
TRequestMethod = enum reqGet, reqPost
proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
proc executeCgi(client: Socket, path, query: string, meth: TRequestMethod) =
var env = newStringTable(modeCaseInsensitive)
var contentLength = -1
case meth
@@ -158,7 +158,7 @@ when false:
# --------------- Server Setup -----------------------------------------------
proc acceptRequest(client: TSocket) =
proc acceptRequest(client: Socket) =
var cgi = false
var query = ""
var buf = TaintedString""
@@ -208,21 +208,21 @@ when false:
executeCgi(client, path, query, meth)
type
TServer* = object of TObject ## contains the current server state
socket: TSocket
port: TPort
client*: TSocket ## the socket to write the file data to
reqMethod*: string ## Request method. GET or POST.
path*, query*: string ## path and query the client requested
headers*: PStringTable ## headers with which the client made the request
body*: string ## only set with POST requests
ip*: string ## ip address of the requesting client
TServer* = object of RootObj ## contains the current server state
socket: Socket
port: Port
client*: Socket ## the socket to write the file data to
reqMethod*: string ## Request method. GET or POST.
path*, query*: string ## path and query the client requested
headers*: StringTableRef ## headers with which the client made the request
body*: string ## only set with POST requests
ip*: string ## ip address of the requesting client
PAsyncHTTPServer* = ref TAsyncHTTPServer
TAsyncHTTPServer = object of TServer
asyncSocket: PAsyncSocket
asyncSocket: AsyncSocket
proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
## creates a new server at port `port`. If ``port == 0`` a free port is
## acquired that can be accessed later by the ``port`` proc.
s.socket = socket(AF_INET)
@@ -232,7 +232,7 @@ proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
bindAddr(s.socket, port)
listen(s.socket)
if port == TPort(0):
if port == Port(0):
s.port = getSockName(s.socket)
else:
s.port = port
@@ -243,13 +243,13 @@ proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
s.query = ""
s.headers = {:}.newStringTable()
proc port*(s: var TServer): TPort =
proc port*(s: var TServer): Port =
## get the port number the server has acquired.
result = s.port
proc next*(s: var TServer) =
## proceed to the first/next request.
var client: TSocket
var client: Socket
new(client)
var ip: string
acceptAddr(s.socket, client, ip)
@@ -358,9 +358,9 @@ proc close*(s: TServer) =
## closes the server (and the socket the server uses).
close(s.socket)
proc run*(handleRequest: proc (client: TSocket,
proc run*(handleRequest: proc (client: Socket,
path, query: string): bool {.closure.},
port = TPort(80)) =
port = Port(80)) =
## encapsulates the server object and main loop
var s: TServer
open(s, port)
@@ -375,7 +375,7 @@ proc run*(handleRequest: proc (client: TSocket,
proc nextAsync(s: PAsyncHTTPServer) =
## proceed to the first/next request.
var client: TSocket
var client: Socket
new(client)
var ip: string
acceptAddr(getSocket(s.asyncSocket), client, ip)
@@ -474,16 +474,16 @@ proc nextAsync(s: PAsyncHTTPServer) =
s.query = ""
s.path = data.substr(i, last-1)
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: Socket,
path, query: string): bool {.closure, gcsafe.},
port = TPort(80), address = "",
port = Port(80), address = "",
reuseAddr = false): PAsyncHTTPServer =
## Creates an Asynchronous HTTP server at ``port``.
var capturedRet: PAsyncHTTPServer
new(capturedRet)
capturedRet.asyncSocket = asyncSocket()
capturedRet.asyncSocket.handleAccept =
proc (s: PAsyncSocket) =
proc (s: AsyncSocket) =
nextAsync(capturedRet)
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
capturedRet.query)
@@ -493,7 +493,7 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
capturedRet.asyncSocket.bindAddr(port, address)
capturedRet.asyncSocket.listen()
if port == TPort(0):
if port == Port(0):
capturedRet.port = getSockName(capturedRet.asyncSocket)
else:
capturedRet.port = port
@@ -506,8 +506,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
capturedRet.headers = {:}.newStringTable()
result = capturedRet
proc register*(d: PDispatcher, s: PAsyncHTTPServer) =
## Registers a ``PAsyncHTTPServer`` with a ``PDispatcher``.
proc register*(d: Dispatcher, s: PAsyncHTTPServer) =
## Registers a ``PAsyncHTTPServer`` with a ``Dispatcher``.
d.register(s.asyncSocket)
proc close*(h: PAsyncHTTPServer) =
@@ -518,7 +518,7 @@ when isMainModule:
var counter = 0
var s: TServer
open(s, TPort(0))
open(s, Port(0))
echo("httpserver running on port ", s.port)
while true:
next(s)

View File

@@ -196,7 +196,6 @@ when not defined(JS):
## computes x to power raised of y.
# C procs:
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".}
proc rand(): cint {.importc: "rand", header: "<stdlib.h>".}
@@ -331,6 +330,8 @@ proc standardDeviation*(s: RunningStat): float =
{.pop.}
when isMainModule and not defined(JS):
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
# Verifies random seed initialization.
let seed = gettime(nil)
randomize(seed)

View File

@@ -54,8 +54,8 @@ type
when defined(ssl):
case isSsl*: bool
of true:
sslHandle*: PSSL
sslContext*: PSSLContext
sslHandle*: SSLPtr
sslContext*: SSLContext
sslNoHandshake*: bool # True if needs handshake.
sslHasPeekChar*: bool
sslPeekChar*: char
@@ -147,11 +147,11 @@ when defined(ssl):
raise newException(SSLError, $errStr)
# http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
proc loadCertificates(ctx: PSSL_CTX, certFile, keyFile: string) =
proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
if certFile != "" and not existsFile(certFile):
raise newException(system.EIO, "Certificate file could not be found: " & certFile)
raise newException(system.IOError, "Certificate file could not be found: " & certFile)
if keyFile != "" and not existsFile(keyFile):
raise newException(system.EIO, "Key file could not be found: " & keyFile)
raise newException(system.IOError, "Key file could not be found: " & keyFile)
if certFile != "":
var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
@@ -168,7 +168,7 @@ when defined(ssl):
raiseSSLError("Verification of private key file failed.")
proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
certFile = "", keyFile = ""): PSSLContext =
certFile = "", keyFile = ""): SSLContext =
## Creates an SSL context.
##
## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1
@@ -184,7 +184,7 @@ when defined(ssl):
## path, a server socket will most likely not work without these.
## Certificates can be generated using the following command:
## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
var newCTX: PSSL_CTX
var newCTX: SSL_CTX
case protVersion
of protSSLv23:
newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
@@ -210,9 +210,9 @@ when defined(ssl):
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
newCTX.loadCertificates(certFile, keyFile)
return PSSLContext(newCTX)
return SSLContext(newCTX)
proc wrapSocket*(ctx: PSSLContext, socket: PSocket) =
proc wrapSocket*(ctx: SSLContext, socket: Socket) =
## Wraps a socket in an SSL context. This function effectively turns
## ``socket`` into an SSL socket.
##
@@ -221,7 +221,7 @@ when defined(ssl):
socket.isSSL = true
socket.sslContext = ctx
socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
socket.sslNoHandshake = false
socket.sslHasPeekChar = false
if socket.sslHandle == nil:
@@ -350,9 +350,9 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
address = $inet_ntoa(sockAddress.sin_addr)
when false: #defined(ssl):
proc acceptAddrSSL*(server: PSocket, client: var PSocket,
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): TSSLAcceptResult {.
tags: [FReadIO].} =
tags: [ReadIOEffect].} =
## This procedure should only be used for non-blocking **SSL** sockets.
## It will immediately return with one of the following values:
##
@@ -480,7 +480,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
socketError(socket, ret)
when defined(ssl):
proc handshake*(socket: PSocket): bool {.tags: [FReadIO, FWriteIO].} =
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
## This proc needs to be called on a socket after it connects. This is
## only applicable when using ``connectAsync``.
## This proc performs the SSL handshake.
@@ -510,7 +510,7 @@ when defined(ssl):
else:
raiseSSLError("Socket is not an SSL socket.")
proc gotHandshake*(socket: PSocket): bool =
proc gotHandshake*(socket: Socket): bool =
## Determines whether a handshake has occurred between a client (``socket``)
## and the server that ``socket`` is connected to.
##

View File

@@ -54,12 +54,12 @@ type
{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].}
proc debugSend(smtp: TSMTP, cmd: string) =
proc debugSend(smtp: Smtp, cmd: string) =
if smtp.debug:
echo("C:" & cmd)
smtp.sock.send(cmd)
proc debugRecv(smtp: var TSMTP): TaintedString =
proc debugRecv(smtp: var Smtp): TaintedString =
var line = TaintedString""
smtp.sock.readLine(line)
@@ -67,11 +67,11 @@ proc debugRecv(smtp: var TSMTP): TaintedString =
echo("S:" & line.string)
return line
proc quitExcpt(smtp: TSMTP, msg: string) =
proc quitExcpt(smtp: Smtp, msg: string) =
smtp.debugSend("QUIT")
raise newException(EInvalidReply, msg)
raise newException(ReplyError, msg)
proc checkReply(smtp: var TSMTP, reply: string) =
proc checkReply(smtp: var Smtp, reply: string) =
var line = smtp.debugRecv()
if not line.string.startswith(reply):
quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
@@ -86,9 +86,9 @@ else:
proc connect*(address: string, port = Port(25),
ssl = false, debug = false,
sslContext = defaultSSLContext): TSMTP =
sslContext = defaultSSLContext): Smtp =
## Establishes a connection with a SMTP server.
## May fail with EInvalidReply or with a socket error.
## May fail with ReplyError or with a socket error.
result.sock = newSocket()
if ssl:
when compiledWithSsl:
@@ -103,10 +103,10 @@ proc connect*(address: string, port = Port(25),
result.debugSend("HELO " & address & "\c\L")
result.checkReply("250")
proc auth*(smtp: var TSMTP, username, password: string) =
proc auth*(smtp: var Smtp, username, password: string) =
## Sends an AUTH command to the server to login as the `username`
## using `password`.
## May fail with EInvalidReply.
## May fail with ReplyError.
smtp.debugSend("AUTH LOGIN\c\L")
smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:"
@@ -117,11 +117,11 @@ proc auth*(smtp: var TSMTP, username, password: string) =
smtp.debugSend(encode(password) & "\c\L")
smtp.checkReply("235") # Check whether the authentification was successful.
proc sendmail*(smtp: var TSMTP, fromaddr: string,
proc sendmail*(smtp: var Smtp, fromaddr: string,
toaddrs: seq[string], msg: string) =
## Sends `msg` from `fromaddr` to `toaddr`.
## Messages may be formed using ``createMessage`` by converting the
## TMessage into a string.
## Message into a string.
smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L")
smtp.checkReply("250")
@@ -136,13 +136,13 @@ proc sendmail*(smtp: var TSMTP, fromaddr: string,
smtp.debugSend(".\c\L")
smtp.checkReply("250")
proc close*(smtp: TSMTP) =
proc close*(smtp: Smtp) =
## Disconnects from the SMTP server and closes the socket.
smtp.debugSend("QUIT\c\L")
smtp.sock.close()
proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
otherHeaders: openarray[tuple[name, value: string]]): TMessage =
otherHeaders: openarray[tuple[name, value: string]]): Message =
## Creates a new MIME compliant message.
result.msgTo = mTo
result.msgCc = mCc
@@ -153,7 +153,7 @@ proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
result.msgOtherHeaders[n] = v
proc createMessage*(mSubject, mBody: string, mTo,
mCc: seq[string] = @[]): TMessage =
mCc: seq[string] = @[]): Message =
## Alternate version of the above.
result.msgTo = mTo
result.msgCc = mCc
@@ -161,8 +161,8 @@ proc createMessage*(mSubject, mBody: string, mTo,
result.msgBody = mBody
result.msgOtherHeaders = newStringTable()
proc `$`*(msg: TMessage): string =
## stringify for ``TMessage``.
proc `$`*(msg: Message): string =
## stringify for ``Message``.
result = ""
if msg.msgTo.len() > 0:
result = "TO: " & msg.msgTo.join(", ") & "\c\L"
@@ -192,7 +192,7 @@ proc newAsyncSmtp*(address: string, port: Port, useSsl = false,
raise newException(ESystem,
"SMTP module compiled without SSL support")
proc quitExcpt(smtp: AsyncSmtp, msg: string): PFuture[void] =
proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
var retFuture = newFuture[void]()
var sendFut = smtp.sock.send("QUIT")
sendFut.callback =
@@ -208,7 +208,7 @@ proc checkReply(smtp: AsyncSmtp, reply: string) {.async.} =
proc connect*(smtp: AsyncSmtp) {.async.} =
## Establishes a connection with a SMTP server.
## May fail with EInvalidReply or with a socket error.
## May fail with ReplyError or with a socket error.
await smtp.sock.connect(smtp.address, smtp.port)
await smtp.checkReply("220")
@@ -218,7 +218,7 @@ proc connect*(smtp: AsyncSmtp) {.async.} =
proc auth*(smtp: AsyncSmtp, username, password: string) {.async.} =
## Sends an AUTH command to the server to login as the `username`
## using `password`.
## May fail with EInvalidReply.
## May fail with ReplyError.
await smtp.sock.send("AUTH LOGIN\c\L")
await smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:"
@@ -233,7 +233,7 @@ proc sendMail*(smtp: AsyncSmtp, fromAddr: string,
toAddrs: seq[string], msg: string) {.async.} =
## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``.
## Messages may be formed using ``createMessage`` by converting the
## TMessage into a string.
## Message into a string.
await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L")
await smtp.checkReply("250")

View File

@@ -55,7 +55,7 @@ when defined(ssl):
SSLProtVersion* = enum
protSSLv2, protSSLv3, protTLSv1, protSSLv23
SSLContext* = distinct PSSLCTX
SSLContext* = distinct SSLCTX
SSLAcceptResult* = enum
AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
@@ -79,7 +79,7 @@ type
when defined(ssl):
case isSsl: bool
of true:
sslHandle: PSSL
sslHandle: SSLPtr
sslContext: SSLContext
sslNoHandshake: bool # True if needs handshake.
sslHasPeekChar: bool
@@ -254,21 +254,21 @@ when defined(ssl):
proc raiseSSLError(s = "") =
if s != "":
raise newException(ESSL, s)
raise newException(SSLError, s)
let err = ErrPeekLastError()
if err == 0:
raise newException(ESSL, "No error reported.")
raise newException(SSLError, "No error reported.")
if err == -1:
raiseOSError(osLastError())
var errStr = ErrErrorString(err, nil)
raise newException(ESSL, $errStr)
raise newException(SSLError, $errStr)
# http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
proc loadCertificates(ctx: PSSL_CTX, certFile, keyFile: string) =
proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
if certFile != "" and not existsFile(certFile):
raise newException(system.EIO, "Certificate file could not be found: " & certFile)
raise newException(system.IOError, "Certificate file could not be found: " & certFile)
if keyFile != "" and not existsFile(keyFile):
raise newException(system.EIO, "Key file could not be found: " & keyFile)
raise newException(system.IOError, "Key file could not be found: " & keyFile)
if certFile != "":
var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
@@ -285,7 +285,7 @@ when defined(ssl):
raiseSslError("Verification of private key file failed.")
proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
certFile = "", keyFile = ""): PSSLContext =
certFile = "", keyFile = ""): SSLContext =
## Creates an SSL context.
##
## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are
@@ -301,7 +301,7 @@ when defined(ssl):
## path, a server socket will most likely not work without these.
## Certificates can be generated using the following command:
## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
var newCTX: PSSL_CTX
var newCTX: SSL_CTX
case protVersion
of protSSLv23:
newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
@@ -327,9 +327,9 @@ when defined(ssl):
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
newCTX.loadCertificates(certFile, keyFile)
return PSSLContext(newCTX)
return SSLContext(newCTX)
proc wrapSocket*(ctx: PSSLContext, socket: TSocket) =
proc wrapSocket*(ctx: SSLContext, socket: Socket) =
## Wraps a socket in an SSL context. This function effectively turns
## ``socket`` into an SSL socket.
##
@@ -338,7 +338,7 @@ when defined(ssl):
socket.isSSL = true
socket.sslContext = ctx
socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext))
socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
socket.sslNoHandshake = false
socket.sslHasPeekChar = false
if socket.sslHandle == nil:
@@ -561,9 +561,9 @@ proc setBlocking*(s: Socket, blocking: bool) {.tags: [], gcsafe.}
## Sets blocking mode on socket
when defined(ssl):
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
address: var string): TSSLAcceptResult {.
tags: [FReadIO].} =
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): SSLAcceptResult {.
tags: [ReadIOEffect].} =
## This procedure should only be used for non-blocking **SSL** sockets.
## It will immediately return with one of the following values:
##
@@ -886,7 +886,7 @@ proc connectAsync*(socket: Socket, name: string, port = Port(0),
socket.sslNoHandshake = true
when defined(ssl):
proc handshake*(socket: TSocket): bool {.tags: [FReadIO, FWriteIO].} =
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
## This proc needs to be called on a socket after it connects. This is
## only applicable when using ``connectAsync``.
## This proc performs the SSL handshake.
@@ -916,7 +916,7 @@ when defined(ssl):
else:
raiseSslError("Socket is not an SSL socket.")
proc gotHandshake*(socket: TSocket): bool =
proc gotHandshake*(socket: Socket): bool =
## Determines whether a handshake has occurred between a client (``socket``)
## and the server that ``socket`` is connected to.
##
@@ -1689,7 +1689,7 @@ proc setBlocking(s: Socket, blocking: bool) =
raiseOSError(osLastError())
s.nonblocking = not blocking
discard """ proc setReuseAddr*(s: TSocket) =
discard """ proc setReuseAddr*(s: Socket) =
var blah: int = 1
var mode = SO_REUSEADDR
if setsockopt(s.fd, SOL_SOCKET, mode, addr blah, TSOcklen(sizeof(int))) == -1: