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')
-rwxr-xr-xlib/pure/sockets.nim61
1 files changed, 40 insertions, 21 deletions
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index c00dcc80b..ae590c99f 100755
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -142,9 +142,11 @@ proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
   else:
     result = TSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol)))
 
-proc listen*(socket: TSocket, attempts = 5) =
-  ## listens to socket.
-  if listen(cint(socket), cint(attempts)) < 0'i32: OSError()
+proc listen*(socket: TSocket, backlog = SOMAXCONN) =
+  ## Marks ``socket`` as accepting connections. 
+  ## ``Backlog`` specifies the maximum length of the 
+  ## queue of pending connections.
+  if listen(cint(socket), cint(backlog)) < 0'i32: OSError()
 
 proc invalidIp4(s: string) {.noreturn, noinline.} =
   raise newException(EInvalidValue, "invalid ip4 address: " & s)
@@ -239,22 +241,35 @@ proc getSockName*(socket: TSocket): TPort =
     OSError()
   result = TPort(sockets.ntohs(name.sin_port))
 
-proc accept*(server: TSocket): TSocket =
-  ## waits for a client and returns its socket. ``InvalidSocket`` is returned
-  ## if an error occurs, or if ``server`` is non-blocking and there are no 
-  ## clients connecting.
-  var client: Tsockaddr_in
-  var clientLen: cint = sizeof(client)
-  result = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(client)),
-                          addr(clientLen)))
-
 proc acceptAddr*(server: TSocket): tuple[sock: TSocket, address: string] =
-  ## waits for a client and returns its socket and IP address
+  ## Blocks until a connection is being made from a client. When a connection
+  ## is made returns the client socket and address of the connecting client.
+  ## If ``server`` is non-blocking then this function returns immediately, and
+  ## if there are no connections queued the returned socket will be
+  ## ``InvalidSocket``.
+  ## This function will raise EOS if an error occurs.
   var address: Tsockaddr_in
   var addrLen: cint = sizeof(address)
-  var sock = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(address)),
-                          addr(addrLen)))
-  return (sock, $inet_ntoa(address.sin_addr))
+  var sock = accept(cint(server), cast[ptr TSockAddr](addr(address)),
+                    addr(addrLen))
+  if sock < 0:
+    # TODO: Test on Windows.
+    when defined(windows):
+      var err = WSAGetLastError()
+      if err == WSAEINPROGRESS:
+        return (InvalidSocket, "")
+      else: OSError()
+    else:
+      if errno == EAGAIN or errno == EWOULDBLOCK:
+        return (InvalidSocket, "")
+      else: OSError()
+  else: return (TSocket(sock), $inet_ntoa(address.sin_addr))
+
+proc accept*(server: TSocket): TSocket =
+  ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
+  ## socket.
+  var (client, a) = acceptAddr(server)
+  return client
 
 proc close*(socket: TSocket) =
   ## closes a socket.
@@ -537,11 +552,14 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
   ## returns false if no further data is available. `Line` must be initialized
   ## and not nil! This does not throw an EOS exception, therefore
   ## it can be used in both blocking and non-blocking sockets.
+  ## If ``socket`` is disconnected, ``true`` will be returned and line will be
+  ## set to ``""``.
   setLen(line.string, 0)
   while true:
     var c: char
     var n = recv(cint(socket), addr(c), 1, 0'i32)
-    if n <= 0: return
+    if n < 0: return
+    elif n == 0: return true
     if c == '\r':
       n = recv(cint(socket), addr(c), 1, MSG_PEEK)
       if n > 0 and c == '\L':
@@ -634,19 +652,20 @@ proc send*(socket: TSocket, data: string) =
   ## sends data to a socket.
   if send(socket, cstring(data), data.len) != data.len: OSError()
 
-proc sendAsync*(socket: TSocket, data: string) =
-  ## sends data to a non-blocking socket.
+proc sendAsync*(socket: TSocket, data: string): bool =
+  ## sends data to a non-blocking socket. Returns whether ``data`` was sent.
+  result = true
   var bytesSent = send(socket, cstring(data), data.len)
   if bytesSent == -1:
     when defined(windows):
       var err = WSAGetLastError()
       # TODO: Test on windows.
       if err == WSAEINPROGRESS:
-        return
+        return false
       else: OSError()
     else:
       if errno == EAGAIN or errno == EWOULDBLOCK:
-        return
+        return false
       else: OSError()
 
 when defined(Windows):