summary refs log tree commit diff stats
path: root/lib/pure
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 /lib/pure
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
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/asyncdispatch.nim9
-rw-r--r--lib/pure/asyncnet.nim29
-rw-r--r--lib/pure/rawsockets.nim31
3 files changed, 49 insertions, 20 deletions
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