put API changes behind a flag (#19685)

This commit is contained in:
Miran
2022-04-07 20:56:39 +02:00
committed by GitHub
parent dcc40b9609
commit bb937f2357
3 changed files with 123 additions and 67 deletions

View File

@@ -155,10 +155,16 @@ when not defined(zephyr):
proc inet_addr*(a1: cstring): InAddrT {.importc, header: "<arpa/inet.h>".}
proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".}
proc inet_ntop*(a1: cint, a2: pointer | ptr InAddr | ptr In6Addr, a3: cstring, a4: int32): cstring {.
importc:"(char *)$1", header: "<arpa/inet.h>".}
proc inet_pton*(a1: cint, a2: cstring, a3: pointer | ptr InAddr | ptr In6Addr): cint {.
importc, header: "<arpa/inet.h>".}
when defined(zephyr): # this switch is done to keep Nim 1.6 API backward compatible
proc inet_ntop*(a1: cint, a2: pointer | ptr InAddr | ptr In6Addr, a3: cstring, a4: int32): cstring {.
importc:"(char *)$1", header: "<arpa/inet.h>".}
proc inet_pton*(a1: cint, a2: cstring, a3: pointer | ptr InAddr | ptr In6Addr): cint {.
importc, header: "<arpa/inet.h>".}
else:
proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {.
importc:"(char *)$1", header: "<arpa/inet.h>".}
proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {.
importc, header: "<arpa/inet.h>".}
var
in6addr_any* {.importc, header: "<netinet/in.h>".}: In6Addr

View File

@@ -65,10 +65,11 @@ runnableExamples("-r:off"):
let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
socket.sendTo("192.168.0.1", Port(27960), "status\n")
runnableExamples("-r:off"):
let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
let ip = parseIpAddress("192.168.0.1")
doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8
when defined(zephyr):
runnableExamples("-r:off"):
let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
let ip = parseIpAddress("192.168.0.1")
doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8
## Creating a server
## -----------------
@@ -1612,53 +1613,98 @@ proc recvLine*(socket: Socket, timeout = -1,
result = ""
readLine(socket, result, timeout, flags, maxLength)
proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int,
address: var T, port: var Port, flags = 0'i32): int {.
tags: [ReadIOEffect].} =
## Receives data from `socket`. This function should normally be used with
## connection-less sockets (UDP sockets). The source address of the data
## packet is stored in the `address` argument as either a string or an IpAddress.
##
## If an error occurs an OSError exception will be raised. Otherwise the return
## value will be the length of data received.
##
## .. warning:: This function does not yet have a buffered implementation,
## so when `socket` is buffered the non-buffered implementation will be
## used. Therefore if `socket` contains something in its buffer this
## function will make no effort to return it.
template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) =
var addrLen = sizeof(sockAddress).SockLen
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
if result != -1:
data.setLen(result)
when defined(zephyr): # this switch is done to keep Nim 1.6 API backward compatible
proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int,
address: var T, port: var Port, flags = 0'i32): int {.
tags: [ReadIOEffect].} =
## Receives data from `socket`. This function should normally be used with
## connection-less sockets (UDP sockets). The source address of the data
## packet is stored in the `address` argument as either a string or an IpAddress.
##
## If an error occurs an OSError exception will be raised. Otherwise the return
## value will be the length of data received.
##
## .. warning:: This function does not yet have a buffered implementation,
## so when `socket` is buffered the non-buffered implementation will be
## used. Therefore if `socket` contains something in its buffer this
## function will make no effort to return it.
template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) =
var addrLen = sizeof(sockAddress).SockLen
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
when typeof(address) is string:
if result != -1:
data.setLen(result)
when typeof(address) is string:
address = getAddrString(cast[ptr SockAddr](addr(sockAddress)))
when domain == AF_INET6:
port = ntohs(sockAddress.sin6_port).Port
else:
port = ntohs(sockAddress.sin_port).Port
else:
data.setLen(result)
sockAddress.fromSockAddr(addrLen, address, port)
else:
raiseOSError(osLastError())
assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
# TODO: Buffered sockets
data.setLen(length)
case socket.domain
of AF_INET6:
var sockAddress: Sockaddr_in6
adaptRecvFromToDomain(sockAddress, AF_INET6)
of AF_INET:
var sockAddress: Sockaddr_in
adaptRecvFromToDomain(sockAddress, AF_INET)
else:
raise newException(ValueError, "Unknown socket address family")
else:
proc recvFrom*(socket: Socket, data: var string, length: int,
address: var string, port: var Port, flags = 0'i32): int {.
tags: [ReadIOEffect].} =
## Receives data from `socket`. This function should normally be used with
## connection-less sockets (UDP sockets).
##
## If an error occurs an OSError exception will be raised. Otherwise the return
## value will be the length of data received.
##
## .. warning:: This function does not yet have a buffered implementation,
## so when `socket` is buffered the non-buffered implementation will be
## used. Therefore if `socket` contains something in its buffer this
## function will make no effort to return it.
template adaptRecvFromToDomain(domain: Domain) =
var addrLen = SockLen(sizeof(sockAddress))
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
if result != -1:
data.setLen(result)
address = getAddrString(cast[ptr SockAddr](addr(sockAddress)))
when domain == AF_INET6:
port = ntohs(sockAddress.sin6_port).Port
else:
port = ntohs(sockAddress.sin_port).Port
else:
data.setLen(result)
sockAddress.fromSockAddr(addrLen, address, port)
raiseOSError(osLastError())
assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
# TODO: Buffered sockets
data.setLen(length)
case socket.domain
of AF_INET6:
var sockAddress: Sockaddr_in6
adaptRecvFromToDomain(AF_INET6)
of AF_INET:
var sockAddress: Sockaddr_in
adaptRecvFromToDomain(AF_INET)
else:
raiseOSError(osLastError())
raise newException(ValueError, "Unknown socket address family")
assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
# TODO: Buffered sockets
data.setLen(length)
case socket.domain
of AF_INET6:
var sockAddress: Sockaddr_in6
adaptRecvFromToDomain(sockAddress, AF_INET6)
of AF_INET:
var sockAddress: Sockaddr_in
adaptRecvFromToDomain(sockAddress, AF_INET)
else:
raise newException(ValueError, "Unknown socket address family")
proc skip*(socket: Socket, size: int, timeout = -1) =
## Skips `size` amount of bytes.
@@ -1762,29 +1808,30 @@ proc sendTo*(socket: Socket, address: string, port: Port,
## This is the high-level version of the above `sendTo` function.
socket.sendTo(address, port, cstring(data), data.len, socket.domain)
proc sendTo*(socket: Socket, address: IpAddress, port: Port,
data: string, flags = 0'i32): int {.
discardable, tags: [WriteIOEffect].} =
## This proc sends `data` to the specified `IpAddress` and returns
## the number of bytes written.
##
## Generally for use with connection-less (UDP) sockets.
##
## If an error occurs an OSError exception will be raised.
##
## This is the high-level version of the above `sendTo` function.
assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket")
assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
when defined(zephyr):
proc sendTo*(socket: Socket, address: IpAddress, port: Port,
data: string, flags = 0'i32): int {.
discardable, tags: [WriteIOEffect].} =
## This proc sends `data` to the specified `IpAddress` and returns
## the number of bytes written.
##
## Generally for use with connection-less (UDP) sockets.
##
## If an error occurs an OSError exception will be raised.
##
## This is the high-level version of the above `sendTo` function.
assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket")
assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
var sa: Sockaddr_storage
var sl: SockLen
toSockAddr(address, port, sa, sl)
result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint,
cast[ptr SockAddr](addr sa), sl)
var sa: Sockaddr_storage
var sl: SockLen
toSockAddr(address, port, sa, sl)
result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint,
cast[ptr SockAddr](addr sa), sl)
if result == -1'i32:
let osError = osLastError()
raiseOSError(osError)
if result == -1'i32:
let osError = osLastError()
raiseOSError(osError)
proc isSsl*(socket: Socket): bool =

View File

@@ -41,7 +41,10 @@ suite "inet_ntop tests":
var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001]
var buff: array[0..255, char]
let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), buff[0].addr, buff.len.int32)
when defined(zephyr):
let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), buff[0].addr, buff.len.int32)
else:
let r = inet_ntop(AF_INET6, ip6[0].addr, buff[0].addr, buff.sizeof.int32)
let res = if r == nil: "" else: $r
check: not ipv6Support or res == "10:110:20:120:30:130:40:140"