Merge pull request #7336 from yglukhov/ipaddr-sockaddr-conversions

Conversion procs for (IpAddress, Port) <-> (SockAddr, Socklen)
This commit is contained in:
Dominik Picheta
2018-04-02 14:31:05 +01:00
committed by GitHub
4 changed files with 76 additions and 2 deletions

View File

@@ -31,7 +31,7 @@ else:
export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
Sockaddr_in6,
Sockaddr_in6, Sockaddr_storage,
inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto,
freeAddrInfo

View File

@@ -414,6 +414,43 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} =
return false
return true
proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl: var Socklen) =
## Converts `IpAddress` and `Port` to `SockAddr` and `Socklen`
let port = htons(uint16(port))
case address.family
of IpAddressFamily.IPv4:
sl = sizeof(Sockaddr_in).Socklen
let s = cast[ptr Sockaddr_in](addr sa)
s.sin_family = type(s.sin_family)(AF_INET)
s.sin_port = port
copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr))
of IpAddressFamily.IPv6:
sl = sizeof(Sockaddr_in6).Socklen
let s = cast[ptr Sockaddr_in6](addr sa)
s.sin6_family = type(s.sin6_family)(AF_INET6)
s.sin6_port = port
copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr))
proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) =
if sa.ss_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen:
address = IpAddress(family: IpAddressFamily.IPv4)
let s = cast[ptr Sockaddr_in](sa)
copyMem(addr address.address_v4[0], addr s.sin_addr, sizeof(address.address_v4))
port = ntohs(s.sin_port).Port
elif sa.ss_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen:
address = IpAddress(family: IpAddressFamily.IPv6)
let s = cast[ptr Sockaddr_in6](sa)
copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6))
port = ntohs(s.sin6_port).Port
else:
raise newException(ValueError, "Neither IPv4 nor IPv6")
proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6,
sl: Socklen, address: var IpAddress, port: var Port) {.inline.} =
## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises
## `ObjectConversionError` in case of invalid `sa` and `sl` arguments.
fromSockAddrAux(unsafeAddr sa, sl, address, port)
when defineSsl:
CRYPTO_malloc_init()
doAssert SslLibraryInit() == 1

View File

@@ -481,6 +481,13 @@ type
sin6_flowinfo*: int32 # unsigned
sin6_addr*: In6_addr
Sockaddr_storage* {.importc: "SOCKADDR_STORAGE",
header: "winsock2.h".} = object
ss_family*: int16
ss_pad1: array[6, byte]
ss_align: int64
ss_pad2: array[112, byte]
Servent* = object
s_name*: cstring
s_aliases*: cstringArray

View File

@@ -1,4 +1,4 @@
import net
import net, nativesockets
import unittest
suite "isIpAddress tests":
@@ -45,3 +45,33 @@ suite "parseIpAddress tests":
test "invalid ipv6":
expect(ValueError):
discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652")
block: # "IpAddress/Sockaddr conversion"
proc test(ipaddrstr: string) =
var ipaddr_1 = parseIpAddress(ipaddrstr)
# echo ipaddrstr, " ", $ipaddr_1
doAssert($ipaddrstr == $ipaddr_1)
var sockaddr: Sockaddr_storage
var socklen: Socklen
var ipaddr_2: IpAddress
var port_2: Port
toSockAddr(ipaddr_1, Port(0), sockaddr, socklen)
fromSockAddr(sockaddr, socklen, ipaddr_2, port_2)
doAssert(ipaddrstr == $ipaddr_1)
doAssert(ipaddr_1 == ipaddr_2)
doAssert($ipaddr_1 == $ipaddr_2)
# ipv6 address of example.com
test("2606:2800:220:1:248:1893:25c8:1946")
# ipv6 address of localhost
test("::1")
# ipv4 address of example.com
test("93.184.216.34")
# ipv4 address of localhost
test("127.0.0.1")