diff options
author | Dominik Picheta <dominikpicheta@googlemail.com> | 2013-10-30 16:40:03 +0000 |
---|---|---|
committer | Dominik Picheta <dominikpicheta@googlemail.com> | 2013-10-30 16:40:03 +0000 |
commit | 78123520a90b08a8a9da592812de340e6a0045c4 (patch) | |
tree | d1fac38f593505793b9243804899f1cb453ad9e0 /lib | |
parent | 0663c883e5994fcfd4f49f8b76e04c5f9e0b1401 (diff) | |
download | Nim-78123520a90b08a8a9da592812de340e6a0045c4.tar.gz |
Implemented boolean socket options.
Added reuseAddr for httpserver and scgi.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/httpserver.nim | 9 | ||||
-rw-r--r-- | lib/pure/scgi.nim | 10 | ||||
-rw-r--r-- | lib/pure/sockets.nim | 32 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 13 |
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.} |