summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@googlemail.com>2013-10-30 16:40:03 +0000
committerDominik Picheta <dominikpicheta@googlemail.com>2013-10-30 16:40:03 +0000
commit78123520a90b08a8a9da592812de340e6a0045c4 (patch)
treed1fac38f593505793b9243804899f1cb453ad9e0 /lib
parent0663c883e5994fcfd4f49f8b76e04c5f9e0b1401 (diff)
downloadNim-78123520a90b08a8a9da592812de340e6a0045c4.tar.gz
Implemented boolean socket options.
Added reuseAddr for httpserver and scgi.
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/httpserver.nim9
-rw-r--r--lib/pure/scgi.nim10
-rw-r--r--lib/pure/sockets.nim32
-rw-r--r--lib/windows/winlean.nim13
4 files changed, 60 insertions, 4 deletions
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index e24709451..043e713a6 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -224,11 +224,13 @@ type
   TAsyncHTTPServer = object of TServer
     asyncSocket: PAsyncSocket
   
-proc open*(s: var TServer, port = TPort(80)) =
+proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
   ## creates a new server at port `port`. If ``port == 0`` a free port is
   ## acquired that can be accessed later by the ``port`` proc.
   s.socket = socket(AF_INET)
   if s.socket == InvalidSocket: OSError(OSLastError())
+  if reuseAddr:
+    s.socket.setSockOpt(OptReuseAddr, True)
   bindAddr(s.socket, port)
   listen(s.socket)
 
@@ -475,7 +477,8 @@ proc nextAsync(s: PAsyncHTTPServer) =
 
 proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket, 
                         path, query: string): bool {.closure.},
-                     port = TPort(80), address = ""): PAsyncHTTPServer =
+                     port = TPort(80), address = "",
+                     reuseAddr = false): PAsyncHTTPServer =
   ## Creates an Asynchronous HTTP server at ``port``.
   var capturedRet: PAsyncHTTPServer
   new(capturedRet)
@@ -486,6 +489,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
       let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
                                capturedRet.query)
       if quit: capturedRet.asyncSocket.close()
+  if reuseAddr:
+    capturedRet.asyncSocket.setSockOpt(OptReuseAddr, True)
   
   capturedRet.asyncSocket.bindAddr(port, address)
   capturedRet.asyncSocket.listen()
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index 8e45032c8..b18fe0094 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -95,7 +95,8 @@ proc recvBuffer(s: var TScgiState, L: int) =
     scgiError("could not read all data")
   setLen(s.input, L)
   
-proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") = 
+proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1",
+  reuseAddr = False) = 
   ## opens a connection.
   s.bufLen = 4000
   s.input = newString(s.buflen) # will be reused
@@ -104,6 +105,8 @@ proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
   new(s.client) # Initialise s.client for `next`
   if s.server == InvalidSocket: scgiError("could not open socket")
   #s.server.connect(connectionName, port)
+  if reuseAddr:
+    s.server.setSockOpt(OptReuseAddr, True)
   bindAddr(s.server, port, address)
   listen(s.server)
   
@@ -243,7 +246,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
 
 proc open*(handleRequest: proc (client: PAsyncSocket, 
                                 input: string, headers: PStringTable) {.closure.},
-           port = TPort(4000), address = "127.0.0.1"): PAsyncScgiState =
+           port = TPort(4000), address = "127.0.0.1",
+           reuseAddr = false): PAsyncScgiState =
   ## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
   ##
   ## After the execution of ``handleRequest`` the client socket will be closed
@@ -252,6 +256,8 @@ proc open*(handleRequest: proc (client: PAsyncSocket,
   new(cres)
   cres.asyncServer = AsyncSocket()
   cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
+  if reuseAddr:
+    cres.asyncServer.setSockOpt(OptReuseAddr, True)
   bindAddr(cres.asyncServer, port, address)
   listen(cres.asyncServer)
   cres.handleRequest = handleRequest
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 9c553f6dc..99117ea4e 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -119,6 +119,10 @@ type
     length*: int
     addrList*: seq[string]
 
+  TSOBool* = enum ## Boolean socket options.
+    OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
+    OptOOBInline, OptReuseAddr
+
   TRecvLineResult* = enum ## result for recvLineAsync
     RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
 
@@ -734,6 +738,34 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
                 sizeof(value).TSockLen) < 0'i32:
     OSError(OSLastError())
 
+proc toCInt(opt: TSOBool): cint =
+  case opt
+  of OptAcceptConn: SO_ACCEPTCONN
+  of OptBroadcast: SO_BROADCAST
+  of OptDebug: SO_DEBUG
+  of OptDontRoute: SO_DONTROUTE
+  of OptKeepAlive: SO_KEEPALIVE
+  of OptOOBInline: SO_OOBINLINE
+  of OptReuseAddr: SO_REUSEADDR
+
+proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
+  tags: [FReadIO].} =
+  ## Retrieves option ``opt`` as a boolean value.
+  var res: cint
+  var size = sizeof(res).TSockLen
+  if getsockopt(socket.fd, cint(level), toCInt(opt), 
+                addr(res), addr(size)) < 0'i32:
+    OSError(OSLastError())
+  result = res != 0
+
+proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
+  tags: [FWriteIO].} =
+  ## 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),  
+                sizeof(valuei).TSockLen) < 0'i32:
+    OSError(OSLastError())
+
 proc connect*(socket: TSocket, address: string, port = TPort(0), 
               af: TDomain = AF_INET) {.tags: [FReadIO].} =
   ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index c9d595d2c..56d279db6 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -415,6 +415,19 @@ type
 var
   SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
   INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
+  SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
+  SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording

+  SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()

+  SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse

+  SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive

+  SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses

+  SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs

+  SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible

+  SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present

+  SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line

+

+  SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint

+  SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
 
 proc `==`*(x, y: TSocketHandle): bool {.borrow.}