55 "net"
66 "net/http"
77 "strings"
8+ "sync"
89 "time"
910
1011 "github.com/gogo/gateway"
@@ -30,8 +31,13 @@ type Server struct {
3031 GRPCGatewayRouter * runtime.ServeMux
3132 ClientCtx client.Context
3233
33- logger log.Logger
34- metrics * telemetry.Metrics
34+ logger log.Logger
35+ metrics * telemetry.Metrics
36+ // Start() is blocking and generally called from a separate goroutine.
37+ // Close() can be called asynchronously and access shared memory
38+ // via the listener. Therefore, we sync access to Start and Close with
39+ // this mutex to avoid data races.
40+ mtx sync.Mutex
3541 listener net.Listener
3642}
3743
@@ -83,9 +89,11 @@ func New(clientCtx client.Context, logger log.Logger) *Server {
8389// and are delegated to the Tendermint JSON RPC server. The process is
8490// non-blocking, so an external signal handler must be used.
8591func (s * Server ) Start (cfg config.Config ) error {
92+ s .mtx .Lock ()
8693 if cfg .Telemetry .Enabled {
8794 m , err := telemetry .New (cfg .Telemetry )
8895 if err != nil {
96+ s .mtx .Unlock ()
8997 return err
9098 }
9199
@@ -101,6 +109,7 @@ func (s *Server) Start(cfg config.Config) error {
101109
102110 listener , err := tmrpcserver .Listen (cfg .API .Address , tmCfg )
103111 if err != nil {
112+ s .mtx .Unlock ()
104113 return err
105114 }
106115
@@ -111,15 +120,19 @@ func (s *Server) Start(cfg config.Config) error {
111120
112121 if cfg .API .EnableUnsafeCORS {
113122 allowAllCORS := handlers .CORS (handlers .AllowedHeaders ([]string {"Content-Type" }))
123+ s .mtx .Unlock ()
114124 return tmrpcserver .Serve (s .listener , allowAllCORS (h ), s .logger , tmCfg )
115125 }
116126
117127 s .logger .Info ("starting API server..." )
128+ s .mtx .Unlock ()
118129 return tmrpcserver .Serve (s .listener , s .Router , s .logger , tmCfg )
119130}
120131
121132// Close closes the API server.
122133func (s * Server ) Close () error {
134+ s .mtx .Lock ()
135+ defer s .mtx .Unlock ()
123136 return s .listener .Close ()
124137}
125138
0 commit comments