From 4fe03fb233d2f7de24a0031437d993ddc7d67928 Mon Sep 17 00:00:00 2001 From: Ola Bini Date: Wed, 25 Mar 2020 19:38:32 +0000 Subject: [PATCH] Add a configuration parameter making it possible to avoid listening to the web port --- cmd/grumble/server.go | 104 +++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/cmd/grumble/server.go b/cmd/grumble/server.go index 8dc0f21..ac6963b 100644 --- a/cmd/grumble/server.go +++ b/cmd/grumble/server.go @@ -1355,6 +1355,12 @@ func (server *Server) Port() int { return port } +// ListenWebPort returns true if we should listen to the +// web port, otherwise false +func (server *Server) ListenWebPort() bool { + return !server.cfg.BoolValue("NoWebServer") +} + // WebPort returns the port the web server will listen on when it is // started. func (server *Server) WebPort() int { @@ -1396,6 +1402,7 @@ func (server *Server) Start() (err error) { host := server.HostAddress() port := server.Port() webport := server.WebPort() + shouldListenWeb := server.ListenWebPort() // Setup our UDP listener server.udpconn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP(host), Port: port}) @@ -1434,37 +1441,42 @@ func (server *Server) Start() (err error) { } server.tlsl = tls.NewListener(server.tcpl, server.tlscfg) - // Create HTTP server and WebSocket "listener" - webaddr := &net.TCPAddr{IP: net.ParseIP(host), Port: webport} - server.webtlscfg = &tls.Config{ - Certificates: []tls.Certificate{cert}, - ClientAuth: tls.NoClientCert, - NextProtos: []string{"http/1.1"}, - } - server.webwsl = web.NewListener(webaddr, server.Logger) - mux := http.NewServeMux() - mux.Handle("/", server.webwsl) - server.webhttp = &http.Server{ - Addr: webaddr.String(), - Handler: mux, - TLSConfig: server.webtlscfg, - ErrorLog: server.Logger, - - // Set sensible timeouts, in case no reverse proxy is in front of Grumble. - // Non-conforming (or malicious) clients may otherwise block indefinitely and cause - // file descriptors (or handles, depending on your OS) to leak and/or be exhausted - ReadTimeout: 5 * time.Second, - WriteTimeout: 10 * time.Second, - IdleTimeout: 2 * time.Minute, + if shouldListenWeb { + // Create HTTP server and WebSocket "listener" + webaddr := &net.TCPAddr{IP: net.ParseIP(host), Port: webport} + server.webtlscfg = &tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientAuth: tls.NoClientCert, + NextProtos: []string{"http/1.1"}, + } + server.webwsl = web.NewListener(webaddr, server.Logger) + mux := http.NewServeMux() + mux.Handle("/", server.webwsl) + server.webhttp = &http.Server{ + Addr: webaddr.String(), + Handler: mux, + TLSConfig: server.webtlscfg, + ErrorLog: server.Logger, + + // Set sensible timeouts, in case no reverse proxy is in front of Grumble. + // Non-conforming (or malicious) clients may otherwise block indefinitely and cause + // file descriptors (or handles, depending on your OS) to leak and/or be exhausted + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 2 * time.Minute, + } + go func() { + err := server.webhttp.ListenAndServeTLS("", "") + if err != http.ErrServerClosed { + server.Fatalf("Fatal HTTP server error: %v", err) + } + }() + + server.Printf("Started: listening on %v and %v", server.tcpl.Addr(), server.webwsl.Addr()) + } else { + server.Printf("Started: listening on %v", server.tcpl.Addr()) } - go func() { - err := server.webhttp.ListenAndServeTLS("", "") - if err != http.ErrServerClosed { - server.Fatalf("Fatal HTTP server error: %v", err) - } - }() - server.Printf("Started: listening on %v and %v", server.tcpl.Addr(), server.webwsl.Addr()) server.running = true // Open a fresh freezer log @@ -1487,10 +1499,17 @@ func (server *Server) Start() (err error) { // for the servers. Each network goroutine defers a call to // netwg.Done(). In the Stop() we close all the connections // and call netwg.Wait() to wait for the goroutines to end. - server.netwg.Add(3) + numWG := 2 + if shouldListenWeb { + numWG++ + } + + server.netwg.Add(numWG) go server.udpListenLoop() go server.acceptLoop(server.tlsl) - go server.acceptLoop(server.webwsl) + if shouldListenWeb { + go server.acceptLoop(server.webwsl) + } // Schedule a server registration update (if needed) go func() { @@ -1520,12 +1539,19 @@ func (server *Server) Stop() (err error) { // This does not apply to opened WebSockets, which were forcibly closed when // all clients were disconnected. ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(15*time.Second)) - err = server.webhttp.Shutdown(ctx) - cancel() - if err == context.DeadlineExceeded { - server.Println("Forcibly shutdown HTTP server while stopping") - } else if err != nil { - return err + if server.ListenWebPort() { + err = server.webhttp.Shutdown(ctx) + cancel() + if err == context.DeadlineExceeded { + server.Println("Forcibly shutdown HTTP server while stopping") + } else if err != nil { + return err + } + + err = server.webwsl.Close() + if err != nil { + return err + } } // Close the listeners @@ -1533,10 +1559,6 @@ func (server *Server) Stop() (err error) { if err != nil { return err } - err = server.webwsl.Close() - if err != nil { - return err - } // Close the UDP connection err = server.udpconn.Close()