Net module fixes (#8597)
* net.accept no longer needs an initialised socket. Fixes #7848. * Assert error when using sendTo/recvFrom on TCP socket. * net.sendTo now raises OSError.
This commit is contained in:
parent
a42150f9a8
commit
6e83746caa
2 changed files with 19 additions and 17 deletions
|
|
@ -72,6 +72,7 @@
|
||||||
- ``lineInfoObj`` now returns absolute path instead of project path.
|
- ``lineInfoObj`` now returns absolute path instead of project path.
|
||||||
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
|
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
|
||||||
|
|
||||||
|
- ``net.sendTo`` no longer returns an int and now raises an ``OSError``.
|
||||||
- `threadpool`'s `await` and derivatives have been renamed to `blockUntil`
|
- `threadpool`'s `await` and derivatives have been renamed to `blockUntil`
|
||||||
to avoid confusions with `await` from the `async` macro.
|
to avoid confusions with `await` from the `async` macro.
|
||||||
|
|
||||||
|
|
@ -140,6 +141,8 @@
|
||||||
- The ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal``
|
- The ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal``
|
||||||
object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs``
|
object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs``
|
||||||
iterators.
|
iterators.
|
||||||
|
- The ``accept`` socket procedure defined in the ``net`` module can now accept
|
||||||
|
a nil socket.
|
||||||
|
|
||||||
### Language additions
|
### Language additions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,15 +58,11 @@
|
||||||
## You can then begin accepting connections using the ``accept`` procedure.
|
## You can then begin accepting connections using the ``accept`` procedure.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## var client = new Socket
|
## var client: Socket
|
||||||
## var address = ""
|
## var address = ""
|
||||||
## while true:
|
## while true:
|
||||||
## socket.acceptAddr(client, address)
|
## socket.acceptAddr(client, address)
|
||||||
## echo("Client connected from: ", address)
|
## echo("Client connected from: ", address)
|
||||||
##
|
|
||||||
## **Note:** The ``client`` variable is initialised with ``new Socket`` **not**
|
|
||||||
## ``newSocket()``. The difference is that the latter creates a new file
|
|
||||||
## descriptor.
|
|
||||||
|
|
||||||
{.deadCodeElim: on.} # dce option deprecated
|
{.deadCodeElim: on.} # dce option deprecated
|
||||||
import nativesockets, os, strutils, parseutils, times, sets, options
|
import nativesockets, os, strutils, parseutils, times, sets, options
|
||||||
|
|
@ -789,16 +785,12 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
## The resulting client will inherit any properties of the server socket. For
|
## The resulting client will inherit any properties of the server socket. For
|
||||||
## example: whether the socket is buffered or not.
|
## example: whether the socket is buffered or not.
|
||||||
##
|
##
|
||||||
## **Note**: ``client`` must be initialised (with ``new``), this function
|
|
||||||
## makes no effort to initialise the ``client`` variable.
|
|
||||||
##
|
|
||||||
## The ``accept`` call may result in an error if the connecting socket
|
## The ``accept`` call may result in an error if the connecting socket
|
||||||
## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
|
## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
|
||||||
## flag is specified then this error will not be raised and instead
|
## flag is specified then this error will not be raised and instead
|
||||||
## accept will be called again.
|
## accept will be called again.
|
||||||
assert(client != nil)
|
if client.isNil:
|
||||||
assert client.fd.int <= 0, "Client socket needs to be initialised with " &
|
new(client)
|
||||||
"`new`, not `newSocket`."
|
|
||||||
let ret = accept(server.fd)
|
let ret = accept(server.fd)
|
||||||
let sock = ret[0]
|
let sock = ret[0]
|
||||||
|
|
||||||
|
|
@ -879,9 +871,6 @@ proc accept*(server: Socket, client: var Socket,
|
||||||
## Equivalent to ``acceptAddr`` but doesn't return the address, only the
|
## Equivalent to ``acceptAddr`` but doesn't return the address, only the
|
||||||
## socket.
|
## socket.
|
||||||
##
|
##
|
||||||
## **Note**: ``client`` must be initialised (with ``new``), this function
|
|
||||||
## makes no effort to initialise the ``client`` variable.
|
|
||||||
##
|
|
||||||
## The ``accept`` call may result in an error if the connecting socket
|
## The ``accept`` call may result in an error if the connecting socket
|
||||||
## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
|
## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
|
||||||
## flag is specified then this error will not be raised and instead
|
## flag is specified then this error will not be raised and instead
|
||||||
|
|
@ -1339,6 +1328,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
|
||||||
## used. Therefore if ``socket`` contains something in its buffer this
|
## used. Therefore if ``socket`` contains something in its buffer this
|
||||||
## function will make no effort to return it.
|
## function will make no effort to return it.
|
||||||
|
|
||||||
|
assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
|
||||||
# TODO: Buffered sockets
|
# TODO: Buffered sockets
|
||||||
data.setLen(length)
|
data.setLen(length)
|
||||||
var sockAddress: Sockaddr_in
|
var sockAddress: Sockaddr_in
|
||||||
|
|
@ -1408,22 +1398,25 @@ proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
|
||||||
result = send(socket, cstring(data), data.len) == data.len
|
result = send(socket, cstring(data), data.len) == data.len
|
||||||
|
|
||||||
proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
|
proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
|
||||||
size: int, af: Domain = AF_INET, flags = 0'i32): int {.
|
size: int, af: Domain = AF_INET, flags = 0'i32) {.
|
||||||
tags: [WriteIOEffect].} =
|
tags: [WriteIOEffect].} =
|
||||||
## This proc sends ``data`` to the specified ``address``,
|
## This proc sends ``data`` to the specified ``address``,
|
||||||
## which may be an IP address or a hostname, if a hostname is specified
|
## which may be an IP address or a hostname, if a hostname is specified
|
||||||
## this function will try each IP of that hostname.
|
## this function will try each IP of that hostname.
|
||||||
##
|
##
|
||||||
|
## If an error occurs an OSError exception will be raised.
|
||||||
##
|
##
|
||||||
## **Note:** You may wish to use the high-level version of this function
|
## **Note:** You may wish to use the high-level version of this function
|
||||||
## which is defined below.
|
## which is defined below.
|
||||||
##
|
##
|
||||||
## **Note:** This proc is not available for SSL sockets.
|
## **Note:** This proc is not available for SSL sockets.
|
||||||
|
assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket")
|
||||||
assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
|
assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
|
||||||
var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol)
|
var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var it = aiList
|
var it = aiList
|
||||||
|
var result = 0
|
||||||
while it != nil:
|
while it != nil:
|
||||||
result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
|
result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
|
||||||
it.ai_addrlen.SockLen)
|
it.ai_addrlen.SockLen)
|
||||||
|
|
@ -1432,16 +1425,22 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
|
||||||
break
|
break
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
|
let osError = osLastError()
|
||||||
freeAddrInfo(aiList)
|
freeAddrInfo(aiList)
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
raiseOSError(osError)
|
||||||
|
|
||||||
proc sendTo*(socket: Socket, address: string, port: Port,
|
proc sendTo*(socket: Socket, address: string, port: Port,
|
||||||
data: string): int {.tags: [WriteIOEffect].} =
|
data: string) {.tags: [WriteIOEffect].} =
|
||||||
## This proc sends ``data`` to the specified ``address``,
|
## This proc sends ``data`` to the specified ``address``,
|
||||||
## which may be an IP address or a hostname, if a hostname is specified
|
## which may be an IP address or a hostname, if a hostname is specified
|
||||||
## this function will try each IP of that hostname.
|
## this function will try each IP of that hostname.
|
||||||
##
|
##
|
||||||
|
## If an error occurs an OSError exception will be raised.
|
||||||
|
##
|
||||||
## This is the high-level version of the above ``sendTo`` function.
|
## This is the high-level version of the above ``sendTo`` function.
|
||||||
result = socket.sendTo(address, port, cstring(data), data.len, socket.domain )
|
socket.sendTo(address, port, cstring(data), data.len, socket.domain)
|
||||||
|
|
||||||
|
|
||||||
proc isSsl*(socket: Socket): bool =
|
proc isSsl*(socket: Socket): bool =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue