mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-06 11:54:11 +00:00
Implemented boolean socket options.
Added reuseAddr for httpserver and scgi.
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user