summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@googlemail.com>2015-06-29 20:11:21 +0100
committerDominik Picheta <dominikpicheta@googlemail.com>2015-06-29 20:11:21 +0100
commit615defb1a9f4739f365ff56321cec0b1a0d1fde2 (patch)
treef3e3086032752281f616258d39466cb49424c6d2 /lib
parentc16d153ff53732331e7a017a29fc13ccb681a402 (diff)
downloadNim-615defb1a9f4739f365ff56321cec0b1a0d1fde2.tar.gz
Fixes socket problems on Windows and normalises some names.
Ref #2976. Ref #2003. See news.txt for details.
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/asyncdispatch.nim33
-rw-r--r--lib/pure/asyncnet.nim37
-rw-r--r--lib/pure/net.nim37
-rw-r--r--lib/pure/rawsockets.nim19
4 files changed, 72 insertions, 54 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 547880f06..3d1992244 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -483,7 +483,7 @@ when defined(windows) or defined(nimdoc):
                   RemoteSockaddr, RemoteSockaddrLength)
 
   proc connect*(socket: AsyncFD, address: string, port: Port,
-    af = rawsockets.AF_INET): Future[void] =
+    domain = rawsockets.AF_INET): Future[void] =
     ## Connects ``socket`` to server at ``address:port``.
     ##
     ## Returns a ``Future`` which will complete when the connection succeeds
@@ -492,14 +492,14 @@ when defined(windows) or defined(nimdoc):
     var retFuture = newFuture[void]("connect")
     # Apparently ``ConnectEx`` expects the socket to be initially bound:
     var saddr: Sockaddr_in
-    saddr.sin_family = int16(toInt(af))
+    saddr.sin_family = int16(toInt(domain))
     saddr.sin_port = 0
     saddr.sin_addr.s_addr = INADDR_ANY
     if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
                   sizeof(saddr).SockLen) < 0'i32:
       raiseOSError(osLastError())
 
-    var aiList = getAddrInfo(address, port, af)
+    var aiList = getAddrInfo(address, port, domain)
     var success = false
     var lastError: OSErrorCode
     var it = aiList
@@ -855,17 +855,17 @@ when defined(windows) or defined(nimdoc):
 
     return retFuture
 
-  proc newAsyncRawSocket*(domain, typ, protocol: cint): AsyncFD =
+  proc newAsyncRawSocket*(domain, sockType, protocol: cint): AsyncFD =
     ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newRawSocket(domain, typ, protocol).AsyncFD
+    result = newRawSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     register(result)
 
   proc newAsyncRawSocket*(domain: Domain = rawsockets.AF_INET,
-               typ: SockType = SOCK_STREAM,
+               sockType: SockType = SOCK_STREAM,
                protocol: Protocol = IPPROTO_TCP): AsyncFD =
     ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newRawSocket(domain, typ, protocol).AsyncFD
+    result = newRawSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     register(result)
 
@@ -928,17 +928,18 @@ else:
     var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
     p.selector.register(fd.SocketHandle, {}, data.RootRef)
 
-  proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): AsyncFD =
-    result = newRawSocket(domain, typ, protocol).AsyncFD
+  proc newAsyncRawSocket*(domain: cint, sockType: cint,
+      protocol: cint): AsyncFD =
+    result = newRawSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     when defined(macosx):
         result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
     register(result)
 
   proc newAsyncRawSocket*(domain: Domain = AF_INET,
-               typ: SockType = SOCK_STREAM,
+               sockType: SockType = SOCK_STREAM,
                protocol: Protocol = IPPROTO_TCP): AsyncFD =
-    result = newRawSocket(domain, typ, protocol).AsyncFD
+    result = newRawSocket(domain, sockType, protocol).AsyncFD
     result.SocketHandle.setBlocking(false)
     when defined(macosx):
         result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
@@ -1009,7 +1010,7 @@ else:
     processTimers(p)
 
   proc connect*(socket: AsyncFD, address: string, port: Port,
-    af_unused = AF_INET): Future[void] =
+    domain = AF_INET): Future[void] =
     var retFuture = newFuture[void]("connect")
 
     proc cb(fd: AsyncFD): bool =
@@ -1017,8 +1018,8 @@ else:
       retFuture.complete()
       return true
 
-    var sockDomain = getSockDomain(socket.SocketHandle)
-    var aiList = getAddrInfo(address, port, sockDomain)
+    assert getSockDomain(socket.SocketHandle) == domain
+    var aiList = getAddrInfo(address, port, domain)
     var success = false
     var lastError: OSErrorCode
     var it = aiList
@@ -1496,8 +1497,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  #if prc[0].getName == "test":
-  #  echo(toStrLit(result))
+  if prc[0].getName == "getAsync":
+    echo(toStrLit(result))
 
 proc recvLine*(socket: AsyncFD): Future[string] {.async.} =
   ## Reads a line of data from ``socket``. Returned future will complete once
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index d7ac60147..cfd3d7666 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -85,35 +85,44 @@ type
         bioIn: BIO
         bioOut: BIO
     of false: nil
+    domain: Domain
+    sockType: SockType
+    protocol: Protocol
   AsyncSocket* = ref AsyncSocketDesc
 
 {.deprecated: [PAsyncSocket: AsyncSocket].}
 
-# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
-
-proc newAsyncSocket*(fd: AsyncFD, buffered = true): AsyncSocket =
+proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET,
+    sockType: SockType = SOCK_STREAM,
+    protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
   ## Creates a new ``AsyncSocket`` based on the supplied params.
   assert fd != osInvalidSocket.AsyncFD
   new(result)
   result.fd = fd.SocketHandle
   result.isBuffered = buffered
+  result.domain = domain
+  result.sockType = sockType
+  result.protocol = protocol
   if buffered:
     result.currPos = 0
 
-proc newAsyncSocket*(domain: Domain = AF_INET6, typ: SockType = SOCK_STREAM,
+proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
     protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
   ## Creates a new asynchronous socket.
   ##
   ## This procedure will also create a brand new file descriptor for
   ## this socket.
-  result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+  result = newAsyncSocket(newAsyncRawSocket(domain, sockType, protocol), domain,
+      sockType, protocol, buffered)
 
-proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
+proc newAsyncSocket*(domain, sockType, protocol: cint,
+    buffered = true): AsyncSocket =
   ## Creates a new asynchronous socket.
   ##
   ## This procedure will also create a brand new file descriptor for
   ## this socket.
-  result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+  result = newAsyncSocket(newAsyncRawSocket(domain, sockType, protocol),
+      Domain(domain), SockType(sockType), Protocol(protocol), buffered)
 
 when defined(ssl):
   proc getSslError(handle: SslPtr, err: cint): cint =
@@ -169,13 +178,12 @@ when defined(ssl):
         let err = getSslError(socket.sslHandle, opResult.cint)
         yield appeaseSsl(socket, flags, err.cint)
 
-proc connect*(socket: AsyncSocket, address: string, port: Port,
-    af = AF_INET) {.async.} =
+proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
   ## Connects ``socket`` to server at ``address:port``.
   ##
   ## Returns a ``Future`` which will complete when the connection succeeds
   ## or an error occurs.
-  await connect(socket.fd.AsyncFD, address, port, af)
+  await connect(socket.fd.AsyncFD, address, port, socket.domain)
   if socket.isSsl:
     when defined(ssl):
       let flags = {SocketFlag.SafeDisconn}
@@ -287,7 +295,8 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
         retFuture.fail(future.readError)
       else:
         let resultTup = (future.read.address,
-                         newAsyncSocket(future.read.client, socket.isBuffered))
+                         newAsyncSocket(future.read.client, socket.domain,
+                         socket.sockType, socket.protocol, socket.isBuffered))
         retFuture.complete(resultTup)
   return retFuture
 
@@ -423,17 +432,15 @@ 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)
-
   var realaddr = address
   if realaddr == "":
-    case sockDomain
+    case socket.domain
     of AF_INET6: realaddr = "::"
     of AF_INET:  realaddr = "0.0.0.0"
     else:
       raiseOSError("Unknown socket address family and no address specified to bindAddr")
 
-  var aiList = getAddrInfo(realaddr, port, sockDomain)
+  var aiList = getAddrInfo(realaddr, port, socket.domain)
   if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
     dealloc(aiList)
     raiseOSError(osLastError())
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 29e115da1..d9f4845f3 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -64,6 +64,9 @@ type
         sslPeekChar: char
       of false: nil
     lastError: OSErrorCode ## stores the last error on this socket
+    domain: Domain
+    sockType: SockType
+    protocol: Protocol
 
   Socket* = ref SocketImpl
 
@@ -124,33 +127,39 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
       result = result or MSG_PEEK
     of SocketFlag.SafeDisconn: continue
 
-proc newSocket*(fd: SocketHandle, buffered = true): Socket =
+proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET,
+    sockType: SockType = SOCK_STREAM,
+    protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
   ## Creates a new socket as specified by the params.
   assert fd != osInvalidSocket
   new(result)
   result.fd = fd
   result.isBuffered = buffered
+  result.domain = domain
+  result.sockType = sockType
+  result.protocol = protocol
   if buffered:
     result.currPos = 0
 
-proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket =
+proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
   ## Creates a new socket.
   ##
   ## If an error occurs EOS will be raised.
-  let fd = newRawSocket(domain, typ, protocol)
+  let fd = newRawSocket(domain, sockType, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
-  result = newSocket(fd, buffered)
+  result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol,
+                     buffered)
 
-proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
                 protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
   ## Creates a new socket.
   ##
   ## If an error occurs EOS will be raised.
-  let fd = newRawSocket(domain, typ, protocol)
+  let fd = newRawSocket(domain, sockType, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
-  result = newSocket(fd, buffered)
+  result = newSocket(fd, domain, sockType, protocol, buffered)
 
 when defined(ssl):
   CRYPTO_malloc_init()
@@ -371,7 +380,7 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
                   sizeof(name).SockLen) < 0'i32:
       raiseOSError(osLastError())
   else:
-    var aiList = getAddrInfo(address, port, AF_INET)
+    var aiList = getAddrInfo(address, port, socket.domain)
     if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
       dealloc(aiList)
       raiseOSError(osLastError())
@@ -532,15 +541,15 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {
   var valuei = cint(if value: 1 else: 0)
   setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
 
-proc connect*(socket: Socket, address: string, port = Port(0),
-              af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
+proc connect*(socket: Socket, address: string,
+    port = Port(0)) {.tags: [ReadIOEffect].} =
   ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
   ## host name. If ``address`` is a host name, this function will try each IP
   ## of that host name. ``htons`` is already performed on ``port`` so you must
   ## not do it.
   ##
   ## If ``socket`` is an SSL socket a handshake will be automatically performed.
-  var aiList = getAddrInfo(address, port, af)
+  var aiList = getAddrInfo(address, port, socket.domain)
   # try all possibilities:
   var success = false
   var lastError: OSErrorCode
@@ -992,15 +1001,15 @@ proc connectAsync(socket: Socket, name: string, port = Port(0),
   dealloc(aiList)
   if not success: raiseOSError(lastError)
 
-proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
-             af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
+proc connect*(socket: Socket, address: string, port = Port(0),
+    timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} =
   ## Connects to server as specified by ``address`` on port specified by ``port``.
   ##
   ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
   ## the connection to the server to be made.
   socket.fd.setBlocking(false)
 
-  socket.connectAsync(address, port, af)
+  socket.connectAsync(address, port, socket.domain)
   var s = @[socket.fd]
   if selectWrite(s, timeout) != 1:
     raise newException(TimeoutError, "Call to 'connect' timed out.")
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index d0e3b4cf1..349b0d97a 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -157,17 +157,17 @@ else:
     result = cint(ord(p))
 
 
-proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+proc newRawSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
              protocol: Protocol = IPPROTO_TCP): SocketHandle =
   ## Creates a new socket; returns `InvalidSocket` if an error occurs.
-  socket(toInt(domain), toInt(typ), toInt(protocol))
+  socket(toInt(domain), toInt(sockType), toInt(protocol))
 
-proc newRawSocket*(domain: cint, typ: cint, protocol: cint): SocketHandle =
+proc newRawSocket*(domain: cint, sockType: cint, protocol: cint): SocketHandle =
   ## Creates a new socket; returns `InvalidSocket` if an error occurs.
   ##
   ## Use this overload if one of the enums specified above does
   ## not contain what you need.
-  socket(domain, typ, protocol)
+  socket(domain, sockType, protocol)
 
 proc close*(socket: SocketHandle) =
   ## closes a socket.
@@ -190,16 +190,17 @@ proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEff
   else:
     result = posix.listen(socket, cint(backlog))
 
-proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM,
-                 prot: Protocol = IPPROTO_TCP): ptr AddrInfo =
+proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
+                  sockType: SockType = SOCK_STREAM,
+                  protocol: Protocol = IPPROTO_TCP): ptr AddrInfo =
   ##
   ##
   ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``!
   var hints: AddrInfo
   result = nil
-  hints.ai_family = toInt(af)
-  hints.ai_socktype = toInt(typ)
-  hints.ai_protocol = toInt(prot)
+  hints.ai_family = toInt(domain)
+  hints.ai_socktype = toInt(sockType)
+  hints.ai_protocol = toInt(protocol)
   hints.ai_flags = AI_V4MAPPED
   var gaiResult = getaddrinfo(address, $port, addr(hints), result)
   if gaiResult != 0'i32: