Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
6cbd5bb017
3 changed files with 244 additions and 159 deletions
|
|
@ -50,6 +50,18 @@
|
||||||
## any of the functions a url with the ``https`` schema, for example:
|
## any of the functions a url with the ``https`` schema, for example:
|
||||||
## ``https://github.com/``, you also have to compile with ``ssl`` defined like so:
|
## ``https://github.com/``, you also have to compile with ``ssl`` defined like so:
|
||||||
## ``nimrod c -d:ssl ...``.
|
## ``nimrod c -d:ssl ...``.
|
||||||
|
##
|
||||||
|
## Timeouts
|
||||||
|
## ========
|
||||||
|
## Currently all functions support an optional timeout, by default the timeout is set to
|
||||||
|
## `-1` which means that the function will never time out. The timeout is
|
||||||
|
## measured in miliseconds, once it is set any call on a socket which may
|
||||||
|
## block will be susceptible to this timeout, however please remember that the
|
||||||
|
## function as a whole can take longer than the specified timeout, only
|
||||||
|
## individual internal calls on the socket are affected. In practice this means
|
||||||
|
## that as long as the server is sending data an exception will not be raised,
|
||||||
|
## if however data does not reach client within the specified timeout an ETimeout
|
||||||
|
## exception will then be raised.
|
||||||
|
|
||||||
import sockets, strutils, parseurl, parseutils, strtabs
|
import sockets, strutils, parseurl, parseutils, strtabs
|
||||||
|
|
||||||
|
|
@ -68,6 +80,8 @@ type
|
||||||
## and ``postContent`` proc,
|
## and ``postContent`` proc,
|
||||||
## when the server returns an error
|
## when the server returns an error
|
||||||
|
|
||||||
|
const defUserAgent* = "Nimrod httpclient/0.1"
|
||||||
|
|
||||||
proc httpError(msg: string) =
|
proc httpError(msg: string) =
|
||||||
var e: ref EInvalidProtocol
|
var e: ref EInvalidProtocol
|
||||||
new(e)
|
new(e)
|
||||||
|
|
@ -80,13 +94,13 @@ proc fileError(msg: string) =
|
||||||
e.msg = msg
|
e.msg = msg
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc parseChunks(s: TSocket): string =
|
proc parseChunks(s: TSocket, timeout: int): string =
|
||||||
result = ""
|
result = ""
|
||||||
var ri = 0
|
var ri = 0
|
||||||
while true:
|
while true:
|
||||||
var chunkSizeStr = ""
|
var chunkSizeStr = ""
|
||||||
var chunkSize = 0
|
var chunkSize = 0
|
||||||
if s.recvLine(chunkSizeStr):
|
if s.recvLine(chunkSizeStr, timeout):
|
||||||
var i = 0
|
var i = 0
|
||||||
if chunkSizeStr == "":
|
if chunkSizeStr == "":
|
||||||
httpError("Server terminated connection prematurely")
|
httpError("Server terminated connection prematurely")
|
||||||
|
|
@ -111,18 +125,17 @@ proc parseChunks(s: TSocket): string =
|
||||||
result.setLen(ri+chunkSize)
|
result.setLen(ri+chunkSize)
|
||||||
var bytesRead = 0
|
var bytesRead = 0
|
||||||
while bytesRead != chunkSize:
|
while bytesRead != chunkSize:
|
||||||
let ret = recv(s, addr(result[ri]), chunkSize-bytesRead)
|
let ret = recv(s, addr(result[ri]), chunkSize-bytesRead, timeout)
|
||||||
ri += ret
|
ri += ret
|
||||||
bytesRead += ret
|
bytesRead += ret
|
||||||
s.skip(2) # Skip \c\L
|
s.skip(2, timeout) # Skip \c\L
|
||||||
# Trailer headers will only be sent if the request specifies that we want
|
# Trailer headers will only be sent if the request specifies that we want
|
||||||
# them: http://tools.ietf.org/html/rfc2616#section-3.6.1
|
# them: http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||||
|
|
||||||
proc parseBody(s: TSocket,
|
proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string =
|
||||||
headers: PStringTable): string =
|
|
||||||
result = ""
|
result = ""
|
||||||
if headers["Transfer-Encoding"] == "chunked":
|
if headers["Transfer-Encoding"] == "chunked":
|
||||||
result = parseChunks(s)
|
result = parseChunks(s, timeout)
|
||||||
else:
|
else:
|
||||||
# -REGION- Content-Length
|
# -REGION- Content-Length
|
||||||
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
|
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
|
||||||
|
|
@ -133,7 +146,7 @@ proc parseBody(s: TSocket,
|
||||||
var received = 0
|
var received = 0
|
||||||
while true:
|
while true:
|
||||||
if received >= length: break
|
if received >= length: break
|
||||||
let r = s.recv(addr(result[received]), length-received)
|
let r = s.recv(addr(result[received]), length-received, timeout)
|
||||||
if r == 0: break
|
if r == 0: break
|
||||||
received += r
|
received += r
|
||||||
if received != length:
|
if received != length:
|
||||||
|
|
@ -148,12 +161,12 @@ proc parseBody(s: TSocket,
|
||||||
var buf = ""
|
var buf = ""
|
||||||
while True:
|
while True:
|
||||||
buf = newString(4000)
|
buf = newString(4000)
|
||||||
let r = s.recv(addr(buf[0]), 4000)
|
let r = s.recv(addr(buf[0]), 4000, timeout)
|
||||||
if r == 0: break
|
if r == 0: break
|
||||||
buf.setLen(r)
|
buf.setLen(r)
|
||||||
result.add(buf)
|
result.add(buf)
|
||||||
|
|
||||||
proc parseResponse(s: TSocket, getBody: bool): TResponse =
|
proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse =
|
||||||
var parsedStatus = false
|
var parsedStatus = false
|
||||||
var linei = 0
|
var linei = 0
|
||||||
var fullyRead = false
|
var fullyRead = false
|
||||||
|
|
@ -162,7 +175,7 @@ proc parseResponse(s: TSocket, getBody: bool): TResponse =
|
||||||
while True:
|
while True:
|
||||||
line = ""
|
line = ""
|
||||||
linei = 0
|
linei = 0
|
||||||
if s.recvLine(line):
|
if s.recvLine(line, timeout):
|
||||||
if line == "": break # We've been disconnected.
|
if line == "": break # We've been disconnected.
|
||||||
if line == "\c\L":
|
if line == "\c\L":
|
||||||
fullyRead = true
|
fullyRead = true
|
||||||
|
|
@ -194,9 +207,11 @@ proc parseResponse(s: TSocket, getBody: bool): TResponse =
|
||||||
linei += skipWhitespace(line, linei)
|
linei += skipWhitespace(line, linei)
|
||||||
|
|
||||||
result.headers[name] = line[linei.. -1]
|
result.headers[name] = line[linei.. -1]
|
||||||
if not fullyRead: httpError("Connection was closed before full request has been made")
|
else: SocketError(s)
|
||||||
|
if not fullyRead:
|
||||||
|
httpError("Connection was closed before full request has been made")
|
||||||
if getBody:
|
if getBody:
|
||||||
result.body = parseBody(s, result.headers)
|
result.body = parseBody(s, result.headers, timeout)
|
||||||
else:
|
else:
|
||||||
result.body = ""
|
result.body = ""
|
||||||
|
|
||||||
|
|
@ -227,9 +242,12 @@ else:
|
||||||
|
|
||||||
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
body = "",
|
body = "",
|
||||||
sslContext: PSSLContext = defaultSSLContext): TResponse =
|
sslContext: PSSLContext = defaultSSLContext,
|
||||||
|
timeout = -1, userAgent = defUserAgent): TResponse =
|
||||||
## | Requests ``url`` with the specified ``httpMethod``.
|
## | Requests ``url`` with the specified ``httpMethod``.
|
||||||
## | Extra headers can be specified and must be seperated by ``\c\L``
|
## | Extra headers can be specified and must be seperated by ``\c\L``
|
||||||
|
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||||
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
var r = parseUrl(url)
|
var r = parseUrl(url)
|
||||||
var headers = substr($httpMethod, len("http"))
|
var headers = substr($httpMethod, len("http"))
|
||||||
headers.add(" /" & r.path & r.query)
|
headers.add(" /" & r.path & r.query)
|
||||||
|
|
@ -237,6 +255,8 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
headers.add(" HTTP/1.1\c\L")
|
headers.add(" HTTP/1.1\c\L")
|
||||||
|
|
||||||
add(headers, "Host: " & r.hostname & "\c\L")
|
add(headers, "Host: " & r.hostname & "\c\L")
|
||||||
|
if userAgent != "":
|
||||||
|
add(headers, "User-Agent: " & userAgent & "\c\L")
|
||||||
add(headers, extraHeaders)
|
add(headers, extraHeaders)
|
||||||
add(headers, "\c\L")
|
add(headers, "\c\L")
|
||||||
|
|
||||||
|
|
@ -246,16 +266,21 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
sslContext.wrapSocket(s)
|
sslContext.wrapSocket(s)
|
||||||
else:
|
else:
|
||||||
raise newException(EHttpRequestErr, "SSL support was not compiled in. Cannot connect over SSL.")
|
raise newException(EHttpRequestErr,
|
||||||
|
"SSL support is not available. Cannot connect over SSL.")
|
||||||
port = TPort(443)
|
port = TPort(443)
|
||||||
if r.port != "":
|
if r.port != "":
|
||||||
port = TPort(r.port.parseInt)
|
port = TPort(r.port.parseInt)
|
||||||
s.connect(r.hostname, port)
|
|
||||||
|
if timeout == -1:
|
||||||
|
s.connect(r.hostname, port)
|
||||||
|
else:
|
||||||
|
s.connect(r.hostname, port, timeout)
|
||||||
s.send(headers)
|
s.send(headers)
|
||||||
if body != "":
|
if body != "":
|
||||||
s.send(body)
|
s.send(body)
|
||||||
|
|
||||||
result = parseResponse(s, httpMethod != httpHEAD)
|
result = parseResponse(s, httpMethod != httpHEAD, timeout)
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
proc redirection(status: string): bool =
|
proc redirection(status: string): bool =
|
||||||
|
|
@ -264,55 +289,93 @@ proc redirection(status: string): bool =
|
||||||
if status.startsWith(i):
|
if status.startsWith(i):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
proc get*(url: string, maxRedirects = 5, sslContext: PSSLContext = defaultSSLContext): TResponse =
|
proc getNewLocation(lastUrl: string, headers: PStringTable): string =
|
||||||
|
result = headers["Location"]
|
||||||
|
if result == "": httpError("location header expected")
|
||||||
|
# Relative URLs. (Not part of the spec, but soon will be.)
|
||||||
|
let r = parseURL(result)
|
||||||
|
if r.hostname == "" and r.path != "":
|
||||||
|
let origParsed = parseURL(lastUrl)
|
||||||
|
result = origParsed.hostname & "/" & r.path
|
||||||
|
|
||||||
|
proc get*(url: string, extraHeaders = "", maxRedirects = 5,
|
||||||
|
sslContext: PSSLContext = defaultSSLContext,
|
||||||
|
timeout = -1, userAgent = defUserAgent): TResponse =
|
||||||
## | GETs the ``url`` and returns a ``TResponse`` object
|
## | GETs the ``url`` and returns a ``TResponse`` object
|
||||||
## | This proc also handles redirection
|
## | This proc also handles redirection
|
||||||
result = request(url)
|
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||||
|
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||||
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
|
result = request(url, httpGET, extraHeaders, "", sslContext, timeout, userAgent)
|
||||||
|
var lastURL = url
|
||||||
for i in 1..maxRedirects:
|
for i in 1..maxRedirects:
|
||||||
if result.status.redirection():
|
if result.status.redirection():
|
||||||
var locationHeader = result.headers["Location"]
|
let redirectTo = getNewLocation(lastURL, result.headers)
|
||||||
if locationHeader == "": httpError("location header expected")
|
result = request(redirectTo, httpGET, extraHeaders, "", sslContext,
|
||||||
result = request(locationHeader, sslContext = sslContext)
|
timeout, userAgent)
|
||||||
|
lastUrl = redirectTo
|
||||||
|
|
||||||
proc getContent*(url: string, sslContext: PSSLContext = defaultSSLContext): string =
|
proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
|
||||||
|
sslContext: PSSLContext = defaultSSLContext,
|
||||||
|
timeout = -1, userAgent = defUserAgent): string =
|
||||||
## | GETs the body and returns it as a string.
|
## | GETs the body and returns it as a string.
|
||||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||||
var r = get(url, sslContext = sslContext)
|
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||||
|
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||||
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
|
var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent)
|
||||||
if r.status[0] in {'4','5'}:
|
if r.status[0] in {'4','5'}:
|
||||||
raise newException(EHTTPRequestErr, r.status)
|
raise newException(EHTTPRequestErr, r.status)
|
||||||
else:
|
else:
|
||||||
return r.body
|
return r.body
|
||||||
|
|
||||||
proc post*(url: string, extraHeaders = "", body = "",
|
proc post*(url: string, extraHeaders = "", body = "",
|
||||||
maxRedirects = 5, sslContext: PSSLContext = defaultSSLContext): TResponse =
|
maxRedirects = 5,
|
||||||
|
sslContext: PSSLContext = defaultSSLContext,
|
||||||
|
timeout = -1, userAgent = defUserAgent): TResponse =
|
||||||
## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object.
|
## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object.
|
||||||
## | This proc adds the necessary Content-Length header.
|
## | This proc adds the necessary Content-Length header.
|
||||||
## | This proc also handles redirection.
|
## | 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
|
||||||
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
|
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
|
||||||
result = request(url, httpPOST, xh, body, sslContext)
|
result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent)
|
||||||
|
var lastUrl = ""
|
||||||
for i in 1..maxRedirects:
|
for i in 1..maxRedirects:
|
||||||
if result.status.redirection():
|
if result.status.redirection():
|
||||||
var locationHeader = result.headers["Location"]
|
let redirectTo = getNewLocation(lastURL, result.headers)
|
||||||
if locationHeader == "": httpError("location header expected")
|
|
||||||
var meth = if result.status != "307": httpGet else: httpPost
|
var meth = if result.status != "307": httpGet else: httpPost
|
||||||
result = request(locationHeader, meth, xh, body)
|
result = request(redirectTo, meth, xh, body, sslContext, timeout,
|
||||||
|
userAgent)
|
||||||
|
lastUrl = redirectTo
|
||||||
|
|
||||||
proc postContent*(url: string, extraHeaders = "", body = "",
|
proc postContent*(url: string, extraHeaders = "", body = "",
|
||||||
sslContext: PSSLContext = defaultSSLContext): string =
|
maxRedirects = 5,
|
||||||
|
sslContext: PSSLContext = defaultSSLContext,
|
||||||
|
timeout = -1, userAgent = defUserAgent): string =
|
||||||
## | POSTs ``body`` to ``url`` and returns the response's body as a string
|
## | POSTs ``body`` to ``url`` and returns the response's body as a string
|
||||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||||
var r = post(url, extraHeaders, body)
|
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||||
|
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||||
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
|
var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
|
||||||
|
userAgent)
|
||||||
if r.status[0] in {'4','5'}:
|
if r.status[0] in {'4','5'}:
|
||||||
raise newException(EHTTPRequestErr, r.status)
|
raise newException(EHTTPRequestErr, r.status)
|
||||||
else:
|
else:
|
||||||
return r.body
|
return r.body
|
||||||
|
|
||||||
proc downloadFile*(url: string, outputFilename: string,
|
proc downloadFile*(url: string, outputFilename: string,
|
||||||
sslContext: PSSLContext = defaultSSLContext) =
|
sslContext: PSSLContext = defaultSSLContext,
|
||||||
## Downloads ``url`` and saves it to ``outputFilename``
|
timeout = -1, userAgent = defUserAgent) =
|
||||||
|
## | 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: TFile
|
||||||
if open(f, outputFilename, fmWrite):
|
if open(f, outputFilename, fmWrite):
|
||||||
f.write(getContent(url, sslContext))
|
f.write(getContent(url, sslContext = sslContext, timeout = timeout,
|
||||||
|
userAgent = userAgent))
|
||||||
f.close()
|
f.close()
|
||||||
else:
|
else:
|
||||||
fileError("Unable to open file")
|
fileError("Unable to open file")
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,28 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a simple portable type-safe sockets layer.
|
## This module implements portable sockets, it supports a mix of different types
|
||||||
|
## of sockets. Sockets are buffered by default meaning that data will be
|
||||||
|
## received in ``BufferSize`` (4000) sized chunks, buffering
|
||||||
|
## behaviour can be disabled by setting the ``buffered`` parameter when calling
|
||||||
|
## the ``socket`` function to `False`. Be aware that some functions may not yet
|
||||||
|
## support buffered sockets (mainly the recvFrom function).
|
||||||
##
|
##
|
||||||
## Most procedures raise EOS on error.
|
## Most procedures raise EOS on error, but some may return ``-1`` or a boolean
|
||||||
|
## ``False``.
|
||||||
##
|
##
|
||||||
## For OpenSSL support compile with ``-d:ssl``. When using SSL be aware that
|
## SSL is supported through the OpenSSL library. This support can be activated
|
||||||
## most functions will then raise ``ESSL`` on SSL errors.
|
## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
|
||||||
|
## raise ESSL exceptions when SSL errors occur.
|
||||||
|
##
|
||||||
|
## Asynchronous sockets are supported, however a better alternative is to use
|
||||||
|
## the `asyncio <asyncio.html>`_ module.
|
||||||
|
|
||||||
{.deadCodeElim: on.}
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
|
|
@ -68,6 +78,7 @@ type
|
||||||
sslHasPeekChar: bool
|
sslHasPeekChar: bool
|
||||||
sslPeekChar: char
|
sslPeekChar: char
|
||||||
of false: nil
|
of false: nil
|
||||||
|
nonblocking: bool
|
||||||
|
|
||||||
TSocket* = ref TSocketImpl
|
TSocket* = ref TSocketImpl
|
||||||
|
|
||||||
|
|
@ -118,6 +129,7 @@ proc newTSocket(fd: int32, isBuff: bool): TSocket =
|
||||||
result.isBuffered = isBuff
|
result.isBuffered = isBuff
|
||||||
if isBuff:
|
if isBuff:
|
||||||
result.currPos = 0
|
result.currPos = 0
|
||||||
|
result.nonblocking = false
|
||||||
|
|
||||||
let
|
let
|
||||||
InvalidSocket*: TSocket = nil ## invalid socket
|
InvalidSocket*: TSocket = nil ## invalid socket
|
||||||
|
|
@ -196,7 +208,7 @@ else:
|
||||||
|
|
||||||
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||||
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
|
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
|
||||||
## creates a new socket; returns `InvalidSocket` if an error occurs.
|
## Creates a new socket; returns `InvalidSocket` if an error occurs.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
|
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
|
||||||
else:
|
else:
|
||||||
|
|
@ -711,10 +723,10 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
sizeof(value).TSockLen) < 0'i32:
|
sizeof(value).TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError()
|
||||||
|
|
||||||
proc connect*(socket: TSocket, name: 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].} =
|
||||||
## Connects socket to ``name``:``port``. ``Name`` can be an IP address or a
|
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
||||||
## host name. If ``name`` is a host name, this function will try each IP
|
## host name. If ``address`` is a host name, this function will try each IP
|
||||||
## of that host name. ``htons`` is already performed on ``port`` so you must
|
## of that host name. ``htons`` is already performed on ``port`` so you must
|
||||||
## not do it.
|
## not do it.
|
||||||
##
|
##
|
||||||
|
|
@ -724,8 +736,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||||
hints.ai_family = toInt(af)
|
hints.ai_family = toInt(af)
|
||||||
hints.ai_socktype = toInt(SOCK_STREAM)
|
hints.ai_socktype = toInt(SOCK_STREAM)
|
||||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||||
gaiNim(name, port, hints, aiList)
|
gaiNim(address, port, hints, aiList)
|
||||||
|
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var it = aiList
|
var it = aiList
|
||||||
|
|
@ -758,7 +769,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
var s: TSockAddrIn
|
var s: TSockAddrIn
|
||||||
s.sin_addr.s_addr = inet_addr(name)
|
s.sin_addr.s_addr = inet_addr(address)
|
||||||
s.sin_port = sockets.htons(int16(port))
|
s.sin_port = sockets.htons(int16(port))
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
s.sin_family = toU16(ord(af))
|
s.sin_family = toU16(ord(af))
|
||||||
|
|
@ -891,6 +902,10 @@ proc hasDataBuffered*(s: TSocket): bool =
|
||||||
if s.isBuffered:
|
if s.isBuffered:
|
||||||
result = s.bufLen > 0 and s.currPos != s.bufLen
|
result = s.bufLen > 0 and s.currPos != s.bufLen
|
||||||
|
|
||||||
|
when defined(ssl):
|
||||||
|
if s.isSSL and not result:
|
||||||
|
result = s.sslHasPeekChar
|
||||||
|
|
||||||
proc checkBuffer(readfds: var seq[TSocket]): int =
|
proc checkBuffer(readfds: var seq[TSocket]): int =
|
||||||
## Checks the buffer of each socket in ``readfds`` to see whether there is data.
|
## Checks the buffer of each socket in ``readfds`` to see whether there is data.
|
||||||
## Removes the sockets from ``readfds`` and returns the count of removed sockets.
|
## Removes the sockets from ``readfds`` and returns the count of removed sockets.
|
||||||
|
|
@ -906,8 +921,8 @@ proc checkBuffer(readfds: var seq[TSocket]): int =
|
||||||
proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||||
timeout = 500): int {.tags: [FReadIO].} =
|
timeout = 500): int {.tags: [FReadIO].} =
|
||||||
## Traditional select function. This function will return the number of
|
## Traditional select function. This function will return the number of
|
||||||
## sockets that are ready to be read from, written to, or which have errors
|
## sockets that are ready to be read from, written to, or which have errors.
|
||||||
## if there are none; 0 is returned.
|
## If there are none; 0 is returned.
|
||||||
## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
|
## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
|
||||||
##
|
##
|
||||||
## A socket is removed from the specific ``seq`` when it has data waiting to
|
## A socket is removed from the specific ``seq`` when it has data waiting to
|
||||||
|
|
@ -935,7 +950,7 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||||
|
|
||||||
proc select*(readfds, writefds: var seq[TSocket],
|
proc select*(readfds, writefds: var seq[TSocket],
|
||||||
timeout = 500): int {.tags: [FReadIO].} =
|
timeout = 500): int {.tags: [FReadIO].} =
|
||||||
## variant of select with only a read and write list.
|
## Variant of select with only a read and write list.
|
||||||
let buffersFilled = checkBuffer(readfds)
|
let buffersFilled = checkBuffer(readfds)
|
||||||
if buffersFilled > 0:
|
if buffersFilled > 0:
|
||||||
return buffersFilled
|
return buffersFilled
|
||||||
|
|
@ -1019,7 +1034,10 @@ template retRead(flags, readBytes: int) =
|
||||||
return res
|
return res
|
||||||
|
|
||||||
proc recv*(socket: TSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
|
proc recv*(socket: TSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
|
||||||
## receives data from a socket
|
## Receives data from a socket.
|
||||||
|
##
|
||||||
|
## **Note**: This is a low-level function, you may be interested in the higher
|
||||||
|
## level versions of this function which are also named ``recv``.
|
||||||
if size == 0: return
|
if size == 0: return
|
||||||
if socket.isBuffered:
|
if socket.isBuffered:
|
||||||
if socket.bufLen == 0:
|
if socket.bufLen == 0:
|
||||||
|
|
@ -1055,24 +1073,79 @@ proc recv*(socket: TSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
|
||||||
else:
|
else:
|
||||||
result = recv(socket.fd, data, size.cint, 0'i32)
|
result = recv(socket.fd, data, size.cint, 0'i32)
|
||||||
|
|
||||||
proc recv*(socket: TSocket, data: var string, size: int): int =
|
proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
|
||||||
## higher-level version of the above
|
funcName: string): int {.tags: [FTime].} =
|
||||||
|
## determines the amount of characters that can be read. Result will never
|
||||||
|
## be larger than ``size``. For unbuffered sockets this will be ``1``.
|
||||||
|
## For buffered sockets it can be as big as ``BufferSize``.
|
||||||
|
##
|
||||||
|
## If this function does not determine that there is data on the socket
|
||||||
|
## within ``timeout`` ms, an ETimeout error will be raised.
|
||||||
|
result = 1
|
||||||
|
if size <= 0: assert false
|
||||||
|
if timeout == -1: return size
|
||||||
|
if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
|
||||||
|
result = socket.bufLen - socket.currPos
|
||||||
|
result = min(result, size)
|
||||||
|
else:
|
||||||
|
if timeout - int(waited * 1000.0) < 1:
|
||||||
|
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
||||||
|
|
||||||
|
when defined(ssl):
|
||||||
|
if socket.isSSL:
|
||||||
|
if socket.hasDataBuffered:
|
||||||
|
# sslPeekChar is present.
|
||||||
|
return 1
|
||||||
|
let sslPending = SSLPending(socket.sslHandle)
|
||||||
|
if sslPending != 0:
|
||||||
|
return sslPending
|
||||||
|
|
||||||
|
var s = @[socket]
|
||||||
|
var startTime = epochTime()
|
||||||
|
let selRet = select(s, timeout - int(waited * 1000.0))
|
||||||
|
if selRet < 0: OSError()
|
||||||
|
if selRet != 1:
|
||||||
|
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
||||||
|
waited += (epochTime() - startTime)
|
||||||
|
|
||||||
|
proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int {.
|
||||||
|
tags: [FReadIO, FTime].} =
|
||||||
|
## overload with a ``timeout`` parameter in miliseconds.
|
||||||
|
var waited = 0.0 # number of seconds already waited
|
||||||
|
|
||||||
|
var read = 0
|
||||||
|
while read < size:
|
||||||
|
let avail = waitFor(socket, waited, timeout, size-read, "recv")
|
||||||
|
var d = cast[cstring](data)
|
||||||
|
result = recv(socket, addr(d[read]), avail)
|
||||||
|
if result == 0: break
|
||||||
|
if result < 0:
|
||||||
|
return result
|
||||||
|
inc(read, result)
|
||||||
|
|
||||||
|
result = read
|
||||||
|
|
||||||
|
proc recv*(socket: TSocket, data: var string, size: int, timeout = -1): int =
|
||||||
|
## Higher-level version of ``recv``.
|
||||||
##
|
##
|
||||||
## When 0 is returned the socket's connection has been closed.
|
## When 0 is returned the socket's connection has been closed.
|
||||||
##
|
##
|
||||||
## This function will throw an EOS exception when an error occurs. A value
|
## This function will throw an EOS exception when an error occurs. A value
|
||||||
## lower than 0 is never returned.
|
## lower than 0 is never returned.
|
||||||
##
|
##
|
||||||
|
## A timeout may be specified in miliseconds, if enough data is not received
|
||||||
|
## within the time specified an ETimeout exception will be raised.
|
||||||
|
##
|
||||||
## **Note**: ``data`` must be initialised.
|
## **Note**: ``data`` must be initialised.
|
||||||
data.setLen(size)
|
data.setLen(size)
|
||||||
result = recv(socket, cstring(data), size)
|
result = recv(socket, cstring(data), size, timeout)
|
||||||
if result < 0:
|
if result < 0:
|
||||||
data.setLen(0)
|
data.setLen(0)
|
||||||
socket.SocketError(result)
|
socket.SocketError(result)
|
||||||
data.setLen(result)
|
data.setLen(result)
|
||||||
|
|
||||||
proc recvAsync*(socket: TSocket, data: var string, size: int): int =
|
proc recvAsync*(socket: TSocket, data: var string, size: int): int =
|
||||||
## Async version of the above.
|
## Async version of ``recv``.
|
||||||
##
|
##
|
||||||
## When socket is non-blocking and no data is available on the socket,
|
## When socket is non-blocking and no data is available on the socket,
|
||||||
## ``-1`` will be returned and ``data`` will be ``""``.
|
## ``-1`` will be returned and ``data`` will be ``""``.
|
||||||
|
|
@ -1086,51 +1159,6 @@ proc recvAsync*(socket: TSocket, data: var string, size: int): int =
|
||||||
result = -1
|
result = -1
|
||||||
data.setLen(result)
|
data.setLen(result)
|
||||||
|
|
||||||
proc waitFor(socket: TSocket, waited: var float, timeout: int): int {.
|
|
||||||
tags: [FTime].} =
|
|
||||||
## returns the number of characters available to be read. In unbuffered
|
|
||||||
## sockets this is always 1, otherwise this may as big as ``BufferSize``.
|
|
||||||
result = 1
|
|
||||||
if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
|
|
||||||
result = socket.bufLen - socket.currPos
|
|
||||||
else:
|
|
||||||
if timeout - int(waited * 1000.0) < 1:
|
|
||||||
raise newException(ETimeout, "Call to recv() timed out.")
|
|
||||||
var s = @[socket]
|
|
||||||
var startTime = epochTime()
|
|
||||||
if select(s, timeout - int(waited * 1000.0)) != 1:
|
|
||||||
raise newException(ETimeout, "Call to recv() timed out.")
|
|
||||||
waited += (epochTime() - startTime)
|
|
||||||
|
|
||||||
proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int {.
|
|
||||||
tags: [FReadIO, FTime].} =
|
|
||||||
## overload with a ``timeout`` parameter in miliseconds.
|
|
||||||
var waited = 0.0 # number of seconds already waited
|
|
||||||
|
|
||||||
var read = 0
|
|
||||||
while read < size:
|
|
||||||
let avail = waitFor(socket, waited, timeout)
|
|
||||||
var d = cast[cstring](data)
|
|
||||||
result = recv(socket, addr(d[read]), avail)
|
|
||||||
if result == 0: break
|
|
||||||
if result < 0:
|
|
||||||
return result
|
|
||||||
inc(read, result)
|
|
||||||
|
|
||||||
result = read
|
|
||||||
|
|
||||||
proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int =
|
|
||||||
## higher-level version of the above.
|
|
||||||
##
|
|
||||||
## Similar to the non-timeout version this will throw an EOS exception
|
|
||||||
## when an error occurs.
|
|
||||||
data.setLen(size)
|
|
||||||
result = recv(socket, cstring(data), size, timeout)
|
|
||||||
if result < 0:
|
|
||||||
data.setLen(0)
|
|
||||||
socket.SocketError()
|
|
||||||
data.setLen(result)
|
|
||||||
|
|
||||||
proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} =
|
proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} =
|
||||||
if socket.isBuffered:
|
if socket.isBuffered:
|
||||||
result = 1
|
result = 1
|
||||||
|
|
@ -1151,9 +1179,11 @@ proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} =
|
||||||
return
|
return
|
||||||
result = recv(socket.fd, addr(c), 1, MSG_PEEK)
|
result = recv(socket.fd, addr(c), 1, MSG_PEEK)
|
||||||
|
|
||||||
proc recvLine*(socket: TSocket, line: var TaintedString): bool {.
|
proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {.
|
||||||
tags: [FReadIO].} =
|
tags: [FReadIO, FTime].} =
|
||||||
## retrieves a line from ``socket``. If a full line is received ``\r\L`` is not
|
## Receive a line of data from ``socket``.
|
||||||
|
##
|
||||||
|
## If a full line is received ``\r\L`` is not
|
||||||
## added to ``line``, however if solely ``\r\L`` is received then ``line``
|
## added to ``line``, however if solely ``\r\L`` is received then ``line``
|
||||||
## will be set to it.
|
## will be set to it.
|
||||||
##
|
##
|
||||||
|
|
@ -1163,49 +1193,24 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool {.
|
||||||
##
|
##
|
||||||
## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
|
## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
|
||||||
## will be returned.
|
## will be returned.
|
||||||
template addNLIfEmpty(): stmt =
|
|
||||||
if line.len == 0:
|
|
||||||
line.add("\c\L")
|
|
||||||
|
|
||||||
setLen(line.string, 0)
|
|
||||||
while true:
|
|
||||||
var c: char
|
|
||||||
var n = recv(socket, addr(c), 1)
|
|
||||||
if n < 0: return
|
|
||||||
elif n == 0: return true
|
|
||||||
if c == '\r':
|
|
||||||
n = peekChar(socket, c)
|
|
||||||
if n > 0 and c == '\L':
|
|
||||||
discard recv(socket, addr(c), 1)
|
|
||||||
elif n <= 0: return false
|
|
||||||
addNlIfEmpty()
|
|
||||||
return true
|
|
||||||
elif c == '\L':
|
|
||||||
addNlIfEmpty()
|
|
||||||
return true
|
|
||||||
add(line.string, c)
|
|
||||||
|
|
||||||
proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool {.
|
|
||||||
tags: [FReadIO, FTime].} =
|
|
||||||
## variant with a ``timeout`` parameter, the timeout parameter specifies
|
|
||||||
## how many miliseconds to wait for data.
|
|
||||||
##
|
##
|
||||||
## ``ETimeout`` will be raised if ``timeout`` is exceeded.
|
## A timeout can be specified in miliseconds, if data is not received within
|
||||||
|
## the specified time an ETimeout exception will be raised.
|
||||||
template addNLIfEmpty(): stmt =
|
template addNLIfEmpty(): stmt =
|
||||||
if line.len == 0:
|
if line.len == 0:
|
||||||
line.add("\c\L")
|
line.add("\c\L")
|
||||||
|
|
||||||
var waited = 0.0 # number of seconds already waited
|
var waited = 0.0
|
||||||
|
|
||||||
setLen(line.string, 0)
|
setLen(line.string, 0)
|
||||||
while true:
|
while true:
|
||||||
var c: char
|
var c: char
|
||||||
discard waitFor(socket, waited, timeout)
|
discard waitFor(socket, waited, timeout, 1, "recvLine")
|
||||||
var n = recv(socket, addr(c), 1)
|
var n = recv(socket, addr(c), 1)
|
||||||
if n < 0: return
|
if n < 0: return
|
||||||
elif n == 0: return true
|
elif n == 0: return true
|
||||||
if c == '\r':
|
if c == '\r':
|
||||||
discard waitFor(socket, waited, timeout)
|
discard waitFor(socket, waited, timeout, 1, "recvLine")
|
||||||
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)
|
||||||
|
|
@ -1219,12 +1224,14 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool {.
|
||||||
|
|
||||||
proc recvLineAsync*(socket: TSocket,
|
proc recvLineAsync*(socket: TSocket,
|
||||||
line: var TaintedString): TRecvLineResult {.tags: [FReadIO].} =
|
line: var TaintedString): TRecvLineResult {.tags: [FReadIO].} =
|
||||||
## similar to ``recvLine`` but for non-blocking sockets.
|
## Similar to ``recvLine`` but designed for non-blocking sockets.
|
||||||
|
##
|
||||||
## The values of the returned enum should be pretty self explanatory:
|
## The values of the returned enum should be pretty self explanatory:
|
||||||
## If a full line has been retrieved; ``RecvFullLine`` is returned.
|
##
|
||||||
## If some data has been retrieved; ``RecvPartialLine`` is returned.
|
## * If a full line has been retrieved; ``RecvFullLine`` is returned.
|
||||||
## If the socket has been disconnected; ``RecvDisconnected`` is returned.
|
## * If some data has been retrieved; ``RecvPartialLine`` is returned.
|
||||||
## If call to ``recv`` failed; ``RecvFail`` is returned.
|
## * If the socket has been disconnected; ``RecvDisconnected`` is returned.
|
||||||
|
## * If call to ``recv`` failed; ``RecvFail`` is returned.
|
||||||
setLen(line.string, 0)
|
setLen(line.string, 0)
|
||||||
while true:
|
while true:
|
||||||
var c: char
|
var c: char
|
||||||
|
|
@ -1348,6 +1355,9 @@ proc recvFrom*(socket: TSocket, data: var string, length: int,
|
||||||
## Receives data from ``socket``. This function should normally be used with
|
## Receives data from ``socket``. This function should normally be used with
|
||||||
## connection-less sockets (UDP sockets).
|
## connection-less sockets (UDP sockets).
|
||||||
##
|
##
|
||||||
|
## If an error occurs the return value will be ``-1``. Otherwise the return
|
||||||
|
## value will be the length of data received.
|
||||||
|
##
|
||||||
## **Warning:** This function does not yet have a buffered implementation,
|
## **Warning:** This function does not yet have a buffered implementation,
|
||||||
## so when ``socket`` is buffered the non-buffered implementation will be
|
## so when ``socket`` is buffered the non-buffered implementation will be
|
||||||
## used. Therefore if ``socket`` contains something in its buffer this
|
## used. Therefore if ``socket`` contains something in its buffer this
|
||||||
|
|
@ -1368,9 +1378,10 @@ proc recvFrom*(socket: TSocket, data: var string, length: int,
|
||||||
proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
||||||
address: var string, port: var TPort,
|
address: var string, port: var TPort,
|
||||||
flags = 0'i32): bool {.tags: [FReadIO].} =
|
flags = 0'i32): bool {.tags: [FReadIO].} =
|
||||||
## Similar to ``recvFrom`` but raises an EOS error when an error occurs and
|
## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``,
|
||||||
## is also meant for non-blocking sockets.
|
## this function will raise an EOS error whenever a socket error occurs.
|
||||||
## Returns False if no messages could be received from ``socket``.
|
##
|
||||||
|
## If there is no data to be read from the socket ``False`` will be returned.
|
||||||
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:
|
||||||
|
|
@ -1394,14 +1405,19 @@ proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
|
||||||
while recv(socket, buf, bufSize) == bufSize: nil
|
while recv(socket, buf, bufSize) == bufSize: nil
|
||||||
dealloc(buf)
|
dealloc(buf)
|
||||||
|
|
||||||
proc skip*(socket: TSocket, size: int) =
|
proc skip*(socket: TSocket, size: int, timeout = -1) =
|
||||||
## Skips ``size`` amount of bytes.
|
## Skips ``size`` amount of bytes.
|
||||||
##
|
##
|
||||||
|
## An optional timeout can be specified in miliseconds, if skipping the
|
||||||
|
## bytes takes longer than specified an ETimeout exception will be raised.
|
||||||
|
##
|
||||||
## Returns the number of skipped bytes.
|
## Returns the number of skipped bytes.
|
||||||
|
var waited = 0.0
|
||||||
var dummy = alloc(size)
|
var dummy = alloc(size)
|
||||||
var bytesSkipped = 0
|
var bytesSkipped = 0
|
||||||
while bytesSkipped != size:
|
while bytesSkipped != size:
|
||||||
bytesSkipped += recv(socket, dummy, size-bytesSkipped)
|
let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
|
||||||
|
bytesSkipped += recv(socket, dummy, avail)
|
||||||
dealloc(dummy)
|
dealloc(dummy)
|
||||||
|
|
||||||
proc send*(socket: TSocket, data: pointer, size: int): int {.
|
proc send*(socket: TSocket, data: pointer, size: int): int {.
|
||||||
|
|
@ -1529,21 +1545,27 @@ proc setBlocking(s: TSocket, blocking: bool) =
|
||||||
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()
|
||||||
|
s.nonblocking = not blocking
|
||||||
|
|
||||||
proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),
|
proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: TDomain = AF_INET) {.tags: [FReadIO, FWriteIO].} =
|
||||||
## Overload for ``connect`` to support timeouts. The ``timeout`` parameter
|
## Connects to server as specified by ``address`` on port specified by ``port``.
|
||||||
## specifies the time in miliseconds of how long to wait for a connection
|
|
||||||
## to be made.
|
|
||||||
##
|
##
|
||||||
## **Warning:** If ``socket`` is non-blocking then
|
## The ``timeout`` paremeter specifies the time in miliseconds to allow for
|
||||||
## this function will set blocking mode on ``socket`` to true.
|
## the connection to the server to be made.
|
||||||
socket.setBlocking(true)
|
let originalStatus = not socket.nonblocking
|
||||||
|
socket.setBlocking(false)
|
||||||
|
|
||||||
socket.connectAsync(name, port, af)
|
socket.connectAsync(address, port, af)
|
||||||
var s: seq[TSocket] = @[socket]
|
var s: seq[TSocket] = @[socket]
|
||||||
if selectWrite(s, timeout) != 1:
|
if selectWrite(s, timeout) != 1:
|
||||||
raise newException(ETimeout, "Call to connect() timed out.")
|
raise newException(ETimeout, "Call to 'connect' timed out.")
|
||||||
|
else:
|
||||||
|
when defined(ssl):
|
||||||
|
if socket.isSSL:
|
||||||
|
socket.setBlocking(true)
|
||||||
|
doAssert socket.handshake()
|
||||||
|
socket.setBlocking(originalStatus)
|
||||||
|
|
||||||
proc isSSL*(socket: TSocket): bool = return socket.isSSL
|
proc isSSL*(socket: TSocket): bool = return socket.isSSL
|
||||||
## Determines whether ``socket`` is a SSL socket.
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,7 @@ proc SSL_read*(ssl: PSSL, buf: pointer, num: int): cint{.cdecl, dynlib: DLLSSLNa
|
||||||
proc SSL_write*(ssl: PSSL, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_write*(ssl: PSSL, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
proc SSL_get_error*(s: PSSL, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_get_error*(s: PSSL, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
proc SSL_accept*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_accept*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
proc SSL_pending*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc BIO_new_ssl_connect*(ctx: PSSL_CTX): PBIO{.cdecl,
|
proc BIO_new_ssl_connect*(ctx: PSSL_CTX): PBIO{.cdecl,
|
||||||
dynlib: DLLSSLName, importc.}
|
dynlib: DLLSSLName, importc.}
|
||||||
|
|
@ -323,7 +324,6 @@ else:
|
||||||
dynlib: DLLSSLName, importc.}
|
dynlib: DLLSSLName, importc.}
|
||||||
proc SslWrite*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl,
|
proc SslWrite*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl,
|
||||||
dynlib: DLLSSLName, importc.}
|
dynlib: DLLSSLName, importc.}
|
||||||
proc SslPending*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
|
||||||
proc SslGetVersion*(ssl: PSSL): cstring{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SslGetVersion*(ssl: PSSL): cstring{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
proc SslGetPeerCertificate*(ssl: PSSL): PX509{.cdecl, dynlib: DLLSSLName,
|
proc SslGetPeerCertificate*(ssl: PSSL): PX509{.cdecl, dynlib: DLLSSLName,
|
||||||
importc.}
|
importc.}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue