diff --git a/httpbeast.nimble b/httpbeast.nimble index ea2be4e..50246aa 100644 --- a/httpbeast.nimble +++ b/httpbeast.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.0" +version = "0.4.1" author = "Dominik Picheta" description = "A super-fast epoll-backed and parallel HTTP server." license = "MIT" diff --git a/src/httpbeast.nim b/src/httpbeast.nim index 6e9f307..6c42c90 100644 --- a/src/httpbeast.nim +++ b/src/httpbeast.nim @@ -55,8 +55,10 @@ type numThreads: int loggers: seq[Logger] reusePort: bool - ## controls whether to fail with "Address already in use". - ## Setting this to false will raise when `threads` are on. + ## controls whether to use `OptReusePort` for sockets + failOnExistingPort: bool + ## Fail with "Address already in use" if port is in use, by attempting + ## to bind to a temporary socket to fail early. HttpBeastDefect* = ref object of Defect @@ -67,7 +69,8 @@ proc initSettings*(port: Port = Port(8080), bindAddr: string = "", numThreads: int = 0, domain = Domain.AF_INET, - reusePort = true): Settings = + reusePort = true, + failOnExistingPort = true): Settings = Settings( port: port, bindAddr: bindAddr, @@ -75,6 +78,7 @@ proc initSettings*(port: Port = Port(8080), numThreads: numThreads, loggers: getHandlers(), reusePort: reusePort, + failOnExistingPort: failOnExistingPort, ) proc initData(fdKind: FdKind, ip = ""): Data = @@ -311,6 +315,12 @@ proc updateDate(fd: AsyncFD): bool = result = false # Returning true signifies we want timer to stop. serverDate = now().utc().format("ddd, dd MMM yyyy HH:mm:ss 'GMT'") +proc newSocketAux(settings: Settings): owned(Socket) = + result = newSocket(settings.domain) + result.setSockOpt(OptReuseAddr, true) + result.setSockOpt(OptReusePort, settings.reusePort) + result.bindAddr(settings.port, settings.bindAddr) + proc eventLoop(params: (OnRequest, Settings)) = let (onRequest, settings) = params @@ -319,12 +329,7 @@ proc eventLoop(params: (OnRequest, Settings)) = let selector = newSelector[Data]() - let server = newSocket(settings.domain) - server.setSockOpt(OptReuseAddr, true) - if compileOption("threads") and not settings.reusePort: - raise HttpBeastDefect(msg: "--threads:on requires reusePort to be enabled in settings") - server.setSockOpt(OptReusePort, settings.reusePort) - server.bindAddr(settings.port, settings.bindAddr) + let server = newSocketAux(settings) server.listen() server.getFd().setBlocking(false) selector.registerHandle(server.getFd(), {Event.Read}, initData(Server)) @@ -475,6 +480,10 @@ proc run*(onRequest: OnRequest, settings: Settings) = let numThreads = 1 echo("Starting ", numThreads, " threads") + if settings.failOnExistingPort: + var settings2 = settings + settings2.reusePort = false + close(newSocketAux(settings2)) # attempt to bind to a temporary socket if numThreads > 1: when compileOption("threads"): var threads = newSeq[Thread[(OnRequest, Settings)]](numThreads)