# # # Nim's Runtime Library # (c) Copyright 2015 Dominik Picheta # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module implements a high-level asynchronous sockets API based on the ## asynchronous dispatcher defined in the ``asyncdispatch`` module. ## ## SSL ## --- ## ## SSL can be enabled by compiling with the ``-d:ssl`` flag. ## ## You must create a new SSL context with the ``newContext`` function defined ## in the ``net`` module. You may then call ``wrapSocket`` on your socket using ## the newly created SSL context to get an SSL socket. ## ## Examples ## -------- ## ## Chat server ## ^^^^^^^^^^^ ## ## The following example demonstrates a simple chat server. ## ## .. code-block::nim ## ## import asyncnet, asyncdispatch ## ## var clients {.threadvar.}: seq[AsyncSocket] ## ## proc processClient(client: AsyncSocket) {.async.} = ## while true: ## let line = await client.recvLine() ## for c in clients: ## await c.send(line & "\c\L") ## ## proc serve() {.async.} = ## clients = @[] ## var server = newAsyncSocket() ## server.bindAddr(Port(12345)) ## server.listen() ## ## while true: ## let client = await server.accept() ## clients.add client ## ## asyncCheck processClient(client) ## ## asyncCheck serve() ## runForever() ## import asyncdispatch import rawsockets import net import os export SOBool when defined(ssl): import openssl type # TODO: I would prefer to just do: # AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work. AsyncSocketDesc = object fd: SocketHandle closed: bool ## determines whether this socket has been closed case isBuffered: bool ## determines whether this socket is buffered. of true: buffer: array[0..BufferSize, char] currPos: int # current index in buffer bufLen: int # current length of buffer of false: nil case isSsl: bool of true: when defined(ssl): sslHandle: SslPtr sslContext: SslContext bioIn: BIO bioOut: BIO of false: nil AsyncSocket* = ref AsyncSocketDesc {.deprecated: [PAsyncSocket: AsyncSocket].} # TODO: Save AF, domain etc info and reuse it in procs which need it like connect. proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket = ## Creates a new ``AsyncSocket`` based on the supplied params. assert fd != osInvalidSocket.TAsyncFD new(result) result.fd = fd.SocketHandle result.isBuffered = isBuff if isBuff: result.currPos = 0 proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = ## Creates a new asynchronous socket. ## ## This procedure will also create a brand new file descriptor for ## this socket. result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered) proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket = ## Creates a new asynchronous socket. ## ## This procedure will also create a brand new file descriptor for ## this socket. result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered) when defined(ssl): proc getSslError(handle: SslPtr, err: cint): cint = assert err < 0 var ret = SSLGetError(handle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: return ret of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: return ret of SSL_ERROR_WANT_X509_LOOKUP: raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: raiseSSLError() else: raiseSSLError("Unknown Error") proc sendPendingSslData(socket: AsyncSocket, flags: set[SocketFlag]) {.async.} = let len = bioCtrlPending(socket.bioOut) if len > 0: var data = newStringOfCap(len) let read = bioRead(socket.bioOut, addr data[0], len) assert read != 0 if read < 0: raiseSslError() data.setLen(read) await socket.fd.TAsyncFd.send(data, flags) proc appeaseSsl(soc
#
#
# Nim's Runtime Library
# (c) Copyright 2017 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
type
Allocator* = ptr object {.inheritable.}
alloc*: proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall.}
dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.}
realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.}
var
currentAllocator {.threadvar.}: Allocator
proc getCurrentAllocator*(): Allocator =
result = currentAllocator
proc setCurrentAllocator*(a: Allocator) =
currentAllocator = a
proc alloc*(size: int; alignment: int = 8): pointer =
let a = getCurrentAllocator()
result = a.alloc(a, size, alignment)
proc dealloc*(p: pointer; size: int) =
let a = getCurrentAllocator()
a.dealloc(a, p, size)
proc realloc*(p: pointer; oldSize, newSize: int): pointer =
let a = getCurrentAllocator()
result = a.realloc(a, p, oldSize, newSize)