diff --git a/httpbeast.nimble b/httpbeast.nimble index ea2be4e..6727453 100644 --- a/httpbeast.nimble +++ b/httpbeast.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.0" +version = "0.5.0" 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..28c704f 100644 --- a/src/httpbeast.nim +++ b/src/httpbeast.nim @@ -54,9 +54,10 @@ type domain*: Domain 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. + failOnExistingPort: bool + ## Fail with "Address already in use" if port is in use, by attempting + ## to bind to a temporary socket to fail early if `numThreads>1`, or + ## not setting `OptReusePort` if `numThreads==1`. HttpBeastDefect* = ref object of Defect @@ -67,14 +68,14 @@ proc initSettings*(port: Port = Port(8080), bindAddr: string = "", numThreads: int = 0, domain = Domain.AF_INET, - reusePort = true): Settings = + failOnExistingPort = true): Settings = Settings( port: port, bindAddr: bindAddr, domain: domain, numThreads: numThreads, loggers: getHandlers(), - reusePort: reusePort, + failOnExistingPort: failOnExistingPort, ) proc initData(fdKind: FdKind, ip = ""): Data = @@ -311,6 +312,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, not settings.failOnExistingPort) + result.bindAddr(settings.port, settings.bindAddr) + proc eventLoop(params: (OnRequest, Settings)) = let (onRequest, settings) = params @@ -319,12 +326,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)) @@ -476,6 +478,10 @@ proc run*(onRequest: OnRequest, settings: Settings) = echo("Starting ", numThreads, " threads") if numThreads > 1: + if settings.failOnExistingPort: + close(newSocketAux(settings)) # attempt to bind to a temporary socket + var settings = settings + settings.failOnExistingPort = false when compileOption("threads"): var threads = newSeq[Thread[(OnRequest, Settings)]](numThreads) for i in 0 ..< numThreads: