mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
Merge pull request #2976 from ayourtch/ipv6-devel
Ipv6 devel - add IPv6 support for asyncsockets, make AF_INET6 a default
This commit is contained in:
@@ -448,7 +448,7 @@ type
|
||||
sa_family*: TSa_Family ## Address family.
|
||||
sa_data*: array [0..255, char] ## Socket address (variable-length data).
|
||||
|
||||
Tsockaddr_storage* {.importc: "struct sockaddr_storage",
|
||||
Sockaddr_storage* {.importc: "struct sockaddr_storage",
|
||||
header: "<sys/socket.h>",
|
||||
pure, final.} = object ## struct sockaddr_storage
|
||||
ss_family*: TSa_Family ## Address family.
|
||||
@@ -506,7 +506,7 @@ type
|
||||
header: "<netinet/in.h>".} = object ## struct in6_addr
|
||||
s6_addr*: array [0..15, char]
|
||||
|
||||
Tsockaddr_in6* {.importc: "struct sockaddr_in6", pure, final,
|
||||
Sockaddr_in6* {.importc: "struct sockaddr_in6", pure, final,
|
||||
header: "<netinet/in.h>".} = object ## struct sockaddr_in6
|
||||
sin6_family*: TSa_Family ## AF_INET6.
|
||||
sin6_port*: InPort ## Port number.
|
||||
@@ -581,6 +581,7 @@ type
|
||||
|
||||
{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
|
||||
TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
|
||||
Tsockaddr_storage: Sockaddr_storage, Tsockaddr_in6: Sockaddr_in6,
|
||||
Thostent: Hostent, TServent: Servent,
|
||||
TInAddr: InAddr, TIOVec: IOVec, TInPort: InPort, TInAddrT: InAddrT,
|
||||
TIn6Addr: In6Addr, TInAddrScalar: InAddrScalar, TProtoent: Protoent].}
|
||||
@@ -1662,6 +1663,8 @@ var
|
||||
|
||||
INET_ADDRSTRLEN* {.importc, header: "<netinet/in.h>".}: cint
|
||||
## 16. Length of the string form for IP.
|
||||
INET6_ADDRSTRLEN* {.importc, header: "<netinet/in.h>".}: cint
|
||||
## Length of the string form for IPv6.
|
||||
|
||||
IPV6_JOIN_GROUP* {.importc, header: "<netinet/in.h>".}: cint
|
||||
## Join a multicast group.
|
||||
|
||||
@@ -1009,7 +1009,7 @@ else:
|
||||
processTimers(p)
|
||||
|
||||
proc connect*(socket: AsyncFD, address: string, port: Port,
|
||||
af = AF_INET): Future[void] =
|
||||
af_unused = AF_INET): Future[void] =
|
||||
var retFuture = newFuture[void]("connect")
|
||||
|
||||
proc cb(fd: AsyncFD): bool =
|
||||
@@ -1017,7 +1017,8 @@ else:
|
||||
retFuture.complete()
|
||||
return true
|
||||
|
||||
var aiList = getAddrInfo(address, port, af)
|
||||
var sockDomain = getSockDomain(socket.SocketHandle)
|
||||
var aiList = getAddrInfo(address, port, sockDomain)
|
||||
var success = false
|
||||
var lastError: OSErrorCode
|
||||
var it = aiList
|
||||
@@ -1135,7 +1136,7 @@ else:
|
||||
client: AsyncFD]]("acceptAddr")
|
||||
proc cb(sock: AsyncFD): bool =
|
||||
result = true
|
||||
var sockAddress: SockAddr_in
|
||||
var sockAddress: Sockaddr_storage
|
||||
var addrLen = sizeof(sockAddress).Socklen
|
||||
var client = accept(sock.SocketHandle,
|
||||
cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
|
||||
@@ -1151,7 +1152,7 @@ else:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||
else:
|
||||
register(client.AsyncFD)
|
||||
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.AsyncFD))
|
||||
retFuture.complete((getAddrString(cast[ptr SockAddr](addr sockAddress)), client.AsyncFD))
|
||||
addRead(socket, cb)
|
||||
return retFuture
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ proc newAsyncSocket*(fd: AsyncFD, buffered = true): AsyncSocket =
|
||||
if buffered:
|
||||
result.currPos = 0
|
||||
|
||||
proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||
proc newAsyncSocket*(domain: Domain = AF_INET6, typ: SockType = SOCK_STREAM,
|
||||
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
|
||||
## Creates a new asynchronous socket.
|
||||
##
|
||||
@@ -423,24 +423,21 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
|
||||
## Binds ``address``:``port`` to the socket.
|
||||
##
|
||||
## If ``address`` is "" then ADDR_ANY will be bound.
|
||||
var sockDomain = getSockDomain(socket.fd)
|
||||
|
||||
if address == "":
|
||||
var name: Sockaddr_in
|
||||
when defined(Windows) or defined(nimdoc):
|
||||
name.sin_family = toInt(AF_INET).int16
|
||||
var realaddr = address
|
||||
if realaddr == "":
|
||||
case sockDomain
|
||||
of AF_INET6: realaddr = "::"
|
||||
of AF_INET: realaddr = "0.0.0.0"
|
||||
else:
|
||||
name.sin_family = toInt(AF_INET)
|
||||
name.sin_port = htons(int16(port))
|
||||
name.sin_addr.s_addr = htonl(INADDR_ANY)
|
||||
if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)),
|
||||
sizeof(name).Socklen) < 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
var aiList = getAddrInfo(address, port, AF_INET)
|
||||
if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
|
||||
dealloc(aiList)
|
||||
raiseOSError(osLastError())
|
||||
raiseOSError("Unknown socket address family and no address specified to bindAddr")
|
||||
|
||||
var aiList = getAddrInfo(realaddr, port, sockDomain)
|
||||
if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
|
||||
dealloc(aiList)
|
||||
raiseOSError(osLastError())
|
||||
dealloc(aiList)
|
||||
|
||||
proc close*(socket: AsyncSocket) =
|
||||
## Closes the socket.
|
||||
|
||||
@@ -29,6 +29,7 @@ else:
|
||||
EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET
|
||||
|
||||
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
|
||||
Sockaddr_in6, Sockaddr_storage,
|
||||
inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto
|
||||
|
||||
export
|
||||
@@ -194,6 +195,7 @@ proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockTy
|
||||
hints.ai_family = toInt(af)
|
||||
hints.ai_socktype = toInt(typ)
|
||||
hints.ai_protocol = toInt(prot)
|
||||
hints.ai_flags = posix.AI_V4MAPPED
|
||||
var gaiResult = getaddrinfo(address, $port, addr(hints), result)
|
||||
if gaiResult != 0'i32:
|
||||
when useWinVersion:
|
||||
@@ -315,6 +317,35 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
|
||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||
result.length = int(s.h_length)
|
||||
|
||||
proc getSockDomain*(socket: SocketHandle): Domain =
|
||||
## returns the socket's domain (AF_INET or AF_INET6).
|
||||
var name: SockAddr
|
||||
var namelen = sizeof(name).SockLen
|
||||
if getsockname(socket, cast[ptr SockAddr](addr(name)),
|
||||
addr(namelen)) == -1'i32:
|
||||
raiseOSError(osLastError())
|
||||
if name.sa_family == posix.AF_INET:
|
||||
result = AF_INET
|
||||
elif name.sa_family == posix.AF_INET6:
|
||||
result = AF_INET6
|
||||
else:
|
||||
raise newException(OSError, "unknown socket family in getSockFamily")
|
||||
|
||||
|
||||
proc getAddrString*(sockAddr: ptr SockAddr): string =
|
||||
## return the string representation of address within sockAddr
|
||||
if sockAddr.sa_family == posix.AF_INET:
|
||||
result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr)
|
||||
elif sockAddr.sa_family == posix.AF_INET6:
|
||||
var v6addr = cast[ptr Sockaddr_in6](sockAddr).sin6_addr
|
||||
result = newString(posix.INET6_ADDRSTRLEN)
|
||||
discard posix.inet_ntop(posix.AF_INET6, addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr, result.cstring, result.len.int32)
|
||||
if posix.IN6_IS_ADDR_V4MAPPED(addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr) != 0:
|
||||
result = result.substr("::ffff:".len)
|
||||
else:
|
||||
raise newException(OSError, "unknown socket family in getAddrString")
|
||||
|
||||
|
||||
proc getSockName*(socket: SocketHandle): Port =
|
||||
## returns the socket's associated port number.
|
||||
var name: Sockaddr_in
|
||||
|
||||
Reference in New Issue
Block a user