summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@googlemail.com>2015-06-25 21:14:40 +0100
committerDominik Picheta <dominikpicheta@googlemail.com>2015-06-25 21:14:40 +0100
commit3ff5e1a1af57d12ea759b72185d56386c63549a4 (patch)
tree59e8ca12a002a165de54b58ecf1554a050ec4cee
parent43c64c7545e155768e117c1894bf1a78af0bf5a8 (diff)
parentc4a25d23b6220cd5740b40d8c20e8dcde45310bc (diff)
downloadNim-3ff5e1a1af57d12ea759b72185d56386c63549a4.tar.gz
Merge pull request #2976 from ayourtch/ipv6-devel
Ipv6 devel - add IPv6 support for asyncsockets, make AF_INET6 a default
-rw-r--r--lib/posix/posix.nim7
-rw-r--r--lib/pure/asyncdispatch.nim9
-rw-r--r--lib/pure/asyncnet.nim29
-rw-r--r--lib/pure/rawsockets.nim31
4 files changed, 54 insertions, 22 deletions
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index dba79cbf6..9b9bf390a 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -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.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 550b82f49..5a059ec8e 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -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
 
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 712bba33b..d7ac60147 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -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.
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index 6d656c983..9bfe9dab5 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -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