Implemented boolean socket options.
Added reuseAddr for httpserver and scgi.
This commit is contained in:
parent
0663c883e5
commit
78123520a9
4 changed files with 60 additions and 4 deletions
|
|
@ -224,11 +224,13 @@ type
|
||||||
TAsyncHTTPServer = object of TServer
|
TAsyncHTTPServer = object of TServer
|
||||||
asyncSocket: PAsyncSocket
|
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
|
## creates a new server at port `port`. If ``port == 0`` a free port is
|
||||||
## acquired that can be accessed later by the ``port`` proc.
|
## acquired that can be accessed later by the ``port`` proc.
|
||||||
s.socket = socket(AF_INET)
|
s.socket = socket(AF_INET)
|
||||||
if s.socket == InvalidSocket: OSError(OSLastError())
|
if s.socket == InvalidSocket: OSError(OSLastError())
|
||||||
|
if reuseAddr:
|
||||||
|
s.socket.setSockOpt(OptReuseAddr, True)
|
||||||
bindAddr(s.socket, port)
|
bindAddr(s.socket, port)
|
||||||
listen(s.socket)
|
listen(s.socket)
|
||||||
|
|
||||||
|
|
@ -475,7 +477,8 @@ proc nextAsync(s: PAsyncHTTPServer) =
|
||||||
|
|
||||||
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
|
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
|
||||||
path, query: string): bool {.closure.},
|
path, query: string): bool {.closure.},
|
||||||
port = TPort(80), address = ""): PAsyncHTTPServer =
|
port = TPort(80), address = "",
|
||||||
|
reuseAddr = false): PAsyncHTTPServer =
|
||||||
## Creates an Asynchronous HTTP server at ``port``.
|
## Creates an Asynchronous HTTP server at ``port``.
|
||||||
var capturedRet: PAsyncHTTPServer
|
var capturedRet: PAsyncHTTPServer
|
||||||
new(capturedRet)
|
new(capturedRet)
|
||||||
|
|
@ -486,6 +489,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
|
||||||
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
|
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
|
||||||
capturedRet.query)
|
capturedRet.query)
|
||||||
if quit: capturedRet.asyncSocket.close()
|
if quit: capturedRet.asyncSocket.close()
|
||||||
|
if reuseAddr:
|
||||||
|
capturedRet.asyncSocket.setSockOpt(OptReuseAddr, True)
|
||||||
|
|
||||||
capturedRet.asyncSocket.bindAddr(port, address)
|
capturedRet.asyncSocket.bindAddr(port, address)
|
||||||
capturedRet.asyncSocket.listen()
|
capturedRet.asyncSocket.listen()
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,8 @@ proc recvBuffer(s: var TScgiState, L: int) =
|
||||||
scgiError("could not read all data")
|
scgiError("could not read all data")
|
||||||
setLen(s.input, L)
|
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.
|
## opens a connection.
|
||||||
s.bufLen = 4000
|
s.bufLen = 4000
|
||||||
s.input = newString(s.buflen) # will be reused
|
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`
|
new(s.client) # Initialise s.client for `next`
|
||||||
if s.server == InvalidSocket: scgiError("could not open socket")
|
if s.server == InvalidSocket: scgiError("could not open socket")
|
||||||
#s.server.connect(connectionName, port)
|
#s.server.connect(connectionName, port)
|
||||||
|
if reuseAddr:
|
||||||
|
s.server.setSockOpt(OptReuseAddr, True)
|
||||||
bindAddr(s.server, port, address)
|
bindAddr(s.server, port, address)
|
||||||
listen(s.server)
|
listen(s.server)
|
||||||
|
|
||||||
|
|
@ -243,7 +246,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
|
||||||
|
|
||||||
proc open*(handleRequest: proc (client: PAsyncSocket,
|
proc open*(handleRequest: proc (client: PAsyncSocket,
|
||||||
input: string, headers: PStringTable) {.closure.},
|
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.
|
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
|
||||||
##
|
##
|
||||||
## After the execution of ``handleRequest`` the client socket will be closed
|
## After the execution of ``handleRequest`` the client socket will be closed
|
||||||
|
|
@ -252,6 +256,8 @@ proc open*(handleRequest: proc (client: PAsyncSocket,
|
||||||
new(cres)
|
new(cres)
|
||||||
cres.asyncServer = AsyncSocket()
|
cres.asyncServer = AsyncSocket()
|
||||||
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
|
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
|
||||||
|
if reuseAddr:
|
||||||
|
cres.asyncServer.setSockOpt(OptReuseAddr, True)
|
||||||
bindAddr(cres.asyncServer, port, address)
|
bindAddr(cres.asyncServer, port, address)
|
||||||
listen(cres.asyncServer)
|
listen(cres.asyncServer)
|
||||||
cres.handleRequest = handleRequest
|
cres.handleRequest = handleRequest
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,10 @@ type
|
||||||
length*: int
|
length*: int
|
||||||
addrList*: seq[string]
|
addrList*: seq[string]
|
||||||
|
|
||||||
|
TSOBool* = enum ## Boolean socket options.
|
||||||
|
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
|
||||||
|
OptOOBInline, OptReuseAddr
|
||||||
|
|
||||||
TRecvLineResult* = enum ## result for recvLineAsync
|
TRecvLineResult* = enum ## result for recvLineAsync
|
||||||
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
||||||
|
|
||||||
|
|
@ -734,6 +738,34 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
sizeof(value).TSockLen) < 0'i32:
|
sizeof(value).TSockLen) < 0'i32:
|
||||||
OSError(OSLastError())
|
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),
|
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||||
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
||||||
|
|
|
||||||
|
|
@ -415,6 +415,19 @@ type
|
||||||
var
|
var
|
||||||
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
||||||
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
|
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.}
|
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue