Improve net and ssl module docs.
This commit is contained in:
parent
38d6e2c221
commit
8e6f5f20f6
2 changed files with 80 additions and 20 deletions
|
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
## This module provides an easy to use sockets-style
|
## This module provides an easy to use sockets-style
|
||||||
## nim interface to the OpenSSL library.
|
## nim interface to the OpenSSL library.
|
||||||
|
##
|
||||||
|
## **Warning:** This module is deprecated, use the SSL procedures defined in
|
||||||
|
## the ``net`` module instead.
|
||||||
|
|
||||||
{.deprecated.}
|
{.deprecated.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,76 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a high-level cross-platform sockets interface.
|
## This module implements a high-level cross-platform sockets interface.
|
||||||
|
## The procedures implemented in this module are primarily for blocking sockets.
|
||||||
|
## For asynchronous non-blocking sockets use the ``asyncnet`` module together
|
||||||
|
## with the ``asyncdispatch`` module.
|
||||||
|
##
|
||||||
|
## The first thing you will always need to do in order to start using sockets,
|
||||||
|
## is to create a new instance of the ``Socket`` type using the ``newSocket``
|
||||||
|
## procedure.
|
||||||
|
##
|
||||||
|
## SSL
|
||||||
|
## ====
|
||||||
|
##
|
||||||
|
## In order to use the SSL procedures defined in this module, you will need to
|
||||||
|
## compile your application with the ``-d:ssl`` flag.
|
||||||
|
##
|
||||||
|
## Examples
|
||||||
|
## ========
|
||||||
|
##
|
||||||
|
## Connecting to a server
|
||||||
|
## ----------------------
|
||||||
|
##
|
||||||
|
## After you create a socket with the ``newSocket`` procedure, you can easily
|
||||||
|
## connect it to a server running at a known hostname (or IP address) and port.
|
||||||
|
## To do so over TCP, use the example below.
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## var socket = newSocket()
|
||||||
|
## socket.connect("google.com", Port(80))
|
||||||
|
##
|
||||||
|
## UDP is a connectionless protocol, so UDP sockets don't have to explicitly
|
||||||
|
## call the ``connect`` procedure. They can simply start sending data
|
||||||
|
## immediately.
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## var socket = newSocket()
|
||||||
|
## socket.sendTo("192.168.0.1", Port(27960), "status\n")
|
||||||
|
##
|
||||||
|
## Creating a server
|
||||||
|
## -----------------
|
||||||
|
##
|
||||||
|
## After you create a socket with the ``newSocket`` procedure, you can create a
|
||||||
|
## TCP server by calling the ``bindAddr`` and ``listen`` procedures.
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## var socket = newSocket()
|
||||||
|
## socket.bindAddr(Port(1234))
|
||||||
|
## socket.listen()
|
||||||
|
##
|
||||||
|
## You can then begin accepting connections using the ``accept`` procedure.
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## var client = newSocket()
|
||||||
|
## var address = ""
|
||||||
|
## while true:
|
||||||
|
## socket.acceptAddr(client, address)
|
||||||
|
## echo("Client connected from: ", address)
|
||||||
|
##
|
||||||
|
|
||||||
{.deadCodeElim: on.}
|
{.deadCodeElim: on.}
|
||||||
import nativesockets, os, strutils, parseutils, times
|
import nativesockets, os, strutils, parseutils, times
|
||||||
export Port, `$`, `==`
|
export Port, `$`, `==`
|
||||||
|
|
||||||
const useWinVersion = defined(Windows) or defined(nimdoc)
|
const useWinVersion = defined(Windows) or defined(nimdoc)
|
||||||
|
const defineSsl = defined(ssl) or defined(nimdoc)
|
||||||
|
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
import openssl
|
import openssl
|
||||||
|
|
||||||
# Note: The enumerations are mapped to Window's constants.
|
# Note: The enumerations are mapped to Window's constants.
|
||||||
|
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
type
|
type
|
||||||
SslError* = object of Exception
|
SslError* = object of Exception
|
||||||
|
|
||||||
|
|
@ -54,7 +111,7 @@ type
|
||||||
currPos: int # current index in buffer
|
currPos: int # current index in buffer
|
||||||
bufLen: int # current length of buffer
|
bufLen: int # current length of buffer
|
||||||
of false: nil
|
of false: nil
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
case isSsl: bool
|
case isSsl: bool
|
||||||
of true:
|
of true:
|
||||||
sslHandle: SSLPtr
|
sslHandle: SSLPtr
|
||||||
|
|
@ -160,7 +217,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = newSocket(fd, domain, sockType, protocol, buffered)
|
result = newSocket(fd, domain, sockType, protocol, buffered)
|
||||||
|
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
CRYPTO_malloc_init()
|
CRYPTO_malloc_init()
|
||||||
SslLibraryInit()
|
SslLibraryInit()
|
||||||
SslLoadErrorStrings()
|
SslLoadErrorStrings()
|
||||||
|
|
@ -301,7 +358,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
|
||||||
## error was caused by no data being available to be read.
|
## error was caused by no data being available to be read.
|
||||||
##
|
##
|
||||||
## If ``err`` is not lower than 0 no exception will be raised.
|
## If ``err`` is not lower than 0 no exception will be raised.
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
if err <= 0:
|
if err <= 0:
|
||||||
var ret = SSLGetError(socket.sslHandle, err.cint)
|
var ret = SSLGetError(socket.sslHandle, err.cint)
|
||||||
|
|
@ -334,7 +391,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
|
||||||
raiseSSLError()
|
raiseSSLError()
|
||||||
else: raiseSSLError("Unknown Error")
|
else: raiseSSLError("Unknown Error")
|
||||||
|
|
||||||
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
|
if err == -1 and not (when defineSsl: socket.isSSL else: false):
|
||||||
var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
|
var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
|
||||||
if async:
|
if async:
|
||||||
when useWinVersion:
|
when useWinVersion:
|
||||||
|
|
@ -414,7 +471,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
client.isBuffered = server.isBuffered
|
client.isBuffered = server.isBuffered
|
||||||
|
|
||||||
# Handle SSL.
|
# Handle SSL.
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if server.isSSL:
|
if server.isSSL:
|
||||||
# We must wrap the client sock in a ssl context.
|
# We must wrap the client sock in a ssl context.
|
||||||
|
|
||||||
|
|
@ -425,7 +482,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
# Client socket is set above.
|
# Client socket is set above.
|
||||||
address = $inet_ntoa(sockAddress.sin_addr)
|
address = $inet_ntoa(sockAddress.sin_addr)
|
||||||
|
|
||||||
when false: #defined(ssl):
|
when false: #defineSsl:
|
||||||
proc acceptAddrSSL*(server: Socket, client: var Socket,
|
proc acceptAddrSSL*(server: Socket, client: var Socket,
|
||||||
address: var string): SSLAcceptResult {.
|
address: var string): SSLAcceptResult {.
|
||||||
tags: [ReadIOEffect].} =
|
tags: [ReadIOEffect].} =
|
||||||
|
|
@ -444,7 +501,7 @@ when false: #defined(ssl):
|
||||||
## ``AcceptNoClient`` will be returned when no client is currently attempting
|
## ``AcceptNoClient`` will be returned when no client is currently attempting
|
||||||
## to connect.
|
## to connect.
|
||||||
template doHandshake(): stmt =
|
template doHandshake(): stmt =
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if server.isSSL:
|
if server.isSSL:
|
||||||
client.setBlocking(false)
|
client.setBlocking(false)
|
||||||
# We must wrap the client sock in a ssl context.
|
# We must wrap the client sock in a ssl context.
|
||||||
|
|
@ -495,7 +552,7 @@ proc accept*(server: Socket, client: var Socket,
|
||||||
proc close*(socket: Socket) =
|
proc close*(socket: Socket) =
|
||||||
## Closes a socket.
|
## Closes a socket.
|
||||||
try:
|
try:
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
ErrClearError()
|
ErrClearError()
|
||||||
# As we are closing the underlying socket immediately afterwards,
|
# As we are closing the underlying socket immediately afterwards,
|
||||||
|
|
@ -547,7 +604,7 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {
|
||||||
var valuei = cint(if value: 1 else: 0)
|
var valuei = cint(if value: 1 else: 0)
|
||||||
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
|
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
|
||||||
|
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
## This proc needs to be called on a socket after it connects. This is
|
## This proc needs to be called on a socket after it connects. This is
|
||||||
## only applicable when using ``connectAsync``.
|
## only applicable when using ``connectAsync``.
|
||||||
|
|
@ -594,7 +651,7 @@ proc hasDataBuffered*(s: Socket): 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):
|
when defineSsl:
|
||||||
if s.isSSL and not result:
|
if s.isSSL and not result:
|
||||||
result = s.sslHasPeekChar
|
result = s.sslHasPeekChar
|
||||||
|
|
||||||
|
|
@ -608,7 +665,7 @@ proc select(readfd: Socket, timeout = 500): int =
|
||||||
|
|
||||||
proc readIntoBuf(socket: Socket, flags: int32): int =
|
proc readIntoBuf(socket: Socket, flags: int32): int =
|
||||||
result = 0
|
result = 0
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
|
result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
|
||||||
else:
|
else:
|
||||||
|
|
@ -658,7 +715,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
|
||||||
|
|
||||||
result = read
|
result = read
|
||||||
else:
|
else:
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
if socket.sslHasPeekChar:
|
if socket.sslHasPeekChar:
|
||||||
copyMem(data, addr(socket.sslPeekChar), 1)
|
copyMem(data, addr(socket.sslPeekChar), 1)
|
||||||
|
|
@ -696,7 +753,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
|
||||||
if timeout - int(waited * 1000.0) < 1:
|
if timeout - int(waited * 1000.0) < 1:
|
||||||
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
|
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
|
||||||
|
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
if socket.hasDataBuffered:
|
if socket.hasDataBuffered:
|
||||||
# sslPeekChar is present.
|
# sslPeekChar is present.
|
||||||
|
|
@ -764,7 +821,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
|
||||||
|
|
||||||
c = socket.buffer[socket.currPos]
|
c = socket.buffer[socket.currPos]
|
||||||
else:
|
else:
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
if not socket.sslHasPeekChar:
|
if not socket.sslHasPeekChar:
|
||||||
result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
|
result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
|
||||||
|
|
@ -872,7 +929,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {.
|
||||||
##
|
##
|
||||||
## **Note**: This is a low-level version of ``send``. You likely should use
|
## **Note**: This is a low-level version of ``send``. You likely should use
|
||||||
## the version below.
|
## the version below.
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
return SSLWrite(socket.sslHandle, cast[cstring](data), size)
|
return SSLWrite(socket.sslHandle, cast[cstring](data), size)
|
||||||
|
|
||||||
|
|
@ -943,7 +1000,7 @@ proc sendTo*(socket: Socket, address: string, port: Port,
|
||||||
|
|
||||||
proc isSsl*(socket: Socket): bool =
|
proc isSsl*(socket: Socket): bool =
|
||||||
## Determines whether ``socket`` is a SSL socket.
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
result = socket.isSSL
|
result = socket.isSSL
|
||||||
else:
|
else:
|
||||||
result = false
|
result = false
|
||||||
|
|
@ -1253,7 +1310,7 @@ proc connect*(socket: Socket, address: string,
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
if not success: raiseOSError(lastError)
|
if not success: raiseOSError(lastError)
|
||||||
|
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
# RFC3546 for SNI specifies that IP addresses are not allowed.
|
# RFC3546 for SNI specifies that IP addresses are not allowed.
|
||||||
if not isIpAddress(address):
|
if not isIpAddress(address):
|
||||||
|
|
@ -1314,7 +1371,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
|
||||||
if selectWrite(s, timeout) != 1:
|
if selectWrite(s, timeout) != 1:
|
||||||
raise newException(TimeoutError, "Call to 'connect' timed out.")
|
raise newException(TimeoutError, "Call to 'connect' timed out.")
|
||||||
else:
|
else:
|
||||||
when defined(ssl):
|
when defineSsl:
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
socket.fd.setBlocking(true)
|
socket.fd.setBlocking(true)
|
||||||
doAssert socket.handshake()
|
doAssert socket.handshake()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue