// Start the monitoring server func (s *Server) startMonitoring(secure bool) { // Used to track HTTP requests s.httpReqStats = map[string]uint64{ RootPath: 0, VarzPath: 0, ConnzPath: 0, RoutezPath: 0, SubszPath: 0, } var hp string var err error if secure { hp = net.JoinHostPort(s.opts.HTTPHost, strconv.Itoa(s.opts.HTTPSPort)) Noticef("Starting https monitor on %s", hp) config := util.CloneTLSConfig(s.opts.TLSConfig) config.ClientAuth = tls.NoClientCert s.http, err = tls.Listen("tcp", hp, config) } else { hp = net.JoinHostPort(s.opts.HTTPHost, strconv.Itoa(s.opts.HTTPPort)) Noticef("Starting http monitor on %s", hp) s.http, err = net.Listen("tcp", hp) } if err != nil { Fatalf("Can't listen to the monitor port: %v", err) return } mux := http.NewServeMux() // Root mux.HandleFunc(RootPath, s.HandleRoot) // Varz mux.HandleFunc(VarzPath, s.HandleVarz) // Connz mux.HandleFunc(ConnzPath, s.HandleConnz) // Routez mux.HandleFunc(RoutezPath, s.HandleRoutez) // Subz mux.HandleFunc(SubszPath, s.HandleSubsz) // Subz alias for backwards compatibility mux.HandleFunc("/subscriptionsz", s.HandleSubsz) // Stacksz mux.HandleFunc(StackszPath, s.HandleStacksz) srv := &http.Server{ Addr: hp, Handler: mux, ReadTimeout: 2 * time.Second, WriteTimeout: 2 * time.Second, MaxHeaderBytes: 1 << 20, } go func() { srv.Serve(s.http) srv.Handler = nil s.done <- true }() }
func (s *Server) createRoute(conn net.Conn, rURL *url.URL) *client { didSolicit := rURL != nil r := &route{didSolicit: didSolicit} for _, route := range s.opts.Routes { if rURL != nil && (strings.ToLower(rURL.Host) == strings.ToLower(route.Host)) { r.routeType = Explicit } } c := &client{srv: s, nc: conn, opts: clientOpts{}, typ: ROUTER, route: r} // Grab server variables s.mu.Lock() infoJSON := s.routeInfoJSON authRequired := s.routeInfo.AuthRequired tlsRequired := s.routeInfo.TLSRequired s.mu.Unlock() // Grab lock c.mu.Lock() // Initialize c.initClient() c.Debugf("Route connection created") if didSolicit { // Do this before the TLS code, otherwise, in case of failure // and if route is explicit, it would try to reconnect to 'nil'... r.url = rURL } // Check for TLS if tlsRequired { // Copy off the config to add in ServerName if we tlsConfig := util.CloneTLSConfig(s.opts.Cluster.TLSConfig) // If we solicited, we will act like the client, otherwise the server. if didSolicit { c.Debugf("Starting TLS route client handshake") // Specify the ServerName we are expecting. host, _, _ := net.SplitHostPort(rURL.Host) tlsConfig.ServerName = host c.nc = tls.Client(c.nc, tlsConfig) } else { c.Debugf("Starting TLS route server handshake") c.nc = tls.Server(c.nc, tlsConfig) } conn := c.nc.(*tls.Conn) // Setup the timeout ttl := secondsToDuration(s.opts.Cluster.TLSTimeout) time.AfterFunc(ttl, func() { tlsTimeout(c, conn) }) conn.SetReadDeadline(time.Now().Add(ttl)) c.mu.Unlock() if err := conn.Handshake(); err != nil { c.Debugf("TLS route handshake error: %v", err) c.sendErr("Secure Connection - TLS Required") c.closeConnection() return nil } // Reset the read deadline conn.SetReadDeadline(time.Time{}) // Re-Grab lock c.mu.Lock() // Verify that the connection did not go away while we released the lock. if c.nc == nil { c.mu.Unlock() return nil } // Rewrap bw c.bw = bufio.NewWriterSize(c.nc, startBufSize) } // Do final client initialization // Set the Ping timer c.setPingTimer() // For routes, the "client" is added to s.routes only when processing // the INFO protocol, that is much later. // In the meantime, if the server shutsdown, there would be no reference // to the client (connection) to be closed, leaving this readLoop // uinterrupted, causing the Shutdown() to wait indefinitively. // We need to store the client in a special map, under a special lock. s.grMu.Lock() s.grTmpClients[c.cid] = c s.grMu.Unlock() // Spin up the read loop. s.startGoRoutine(func() { c.readLoop() }) if tlsRequired { c.Debugf("TLS handshake complete") cs := c.nc.(*tls.Conn).ConnectionState() c.Debugf("TLS version %s, cipher suite %s", tlsVersion(cs.Version), tlsCipher(cs.CipherSuite)) } // Queue Connect proto if we solicited the connection. if didSolicit { c.Debugf("Route connect msg sent") c.sendConnect(tlsRequired) } // Send our info to the other side. c.sendInfo(infoJSON) // Check for Auth required state for incoming connections. if authRequired && !didSolicit { ttl := secondsToDuration(s.opts.Cluster.AuthTimeout) c.setAuthTimer(ttl) } c.mu.Unlock() return c }