From 4237486605e816c046ca08df866ba731b7c7915d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 4 Jul 2021 13:59:37 -0700 Subject: [PATCH 1/4] reusePort = false now default; honored regarless of numThreads --- httpbeast.nimble | 2 +- src/httpbeast.nim | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) 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..39874eb 100644 --- a/src/httpbeast.nim +++ b/src/httpbeast.nim @@ -54,9 +54,7 @@ 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. + reusePort: bool ## controls whether to fail with "Address already in use". HttpBeastDefect* = ref object of Defect @@ -67,7 +65,7 @@ proc initSettings*(port: Port = Port(8080), bindAddr: string = "", numThreads: int = 0, domain = Domain.AF_INET, - reusePort = true): Settings = + reusePort = false): Settings = Settings( port: port, bindAddr: bindAddr, @@ -311,6 +309,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 +323,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)) @@ -477,12 +476,17 @@ proc run*(onRequest: OnRequest, settings: Settings) = echo("Starting ", numThreads, " threads") if numThreads > 1: when compileOption("threads"): + var settings2 = settings + if not settings.reusePort and numThreads > 1: + let server = newSocketAux(settings) + close(server) # binds to a temporary socket to honor `reusePort = false` + settings2.reusePort = true var threads = newSeq[Thread[(OnRequest, Settings)]](numThreads) for i in 0 ..< numThreads: createThread[(OnRequest, Settings)]( - threads[i], eventLoop, (onRequest, settings) + threads[i], eventLoop, (onRequest, settings2) ) - echo("Listening on port ", settings.port) # This line is used in the tester to signal readiness. + echo("Listening on port ", settings2.port) # This line is used in the tester to signal readiness. joinThreads(threads) else: assert false From 3c9adbdb987decb4f7d338f17ca1ff770004d22a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Jul 2021 17:25:07 -0700 Subject: [PATCH 2/4] use failOnExistingPort --- src/httpbeast.nim | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/httpbeast.nim b/src/httpbeast.nim index 39874eb..6c42c90 100644 --- a/src/httpbeast.nim +++ b/src/httpbeast.nim @@ -54,7 +54,11 @@ type domain*: Domain numThreads: int loggers: seq[Logger] - reusePort: bool ## controls whether to fail with "Address already in use". + reusePort: bool + ## 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 @@ -65,7 +69,8 @@ proc initSettings*(port: Port = Port(8080), bindAddr: string = "", numThreads: int = 0, domain = Domain.AF_INET, - reusePort = false): Settings = + reusePort = true, + failOnExistingPort = true): Settings = Settings( port: port, bindAddr: bindAddr, @@ -73,6 +78,7 @@ proc initSettings*(port: Port = Port(8080), numThreads: numThreads, loggers: getHandlers(), reusePort: reusePort, + failOnExistingPort: failOnExistingPort, ) proc initData(fdKind: FdKind, ip = ""): Data = @@ -474,19 +480,18 @@ 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 settings2 = settings - if not settings.reusePort and numThreads > 1: - let server = newSocketAux(settings) - close(server) # binds to a temporary socket to honor `reusePort = false` - settings2.reusePort = true var threads = newSeq[Thread[(OnRequest, Settings)]](numThreads) for i in 0 ..< numThreads: createThread[(OnRequest, Settings)]( - threads[i], eventLoop, (onRequest, settings2) + threads[i], eventLoop, (onRequest, settings) ) - echo("Listening on port ", settings2.port) # This line is used in the tester to signal readiness. + echo("Listening on port ", settings.port) # This line is used in the tester to signal readiness. joinThreads(threads) else: assert false From 74ef5fc1131e7084bce990458df83ff9a4dc9527 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Jul 2021 18:03:56 -0700 Subject: [PATCH 3/4] use failOnExistingPort and remove reusePort option --- src/httpbeast.nim | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/httpbeast.nim b/src/httpbeast.nim index 6c42c90..28c704f 100644 --- a/src/httpbeast.nim +++ b/src/httpbeast.nim @@ -54,11 +54,10 @@ type domain*: Domain numThreads: int loggers: seq[Logger] - reusePort: bool - ## 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. + ## to bind to a temporary socket to fail early if `numThreads>1`, or + ## not setting `OptReusePort` if `numThreads==1`. HttpBeastDefect* = ref object of Defect @@ -69,7 +68,6 @@ proc initSettings*(port: Port = Port(8080), bindAddr: string = "", numThreads: int = 0, domain = Domain.AF_INET, - reusePort = true, failOnExistingPort = true): Settings = Settings( port: port, @@ -77,7 +75,6 @@ proc initSettings*(port: Port = Port(8080), domain: domain, numThreads: numThreads, loggers: getHandlers(), - reusePort: reusePort, failOnExistingPort: failOnExistingPort, ) @@ -318,7 +315,7 @@ proc updateDate(fd: AsyncFD): bool = proc newSocketAux(settings: Settings): owned(Socket) = result = newSocket(settings.domain) result.setSockOpt(OptReuseAddr, true) - result.setSockOpt(OptReusePort, settings.reusePort) + result.setSockOpt(OptReusePort, not settings.failOnExistingPort) result.bindAddr(settings.port, settings.bindAddr) proc eventLoop(params: (OnRequest, Settings)) = @@ -480,11 +477,11 @@ 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: + 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: From 1ea9edd2cd5a476db232b53b4553714dbf507055 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Jul 2021 18:30:01 -0700 Subject: [PATCH 4/4] bump version because of the change --- httpbeast.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpbeast.nimble b/httpbeast.nimble index 50246aa..6727453 100644 --- a/httpbeast.nimble +++ b/httpbeast.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.1" +version = "0.5.0" author = "Dominik Picheta" description = "A super-fast epoll-backed and parallel HTTP server." license = "MIT"