summary refs log tree commit diff stats
path: root/lib/pure/sockets.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/sockets.nim')
-rw-r--r--lib/pure/sockets.nim240
1 files changed, 120 insertions, 120 deletions
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 18b2ab1e9..29f0bf87d 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -51,17 +51,17 @@ else:
 
 # Note: The enumerations are mapped to Window's constants.
 
-when defined(ssl):  
+when defined(ssl):
 
   type
     SSLError* = object of Exception
 
     SSLCVerifyMode* = enum
       CVerifyNone, CVerifyPeer
-    
+
     SSLProtVersion* = enum
       protSSLv2, protSSLv3, protTLSv1, protSSLv23
-    
+
     SSLContext* = distinct SSLCTX
 
     SSLAcceptResult* = enum
@@ -93,11 +93,11 @@ type
         sslPeekChar: char
       of false: nil
     nonblocking: bool
-  
+
   Socket* = ref SocketImpl
-  
+
   Port* = distinct uint16  ## port type
-  
+
   Domain* = enum    ## domain, which specifies the protocol family of the
                     ## created socket. Other domains than those that are listed
                     ## here are unsupported.
@@ -112,7 +112,7 @@ type
     SOCK_SEQPACKET = 5 ## reliable sequenced packet service
 
   Protocol* = enum      ## third argument to `socket` proc
-    IPPROTO_TCP = 6,    ## Transmission control protocol. 
+    IPPROTO_TCP = 6,    ## Transmission control protocol.
     IPPROTO_UDP = 17,   ## User datagram protocol.
     IPPROTO_IP,         ## Internet protocol. Unsupported on Windows.
     IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
@@ -178,7 +178,7 @@ proc `==`*(a, b: Port): bool {.borrow.}
 proc `$`*(p: Port): string {.borrow.}
   ## returns the port number as a string
 
-proc ntohl*(x: int32): int32 = 
+proc ntohl*(x: int32): int32 =
   ## Converts 32-bit integers from network to host byte order.
   ## On machines where the host byte order is the same as network byte order,
   ## this is a no-op; otherwise, it performs a 4-byte swap operation.
@@ -206,7 +206,7 @@ proc htons*(x: int16): int16 =
   ## On machines where the host byte order is the same as network byte
   ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
   result = sockets.ntohs(x)
-  
+
 when defined(Posix):
   proc toInt(domain: Domain): cint =
     case domain
@@ -234,19 +234,19 @@ when defined(Posix):
     else: discard
 
 else:
-  proc toInt(domain: Domain): cint = 
+  proc toInt(domain: Domain): cint =
     result = toU16(ord(domain))
 
   proc toInt(typ: SockType): cint =
     result = cint(ord(typ))
-  
+
   proc toInt(p: Protocol): cint =
     result = cint(ord(p))
 
 proc socket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
              protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
   ## Creates a new socket; returns `InvalidSocket` if an error occurs.
-  
+
   # TODO: Perhaps this should just raise EOS when an error occurs.
   when defined(Windows):
     result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
@@ -277,27 +277,27 @@ when defined(ssl):
       raise newException(system.IOError, "Certificate file could not be found: " & certFile)
     if keyFile != "" and not existsFile(keyFile):
       raise newException(system.IOError, "Key file could not be found: " & keyFile)
-    
+
     if certFile != "":
       var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
       if ret != 1:
         raiseSslError()
-    
+
     # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
     if keyFile != "":
       if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
                                      SSL_FILETYPE_PEM) != 1:
         raiseSslError()
-        
+
       if SSL_CTX_check_private_key(ctx) != 1:
         raiseSslError("Verification of private key file failed.")
 
   proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
                    certFile = "", keyFile = ""): SSLContext =
     ## Creates an SSL context.
-    ## 
-    ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are 
-    ## are available with the addition of ``ProtSSLv23`` which allows for 
+    ##
+    ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are
+    ## are available with the addition of ``ProtSSLv23`` which allows for
     ## compatibility with all of them.
     ##
     ## There are currently only two options for verify mode;
@@ -322,7 +322,7 @@ when defined(ssl):
       newCTX = SSL_CTX_new(SSLv3_method())
     of protTLSv1:
       newCTX = SSL_CTX_new(TLSv1_method())
-    
+
     if newCTX.SSLCTXSetCipherList("ALL") != 1:
       raiseSslError()
     case verifyMode
@@ -343,7 +343,7 @@ when defined(ssl):
     ##
     ## **Disclaimer**: This code is not well tested, may be very unsafe and
     ## prone to security vulnerabilities.
-    
+
     socket.isSSL = true
     socket.sslContext = ctx
     socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
@@ -351,7 +351,7 @@ when defined(ssl):
     socket.sslHasPeekChar = false
     if socket.sslHandle == nil:
       raiseSslError()
-    
+
     if SSLSetFd(socket.sslHandle, socket.fd) != 1:
       raiseSslError()
 
@@ -382,7 +382,7 @@ proc raiseSocketError*(socket: Socket, err: int = -1, async = false) =
         of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
           raiseSslError()
         else: raiseSslError("Unknown Error")
-  
+
   if err == -1 and not (when defined(ssl): socket.isSSL else: false):
     let lastError = osLastError()
     if async:
@@ -397,15 +397,15 @@ proc raiseSocketError*(socket: Socket, err: int = -1, async = false) =
     else: raiseOSError(lastError)
 
 proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
-  ## Marks ``socket`` as accepting connections. 
-  ## ``Backlog`` specifies the maximum length of the 
+  ## Marks ``socket`` as accepting connections.
+  ## ``Backlog`` specifies the maximum length of the
   ## queue of pending connections.
   if listen(socket.fd, cint(backlog)) < 0'i32: raiseOSError(osLastError())
 
 proc invalidIp4(s: string) {.noreturn, noinline.} =
   raise newException(ValueError, "invalid ip4 address: " & s)
 
-proc parseIp4*(s: string): BiggestInt = 
+proc parseIp4*(s: string): BiggestInt =
   ## parses an IP version 4 in dotted decimal form like "a.b.c.d".
   ##
   ## This is equivalent to `inet_ntoa`:idx:.
@@ -469,8 +469,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
     gaiNim(address, port, hints, aiList)
     if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
       raiseOSError(osLastError())
-  
-proc getSockName*(socket: Socket): Port = 
+
+proc getSockName*(socket: Socket): Port =
   ## returns the socket's associated port number.
   var name: Sockaddr_in
   when defined(Windows):
@@ -485,14 +485,14 @@ proc getSockName*(socket: Socket): Port =
     raiseOSError(osLastError())
   result = Port(sockets.ntohs(name.sin_port))
 
-template acceptAddrPlain(noClientRet, successRet: expr, 
+template acceptAddrPlain(noClientRet, successRet: expr,
                          sslImplementation: stmt): stmt {.immediate.} =
   assert(client != nil)
   var sockAddress: Sockaddr_in
   var addrLen = sizeof(sockAddress).SockLen
   var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
                     addr(addrLen))
-  
+
   if sock == osInvalidSocket:
     let err = osLastError()
     when defined(windows):
@@ -537,7 +537,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string) {.
   ## The resulting client will inherit any properties of the server socket. For
   ## example: whether the socket is buffered or not.
   ##
-  ## **Note**: ``client`` must be initialised (with ``new``), this function 
+  ## **Note**: ``client`` must be initialised (with ``new``), this function
   ## makes no effort to initialise the ``client`` variable.
   ##
   ## **Warning:** When using SSL with non-blocking sockets, it is best to use
@@ -546,7 +546,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string) {.
     when defined(ssl):
       if server.isSSL:
         # We must wrap the client sock in a ssl context.
-        
+
         server.sslContext.wrapSocket(client)
         let ret = SSLAccept(client.sslHandle)
         while ret <= 0:
@@ -572,9 +572,9 @@ when defined(ssl):
   proc acceptAddrSSL*(server: Socket, client: var Socket,
                       address: var string): SSLAcceptResult {.
                       tags: [ReadIOEffect].} =
-    ## This procedure should only be used for non-blocking **SSL** sockets. 
+    ## This procedure should only be used for non-blocking **SSL** sockets.
     ## It will immediately return with one of the following values:
-    ## 
+    ##
     ## ``AcceptSuccess`` will be returned when a client has been successfully
     ## accepted and the handshake has been successfully performed between
     ## ``server`` and the newly connected client.
@@ -591,7 +591,7 @@ when defined(ssl):
         if server.isSSL:
           client.setBlocking(false)
           # We must wrap the client sock in a ssl context.
-          
+
           if not client.isSSL or client.sslHandle == nil:
             server.sslContext.wrapSocket(client)
           let ret = SSLAccept(client.sslHandle)
@@ -623,10 +623,10 @@ when defined(ssl):
 proc accept*(server: Socket, client: var Socket) {.tags: [ReadIOEffect].} =
   ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
   ## socket.
-  ## 
+  ##
   ## **Note**: ``client`` must be initialised (with ``new``), this function
   ## makes no effort to initialise the ``client`` variable.
-  
+
   var addrDummy = ""
   acceptAddr(server, client, addrDummy)
 
@@ -662,7 +662,7 @@ proc close*(socket: Socket) =
       socket.sslHandle = nil
 
 proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
-  ## Searches the database from the beginning and finds the first entry for 
+  ## Searches the database from the beginning and finds the first entry for
   ## which the service name specified by ``name`` matches the s_name member
   ## and the protocol name specified by ``proto`` matches the s_proto member.
   ##
@@ -676,10 +676,10 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = Port(s.s_port)
   result.proto = $s.s_proto
-  
-proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = 
-  ## Searches the database from the beginning and finds the first entry for 
-  ## which the port specified by ``port`` matches the s_port member and the 
+
+proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} =
+  ## Searches the database from the beginning and finds the first entry for
+  ## which the port specified by ``port`` matches the s_port member and the
   ## protocol name specified by ``proto`` matches the s_proto member.
   ##
   ## On posix this will search through the ``/etc/services`` file.
@@ -697,20 +697,20 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
   ## This function will lookup the hostname of an IP Address.
   var myaddr: InAddr
   myaddr.s_addr = inet_addr(ip)
-  
+
   when defined(windows):
     var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
                                   cint(sockets.AF_INET))
     if s == nil: raiseOSError(osLastError())
   else:
-    var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, 
+    var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen,
                                 cint(posix.AF_INET))
     if s == nil:
       raiseOSError(osLastError(), $hstrerror(h_errno))
-  
+
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
-  when defined(windows): 
+  when defined(windows):
     result.addrtype = Domain(s.h_addrtype)
   else:
     if s.h_addrtype == posix.AF_INET:
@@ -722,7 +722,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
-proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = 
+proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
   ## This function will lookup the IP address of a hostname.
   when defined(Windows):
     var s = winlean.gethostbyname(name)
@@ -731,7 +731,7 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
   if s == nil: raiseOSError(osLastError())
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
-  when defined(windows): 
+  when defined(windows):
     result.addrtype = Domain(s.h_addrtype)
   else:
     if s.h_addrtype == posix.AF_INET:
@@ -744,11 +744,11 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
   result.length = int(s.h_length)
 
 proc getSockOptInt*(socket: Socket, level, optname: int): int {.
-  tags: [ReadIOEffect].} = 
+  tags: [ReadIOEffect].} =
   ## getsockopt for integer options.
   var res: cint
   var size = sizeof(res).SockLen
-  if getsockopt(socket.fd, cint(level), cint(optname), 
+  if getsockopt(socket.fd, cint(level), cint(optname),
                 addr(res), addr(size)) < 0'i32:
     raiseOSError(osLastError())
   result = int(res)
@@ -757,7 +757,7 @@ proc setSockOptInt*(socket: Socket, level, optname, optval: int) {.
   tags: [WriteIOEffect].} =
   ## setsockopt for integer options.
   var value = cint(optval)
-  if setsockopt(socket.fd, cint(level), cint(optname), addr(value),  
+  if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
                 sizeof(value).SockLen) < 0'i32:
     raiseOSError(osLastError())
 
@@ -776,7 +776,7 @@ proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
   ## Retrieves option ``opt`` as a boolean value.
   var res: cint
   var size = sizeof(res).SockLen
-  if getsockopt(socket.fd, cint(level), toCInt(opt), 
+  if getsockopt(socket.fd, cint(level), toCInt(opt),
                 addr(res), addr(size)) < 0'i32:
     raiseOSError(osLastError())
   result = res != 0
@@ -785,11 +785,11 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {
   tags: [WriteIOEffect].} =
   ## Sets option ``opt`` to a boolean value specified by ``value``.
   var valuei = cint(if value: 1 else: 0)
-  if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),  
+  if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
                 sizeof(valuei).SockLen) < 0'i32:
     raiseOSError(osLastError())
 
-proc connect*(socket: Socket, address: string, port = Port(0), 
+proc connect*(socket: Socket, address: string, port = Port(0),
               af: Domain = AF_INET) {.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
@@ -816,7 +816,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
 
   freeaddrinfo(aiList)
   if not success: raiseOSError(lastError)
-  
+
   when defined(ssl):
     if socket.isSSL:
       let ret = SSLConnect(socket.sslHandle)
@@ -825,7 +825,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
         case err
         of SSL_ERROR_ZERO_RETURN:
           raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
-        of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, 
+        of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT,
            SSL_ERROR_WANT_ACCEPT:
           raiseSslError("The operation did not complete. Perhaps you should use connectAsync?")
         of SSL_ERROR_WANT_X509_LOOKUP:
@@ -834,7 +834,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
           raiseSslError()
         else:
           raiseSslError("Unknown error")
-        
+
   when false:
     var s: TSockAddrIn
     s.sin_addr.s_addr = inet_addr(address)
@@ -842,7 +842,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
     when defined(windows):
       s.sin_family = toU16(ord(af))
     else:
-      case af 
+      case af
       of AF_UNIX: s.sin_family = posix.AF_UNIX
       of AF_INET: s.sin_family = posix.AF_INET
       of AF_INET6: s.sin_family = posix.AF_INET6
@@ -886,7 +886,7 @@ proc connectAsync*(socket: Socket, name: string, port = Port(0),
         if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
           success = true
           break
-        
+
     it = it.ai_next
 
   freeaddrinfo(aiList)
@@ -942,12 +942,12 @@ proc timeValFromMilliseconds(timeout = 500): Timeval =
     result.tv_sec = seconds.int32
     result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
 
-proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) = 
+proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) =
   FD_ZERO(fd)
-  for i in items(s): 
+  for i in items(s):
     m = max(m, int(i.fd))
     FD_SET(i.fd, fd)
-   
+
 proc pruneSocketSet(s: var seq[Socket], fd: var TFdSet) =
   var i = 0
   var L = s.len
@@ -982,13 +982,13 @@ proc checkBuffer(readfds: var seq[Socket]): int =
   if result > 0:
     readfds = res
 
-proc select*(readfds, writefds, exceptfds: var seq[Socket], 
-             timeout = 500): int {.tags: [ReadIOEffect].} = 
+proc select*(readfds, writefds, exceptfds: var seq[Socket],
+             timeout = 500): int {.tags: [ReadIOEffect].} =
   ## Traditional select function. This function will return the number of
   ## sockets that are ready to be read from, written to, or which have errors.
-  ## If there are none; 0 is returned. 
+  ## If there are none; 0 is returned.
   ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
-  ## 
+  ##
   ## Sockets which are **not** ready for reading, writing or which don't have
   ## errors waiting on them are removed from the ``readfds``, ``writefds``,
   ## ``exceptfds`` sequences respectively.
@@ -997,44 +997,44 @@ proc select*(readfds, writefds, exceptfds: var seq[Socket],
     return buffersFilled
 
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
+
   var rd, wr, ex: TFdSet
   var m = 0
   createFdSet((rd), readfds, m)
   createFdSet((wr), writefds, m)
   createFdSet((ex), exceptfds, m)
-  
+
   if timeout != -1:
     result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
   else:
     result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), nil))
-  
+
   pruneSocketSet(readfds, (rd))
   pruneSocketSet(writefds, (wr))
   pruneSocketSet(exceptfds, (ex))
 
-proc select*(readfds, writefds: var seq[Socket], 
+proc select*(readfds, writefds: var seq[Socket],
              timeout = 500): int {.tags: [ReadIOEffect].} =
   ## Variant of select with only a read and write list.
   let buffersFilled = checkBuffer(readfds)
   if buffersFilled > 0:
     return buffersFilled
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
+
   var rd, wr: TFdSet
   var m = 0
   createFdSet((rd), readfds, m)
   createFdSet((wr), writefds, m)
-  
+
   if timeout != -1:
     result = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
   else:
     result = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
-  
+
   pruneSocketSet(readfds, (rd))
   pruneSocketSet(writefds, (wr))
 
-proc selectWrite*(writefds: var seq[Socket], 
+proc selectWrite*(writefds: var seq[Socket],
                   timeout = 500): int {.tags: [ReadIOEffect].} =
   ## When a socket in ``writefds`` is ready to be written to then a non-zero
   ## value will be returned specifying the count of the sockets which can be
@@ -1044,16 +1044,16 @@ proc selectWrite*(writefds: var seq[Socket],
   ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
   ## an unlimited time.
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
+
   var wr: TFdSet
   var m = 0
   createFdSet((wr), writefds, m)
-  
+
   if timeout != -1:
     result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
   else:
     result = int(select(cint(m+1), nil, addr(wr), nil, nil))
-  
+
   pruneSocketSet(writefds, (wr))
 
 proc select*(readfds: var seq[Socket], timeout = 500): int =
@@ -1062,16 +1062,16 @@ proc select*(readfds: var seq[Socket], timeout = 500): int =
   if buffersFilled > 0:
     return buffersFilled
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
+
   var rd: TFdSet
   var m = 0
   createFdSet((rd), readfds, m)
-  
+
   if timeout != -1:
     result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
   else:
     result = int(select(cint(m+1), addr(rd), nil, nil, nil))
-  
+
   pruneSocketSet(readfds, (rd))
 
 proc readIntoBuf(socket: Socket, flags: int32): int =
@@ -1107,12 +1107,12 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
   if socket.isBuffered:
     if socket.bufLen == 0:
       retRead(0'i32, 0)
-    
+
     var read = 0
     while read < size:
       if socket.currPos >= socket.bufLen:
         retRead(0'i32, read)
-    
+
       let chunk = min(socket.bufLen-socket.currPos, size-read)
       var d = cast[cstring](data)
       copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
@@ -1155,7 +1155,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
   else:
     if timeout - int(waited * 1000.0) < 1:
       raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
-    
+
     when defined(ssl):
       if socket.isSSL:
         if socket.hasDataBuffered:
@@ -1164,7 +1164,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
         let sslPending = SSLPending(socket.sslHandle)
         if sslPending != 0:
           return sslPending
-    
+
     var s = @[socket]
     var startTime = epochTime()
     let selRet = select(s, timeout - int(waited * 1000.0))
@@ -1176,8 +1176,8 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
 proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
   tags: [ReadIOEffect, TimeEffect].} =
   ## overload with a ``timeout`` parameter in milliseconds.
-  var waited = 0.0 # number of seconds already waited  
-  
+  var waited = 0.0 # number of seconds already waited
+
   var read = 0
   while read < size:
     let avail = waitFor(socket, waited, timeout, size-read, "recv")
@@ -1187,7 +1187,7 @@ proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
     if result < 0:
       return result
     inc(read, result)
-  
+
   result = read
 
 proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int =
@@ -1231,7 +1231,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
       var res = socket.readIntoBuf(0'i32)
       if res <= 0:
         result = res
-    
+
     c = socket.buffer[socket.currPos]
   else:
     when defined(ssl):
@@ -1239,7 +1239,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
         if not socket.sslHasPeekChar:
           result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
           socket.sslHasPeekChar = true
-        
+
         c = socket.sslPeekChar
         return
     result = recv(socket.fd, addr(c), 1, MSG_PEEK)
@@ -1251,11 +1251,11 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
   ## If a full line is received ``\r\L`` is not
   ## added to ``line``, however if solely ``\r\L`` is received then ``line``
   ## will be set to it.
-  ## 
+  ##
   ## ``True`` is returned if data is available. ``False`` suggests an
   ## error, EOS exceptions are not raised and ``False`` is simply returned
   ## instead.
-  ## 
+  ##
   ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
   ## will be returned.
   ##
@@ -1264,7 +1264,7 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
   ##
   ## **Deprecated since version 0.9.2**: This function has been deprecated in
   ## favour of readLine.
-  
+
   template addNLIfEmpty(): stmt =
     if line.len == 0:
       line.add("\c\L")
@@ -1286,7 +1286,7 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
       elif n <= 0: return false
       addNLIfEmpty()
       return true
-    elif c == '\L': 
+    elif c == '\L':
       addNLIfEmpty()
       return true
     add(line.string, c)
@@ -1298,14 +1298,14 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
   ## If a full line is read ``\r\L`` is not
   ## added to ``line``, however if solely ``\r\L`` is read then ``line``
   ## will be set to it.
-  ## 
+  ##
   ## If the socket is disconnected, ``line`` will be set to ``""``.
   ##
   ## An EOS exception will be raised in the case of a socket error.
   ##
   ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
-  
+
   template addNLIfEmpty(): stmt =
     if line.len == 0:
       line.add("\c\L")
@@ -1327,12 +1327,12 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
       elif n <= 0: socket.raiseSocketError()
       addNLIfEmpty()
       return
-    elif c == '\L': 
+    elif c == '\L':
       addNLIfEmpty()
       return
     add(line.string, c)
 
-proc recvLineAsync*(socket: Socket, 
+proc recvLineAsync*(socket: Socket,
   line: var TaintedString): RecvLineResult {.tags: [ReadIOEffect], deprecated.} =
   ## Similar to ``recvLine`` but designed for non-blocking sockets.
   ##
@@ -1350,21 +1350,21 @@ proc recvLineAsync*(socket: Socket,
   while true:
     var c: char
     var n = recv(socket, addr(c), 1)
-    if n < 0: 
+    if n < 0:
       return (if line.len == 0: RecvFail else: RecvPartialLine)
-    elif n == 0: 
+    elif n == 0:
       return (if line.len == 0: RecvDisconnected else: RecvPartialLine)
     if c == '\r':
       n = peekChar(socket, c)
       if n > 0 and c == '\L':
         discard recv(socket, addr(c), 1)
-      elif n <= 0: 
+      elif n <= 0:
         return (if line.len == 0: RecvFail else: RecvPartialLine)
       return RecvFullLine
     elif c == '\L': return RecvFullLine
     add(line.string, c)
 
-proc readLineAsync*(socket: Socket, 
+proc readLineAsync*(socket: Socket,
   line: var TaintedString): ReadLineResult {.tags: [ReadIOEffect].} =
   ## Similar to ``recvLine`` but designed for non-blocking sockets.
   ##
@@ -1376,24 +1376,24 @@ proc readLineAsync*(socket: Socket,
   ##   * If no data could be retrieved; ``ReadNone`` is returned.
   ##   * If call to ``recv`` failed; **an EOS exception is raised.**
   setLen(line.string, 0)
-  
+
   template errorOrNone =
     socket.raiseSocketError(async = true)
     return ReadNone
-  
+
   while true:
     var c: char
     var n = recv(socket, addr(c), 1)
     #echo(n)
     if n < 0:
       if line.len == 0: errorOrNone else: return ReadPartialLine
-    elif n == 0: 
+    elif n == 0:
       return (if line.len == 0: ReadDisconnected else: ReadPartialLine)
     if c == '\r':
       n = peekChar(socket, c)
       if n > 0 and c == '\L':
         discard recv(socket, addr(c), 1)
-      elif n <= 0: 
+      elif n <= 0:
         if line.len == 0: errorOrNone else: return ReadPartialLine
       return ReadFullLine
     elif c == '\L': return ReadFullLine
@@ -1424,7 +1424,7 @@ proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} =
       var bytesRead = recv(socket, cstring(buf), bufSize-1)
       # Error
       if bytesRead == -1: OSError(osLastError())
-      
+
       buf[bytesRead] = '\0' # might not be necessary
       setLen(buf, bytesRead)
       add(result.string, buf)
@@ -1442,13 +1442,13 @@ proc recvTimeout*(socket: Socket, timeout: int): TaintedString {.
     var s = @[socket]
     if s.select(timeout) != 1:
       raise newException(TimeoutError, "Call to recv() timed out.")
-  
+
   return socket.recv
 {.pop.}
 
 proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
   tags: [ReadIOEffect], deprecated.} =
-  ## receives all the data from a non-blocking socket. If socket is non-blocking 
+  ## receives all the data from a non-blocking socket. If socket is non-blocking
   ## and there are no messages available, `False` will be returned.
   ## Other socket errors will result in an ``EOS`` error.
   ## If socket is not a connectionless socket and socket is not connected
@@ -1478,7 +1478,7 @@ proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
           of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
             raiseSslError()
           else: raiseSslError("Unknown Error")
-          
+
     if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
       let err = osLastError()
       when defined(windows):
@@ -1510,7 +1510,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
   ## so when ``socket`` is buffered the non-buffered implementation will be
   ## used. Therefore if ``socket`` contains something in its buffer this
   ## function will make no effort to return it.
-  
+
   # TODO: Buffered sockets
   data.setLen(length)
   var sockAddress: Sockaddr_in
@@ -1524,7 +1524,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
     port = ntohs(sockAddress.sin_port).Port
 
 proc recvFromAsync*(socket: Socket, data: var string, length: int,
-                    address: var string, port: var Port, 
+                    address: var string, port: var Port,
                     flags = 0'i32): bool {.tags: [ReadIOEffect].} =
   ## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``,
   ## this function will raise an EOS error whenever a socket error occurs.
@@ -1573,11 +1573,11 @@ proc send*(socket: Socket, data: pointer, size: int): int {.
   when defined(ssl):
     if socket.isSSL:
       return SSLWrite(socket.sslHandle, cast[cstring](data), size)
-  
+
   when defined(windows) or defined(macosx):
     result = send(socket.fd, data, size.cint, 0'i32)
   else:
-    when defined(solaris): 
+    when defined(solaris):
       const MSG_NOSIGNAL = 0
     result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
 
@@ -1590,7 +1590,7 @@ proc send*(socket: Socket, data: string) {.tags: [WriteIOEffect].} =
     when defined(ssl):
       if socket.isSSL:
         raiseSslError()
-    
+
     raiseOSError(osLastError())
 
   if sent != data.len:
@@ -1633,7 +1633,7 @@ proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
       if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
         return 0
       else: raiseOSError(err)
-  
+
 
 proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
   ## safe alternative to ``send``. Does not raise an EOS when an error occurs,
@@ -1644,7 +1644,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
              size: int, af: Domain = AF_INET, flags = 0'i32): int {.
              tags: [WriteIOEffect].} =
   ## low-level sendTo proc. This proc sends ``data`` to the specified ``address``,
-  ## which may be an IP address or a hostname, if a hostname is specified 
+  ## which may be an IP address or a hostname, if a hostname is specified
   ## this function will try each IP of that hostname.
   ##
   ## **Note:** This proc is not available for SSL sockets.
@@ -1654,7 +1654,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
   hints.ai_socktype = toInt(SOCK_STREAM)
   hints.ai_protocol = toInt(IPPROTO_TCP)
   gaiNim(address, port, hints, aiList)
-  
+
   # try all possibilities:
   var success = false
   var it = aiList
@@ -1668,7 +1668,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
 
   freeaddrinfo(aiList)
 
-proc sendTo*(socket: Socket, address: string, port: Port, 
+proc sendTo*(socket: Socket, address: string, port: Port,
              data: string): int {.tags: [WriteIOEffect].} =
   ## Friendlier version of the low-level ``sendTo``.
   result = socket.sendTo(address, port, cstring(data), data.len)
@@ -1677,10 +1677,10 @@ when defined(Windows):
   const
     IOCPARM_MASK = 127
     IOC_IN = int(-2147483648)
-    FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or 
+    FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
                              (102 shl 8) or 126
 
-  proc ioctlsocket(s: SocketHandle, cmd: clong, 
+  proc ioctlsocket(s: SocketHandle, cmd: clong,
                    argptr: ptr clong): cint {.
                    stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
 
@@ -1713,7 +1713,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
   ## the connection to the server to be made.
   let originalStatus = not socket.nonblocking
   socket.setBlocking(false)
-  
+
   socket.connectAsync(address, port, af)
   var s: seq[Socket] = @[socket]
   if selectWrite(s, timeout) != 1: