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:
Dominik Picheta
2015-06-25 21:14:40 +01:00
4 changed files with 54 additions and 22 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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