From 0c14419e7e88f66e04016e2024311452739d0cd8 Mon Sep 17 00:00:00 2001 From: dcarrillo Date: Sat, 23 Mar 2024 17:41:34 +0100 Subject: [PATCH] Server handling refactor (#27) --- cmd/whatismyip.go | 24 ++++++++++- go.mod | 8 ++-- go.sum | 19 ++++---- internal/httputils/http.go | 2 +- server/{quic_server.go => quic.go} | 15 ++++--- server/server.go | 69 ++++++++---------------------- server/{tcp_server.go => tcp.go} | 10 ++--- server/{tls_server.go => tls.go} | 10 ++--- service/port_scanner.go | 5 ++- 9 files changed, 77 insertions(+), 85 deletions(-) rename server/{quic_server.go => quic.go} (79%) rename server/{tcp_server.go => tcp.go} (88%) rename server/{tls_server.go => tls.go} (88%) diff --git a/cmd/whatismyip.go b/cmd/whatismyip.go index 62eea0e..b172965 100644 --- a/cmd/whatismyip.go +++ b/cmd/whatismyip.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "net/http" "os" "github.com/dcarrillo/whatismyip/internal/httputils" @@ -30,8 +31,9 @@ func main() { engine := setupEngine() router.SetupTemplate(engine) router.Setup(engine) + servers := setupHTTPServers(context.Background(), engine.Handler()) - whatismyip := server.Setup(context.Background(), engine.Handler()) + whatismyip := server.Setup(servers) whatismyip.Run() } @@ -55,3 +57,23 @@ func setupEngine() *gin.Engine { return engine } + +func setupHTTPServers(ctx context.Context, handler http.Handler) []server.Server { + var servers []server.Server + + if setting.App.BindAddress != "" { + tcpServer := server.NewTCPServer(ctx, &handler) + servers = append(servers, tcpServer) + } + + if setting.App.TLSAddress != "" { + tlsServer := server.NewTLSServer(ctx, &handler) + servers = append(servers, tlsServer) + if setting.App.EnableHTTP3 { + quicServer := server.NewQuicServer(ctx, tlsServer) + servers = append(servers, quicServer) + } + } + + return servers +} diff --git a/go.mod b/go.mod index 5a09ae3..5cb5228 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/quic-go/quic-go v0.40.1 github.com/stretchr/testify v1.8.4 github.com/testcontainers/testcontainers-go v0.27.0 - golang.org/x/net v0.19.0 ) require ( @@ -76,12 +75,13 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect go.uber.org/mock v0.4.0 // indirect golang.org/x/arch v0.6.0 // indirect - golang.org/x/crypto v0.17.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.16.1 // indirect + golang.org/x/tools v0.17.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index d7b852a..f0e599b 100644 --- a/go.sum +++ b/go.sum @@ -198,8 +198,8 @@ golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -210,13 +210,13 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -229,8 +229,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -241,8 +242,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/httputils/http.go b/internal/httputils/http.go index e3ccc08..9b7be09 100644 --- a/internal/httputils/http.go +++ b/internal/httputils/http.go @@ -63,7 +63,7 @@ func GetLogFormatter(param gin.LogFormatterParams) string { ) } -func normalizeLog(log interface{}) interface{} { +func normalizeLog(log any) any { switch v := log.(type) { case string: if v == "" { diff --git a/server/quic_server.go b/server/quic.go similarity index 79% rename from server/quic_server.go rename to server/quic.go index 6889389..a830f5c 100644 --- a/server/quic_server.go +++ b/server/quic.go @@ -2,6 +2,7 @@ package server import ( "context" + "errors" "log" "net/http" @@ -9,20 +10,20 @@ import ( "github.com/quic-go/quic-go/http3" ) -type QuicServer struct { +type Quic struct { server *http3.Server - tlsServer *TLSServer + tlsServer *TLS ctx context.Context } -func NewQuicServer(ctx context.Context, tlsServer *TLSServer) *QuicServer { - return &QuicServer{ +func NewQuicServer(ctx context.Context, tlsServer *TLS) *Quic { + return &Quic{ tlsServer: tlsServer, ctx: ctx, } } -func (q *QuicServer) Start() { +func (q *Quic) Start() { q.server = &http3.Server{ Addr: setting.App.TLSAddress, Handler: q.tlsServer.server.Handler, @@ -40,13 +41,13 @@ func (q *QuicServer) Start() { log.Printf("Starting QUIC server listening on %s (udp)", setting.App.TLSAddress) go func() { if err := q.server.ListenAndServeTLS(setting.App.TLSCrtPath, setting.App.TLSKeyPath); err != nil && - err.Error() != "quic: Server closed" { + !errors.Is(err, http.ErrServerClosed) { log.Fatal(err) } }() } -func (q *QuicServer) Stop() { +func (q *Quic) Stop() { log.Printf("Stopping QUIC server...") if err := q.server.Close(); err != nil { log.Printf("QUIC server forced to shutdown") diff --git a/server/server.go b/server/server.go index e4764dc..4817b50 100644 --- a/server/server.go +++ b/server/server.go @@ -2,14 +2,12 @@ package server import ( "log" - "net/http" "os" "os/signal" "syscall" "github.com/dcarrillo/whatismyip/internal/setting" "github.com/dcarrillo/whatismyip/models" - "golang.org/x/net/context" ) type Server interface { @@ -17,80 +15,47 @@ type Server interface { Stop() } -type Factory struct { - tcpServer *TCPServer - tlsServer *TLSServer - quicServer *QuicServer +type Manager struct { + servers []Server } -func Setup(ctx context.Context, handler http.Handler) *Factory { - var tcpServer *TCPServer - var tlsServer *TLSServer - var quicServer *QuicServer - - if setting.App.BindAddress != "" { - tcpServer = NewTCPServer(ctx, &handler) - } - - if setting.App.TLSAddress != "" { - tlsServer = NewTLSServer(ctx, &handler) - if setting.App.EnableHTTP3 { - quicServer = NewQuicServer(ctx, tlsServer) - } - } - - return &Factory{ - tcpServer: tcpServer, - tlsServer: tlsServer, - quicServer: quicServer, +func Setup(servers []Server) *Manager { + return &Manager{ + servers: servers, } } -func (f *Factory) Run() { - f.start() +func (m *Manager) Run() { + m.start() - signalChan := make(chan os.Signal, 3) + signalChan := make(chan os.Signal, len(m.servers)) signal.Notify(signalChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) var s os.Signal for { s = <-signalChan if s == syscall.SIGHUP { - f.stop() + m.stop() models.CloseDBs() models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN) - f.start() + m.start() } else { log.Printf("Shutting down...") - f.stop() + m.stop() models.CloseDBs() break } } } -func (f *Factory) start() { - if f.tcpServer != nil { - f.tcpServer.Start() - } - - if f.tlsServer != nil { - f.tlsServer.Start() - if f.quicServer != nil { - f.quicServer.Start() - } +func (m *Manager) start() { + for _, s := range m.servers { + s.Start() } } -func (f *Factory) stop() { - if f.tcpServer != nil { - f.tcpServer.Stop() - } - - if f.tlsServer != nil { - if f.quicServer != nil { - f.quicServer.Stop() - } - f.tlsServer.Stop() +func (m *Manager) stop() { + for _, s := range m.servers { + s.Stop() } } diff --git a/server/tcp_server.go b/server/tcp.go similarity index 88% rename from server/tcp_server.go rename to server/tcp.go index 0a4d11d..f805471 100644 --- a/server/tcp_server.go +++ b/server/tcp.go @@ -9,20 +9,20 @@ import ( "github.com/dcarrillo/whatismyip/internal/setting" ) -type TCPServer struct { +type TCP struct { server *http.Server handler *http.Handler ctx context.Context } -func NewTCPServer(ctx context.Context, handler *http.Handler) *TCPServer { - return &TCPServer{ +func NewTCPServer(ctx context.Context, handler *http.Handler) *TCP { + return &TCP{ handler: handler, ctx: ctx, } } -func (t *TCPServer) Start() { +func (t *TCP) Start() { t.server = &http.Server{ Addr: setting.App.BindAddress, Handler: *t.handler, @@ -38,7 +38,7 @@ func (t *TCPServer) Start() { }() } -func (t *TCPServer) Stop() { +func (t *TCP) Stop() { log.Printf("Stopping TCP server...") if err := t.server.Shutdown(t.ctx); err != nil { log.Printf("TCP server forced to shutdown: %s", err) diff --git a/server/tls_server.go b/server/tls.go similarity index 88% rename from server/tls_server.go rename to server/tls.go index dc269f0..47a931f 100644 --- a/server/tls_server.go +++ b/server/tls.go @@ -9,20 +9,20 @@ import ( "github.com/dcarrillo/whatismyip/internal/setting" ) -type TLSServer struct { +type TLS struct { server *http.Server handler *http.Handler ctx context.Context } -func NewTLSServer(ctx context.Context, handler *http.Handler) *TLSServer { - return &TLSServer{ +func NewTLSServer(ctx context.Context, handler *http.Handler) *TLS { + return &TLS{ handler: handler, ctx: ctx, } } -func (t *TLSServer) Start() { +func (t *TLS) Start() { t.server = &http.Server{ Addr: setting.App.TLSAddress, Handler: *t.handler, @@ -39,7 +39,7 @@ func (t *TLSServer) Start() { }() } -func (t *TLSServer) Stop() { +func (t *TLS) Stop() { log.Printf("Stopping TLS server...") if err := t.server.Shutdown(t.ctx); err != nil { log.Printf("TLS server forced to shutdown: %s", err) diff --git a/service/port_scanner.go b/service/port_scanner.go index d38ee99..c24f348 100644 --- a/service/port_scanner.go +++ b/service/port_scanner.go @@ -5,17 +5,20 @@ import ( "time" ) +const scannerTimeOut = 3 * time.Second + type PortScanner struct { Address net.Addr } func (p *PortScanner) IsPortOpen() (bool, error) { - conn, err := net.DialTimeout(p.Address.Network(), p.Address.String(), 3*time.Second) + conn, err := net.DialTimeout(p.Address.Network(), p.Address.String(), scannerTimeOut) if err != nil { return false, err } if conn != nil { defer conn.Close() } + return true, nil }