github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/gateway.go (about)

     1  // Copyright 2018-2024 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"bytes"
    18  	"crypto/sha256"
    19  	"crypto/tls"
    20  	"encoding/json"
    21  	"fmt"
    22  	"math/rand"
    23  	"net"
    24  	"net/url"
    25  	"sort"
    26  	"strconv"
    27  	"sync"
    28  	"sync/atomic"
    29  	"time"
    30  )
    31  
    32  const (
    33  	defaultSolicitGatewaysDelay         = time.Second
    34  	defaultGatewayConnectDelay          = time.Second
    35  	defaultGatewayReconnectDelay        = time.Second
    36  	defaultGatewayRecentSubExpiration   = 2 * time.Second
    37  	defaultGatewayMaxRUnsubBeforeSwitch = 1000
    38  
    39  	oldGWReplyPrefix    = "$GR."
    40  	oldGWReplyPrefixLen = len(oldGWReplyPrefix)
    41  	oldGWReplyStart     = oldGWReplyPrefixLen + 5 // len of prefix above + len of hash (4) + "."
    42  
    43  	// The new prefix is "_GR_.<cluster>.<server>." where <cluster> is 6 characters
    44  	// hash of origin cluster name and <server> is 6 characters hash of origin server pub key.
    45  	gwReplyPrefix    = "_GR_."
    46  	gwReplyPrefixLen = len(gwReplyPrefix)
    47  	gwHashLen        = 6
    48  	gwClusterOffset  = gwReplyPrefixLen
    49  	gwServerOffset   = gwClusterOffset + gwHashLen + 1
    50  	gwSubjectOffset  = gwServerOffset + gwHashLen + 1
    51  
    52  	// Gateway connections send PINGs regardless of traffic. The interval is
    53  	// either Options.PingInterval or this value, whichever is the smallest.
    54  	gwMaxPingInterval = 15 * time.Second
    55  )
    56  
    57  var (
    58  	gatewayConnectDelay          = defaultGatewayConnectDelay
    59  	gatewayReconnectDelay        = defaultGatewayReconnectDelay
    60  	gatewayMaxRUnsubBeforeSwitch = defaultGatewayMaxRUnsubBeforeSwitch
    61  	gatewaySolicitDelay          = int64(defaultSolicitGatewaysDelay)
    62  	gatewayMaxPingInterval       = gwMaxPingInterval
    63  )
    64  
    65  // Warning when user configures gateway TLS insecure
    66  const gatewayTLSInsecureWarning = "TLS certificate chain and hostname of solicited gateways will not be verified. DO NOT USE IN PRODUCTION!"
    67  
    68  // SetGatewaysSolicitDelay sets the initial delay before gateways
    69  // connections are initiated.
    70  // Used by tests.
    71  func SetGatewaysSolicitDelay(delay time.Duration) {
    72  	atomic.StoreInt64(&gatewaySolicitDelay, int64(delay))
    73  }
    74  
    75  // ResetGatewaysSolicitDelay resets the initial delay before gateways
    76  // connections are initiated to its default values.
    77  // Used by tests.
    78  func ResetGatewaysSolicitDelay() {
    79  	atomic.StoreInt64(&gatewaySolicitDelay, int64(defaultSolicitGatewaysDelay))
    80  }
    81  
    82  const (
    83  	gatewayCmdGossip          byte = 1
    84  	gatewayCmdAllSubsStart    byte = 2
    85  	gatewayCmdAllSubsComplete byte = 3
    86  )
    87  
    88  // GatewayInterestMode represents an account interest mode for a gateway connection
    89  type GatewayInterestMode byte
    90  
    91  // GatewayInterestMode values
    92  const (
    93  	// optimistic is the default mode where a cluster will send
    94  	// to a gateway unless it is been told that there is no interest
    95  	// (this is for plain subscribers only).
    96  	Optimistic GatewayInterestMode = iota
    97  	// transitioning is when a gateway has to send too many
    98  	// no interest on subjects to the remote and decides that it is
    99  	// now time to move to modeInterestOnly (this is on a per account
   100  	// basis).
   101  	Transitioning
   102  	// interestOnly means that a cluster sends all it subscriptions
   103  	// interest to the gateway, which in return does not send a message
   104  	// unless it knows that there is explicit interest.
   105  	InterestOnly
   106  )
   107  
   108  func (im GatewayInterestMode) String() string {
   109  	switch im {
   110  	case Optimistic:
   111  		return "Optimistic"
   112  	case InterestOnly:
   113  		return "Interest-Only"
   114  	case Transitioning:
   115  		return "Transitioning"
   116  	default:
   117  		return "Unknown"
   118  	}
   119  }
   120  
   121  var gwDoNotForceInterestOnlyMode bool
   122  
   123  // GatewayDoNotForceInterestOnlyMode is used ONLY in tests.
   124  // DO NOT USE in normal code or if you embed the NATS Server.
   125  func GatewayDoNotForceInterestOnlyMode(doNotForce bool) {
   126  	gwDoNotForceInterestOnlyMode = doNotForce
   127  }
   128  
   129  type srvGateway struct {
   130  	totalQSubs int64 //total number of queue subs in all remote gateways (used with atomic operations)
   131  	sync.RWMutex
   132  	enabled  bool                   // Immutable, true if both a name and port are configured
   133  	name     string                 // Name of the Gateway on this server
   134  	out      map[string]*client     // outbound gateways
   135  	outo     []*client              // outbound gateways maintained in an order suitable for sending msgs (currently based on RTT)
   136  	in       map[uint64]*client     // inbound gateways
   137  	remotes  map[string]*gatewayCfg // Config of remote gateways
   138  	URLs     refCountedUrlSet       // Set of all Gateway URLs in the cluster
   139  	URL      string                 // This server gateway URL (after possible random port is resolved)
   140  	info     *Info                  // Gateway Info protocol
   141  	infoJSON []byte                 // Marshal'ed Info protocol
   142  	runknown bool                   // Rejects unknown (not configured) gateway connections
   143  	replyPfx []byte                 // Will be "$GNR.<1:reserved>.<8:cluster hash>.<8:server hash>."
   144  
   145  	// For backward compatibility
   146  	oldReplyPfx []byte
   147  	oldHash     []byte
   148  
   149  	// We maintain the interest of subjects and queues per account.
   150  	// For a given account, entries in the map could be something like this:
   151  	// foo.bar {n: 3} 			// 3 subs on foo.bar
   152  	// foo.>   {n: 6}			// 6 subs on foo.>
   153  	// foo bar {n: 1, q: true}  // 1 qsub on foo, queue bar
   154  	// foo baz {n: 3, q: true}  // 3 qsubs on foo, queue baz
   155  	pasi struct {
   156  		// Protect map since accessed from different go-routine and avoid
   157  		// possible race resulting in RS+ being sent before RS- resulting
   158  		// in incorrect interest suppression.
   159  		// Will use while sending QSubs (on GW connection accept) and when
   160  		// switching to the send-all-subs mode.
   161  		sync.Mutex
   162  		m map[string]map[string]*sitally
   163  	}
   164  
   165  	// This is to track recent subscriptions for a given account
   166  	rsubs sync.Map
   167  
   168  	resolver  netResolver   // Used to resolve host name before calling net.Dial()
   169  	sqbsz     int           // Max buffer size to send queue subs protocol. Used for testing.
   170  	recSubExp time.Duration // For how long do we check if there is a subscription match for a message with reply
   171  
   172  	// These are used for routing of mapped replies.
   173  	sIDHash        []byte   // Server ID hash (6 bytes)
   174  	routesIDByHash sync.Map // Route's server ID is hashed (6 bytes) and stored in this map.
   175  
   176  	// If a server has its own configuration in the "Gateways" remotes configuration
   177  	// we will keep track of the URLs that are defined in the config so they can
   178  	// be reported in monitoring.
   179  	ownCfgURLs []string
   180  }
   181  
   182  // Subject interest tally. Also indicates if the key in the map is a
   183  // queue or not.
   184  type sitally struct {
   185  	n int32 // number of subscriptions directly matching
   186  	q bool  // indicate that this is a queue
   187  }
   188  
   189  type gatewayCfg struct {
   190  	sync.RWMutex
   191  	*RemoteGatewayOpts
   192  	hash           []byte
   193  	oldHash        []byte
   194  	urls           map[string]*url.URL
   195  	connAttempts   int
   196  	tlsName        string
   197  	implicit       bool
   198  	varzUpdateURLs bool // Tells monitoring code to update URLs when varz is inspected.
   199  }
   200  
   201  // Struct for client's gateway related fields
   202  type gateway struct {
   203  	name       string
   204  	cfg        *gatewayCfg
   205  	connectURL *url.URL          // Needed when sending CONNECT after receiving INFO from remote
   206  	outsim     *sync.Map         // Per-account subject interest (or no-interest) (outbound conn)
   207  	insim      map[string]*insie // Per-account subject no-interest sent or modeInterestOnly mode (inbound conn)
   208  
   209  	// This is an outbound GW connection
   210  	outbound bool
   211  	// Set/check in readLoop without lock. This is to know that an inbound has sent the CONNECT protocol first
   212  	connected bool
   213  	// Set to true if outbound is to a server that only knows about $GR, not $GNR
   214  	useOldPrefix bool
   215  	// If true, it indicates that the inbound side will switch any account to
   216  	// interest-only mode "immediately", so the outbound should disregard
   217  	// the optimistic mode when checking for interest.
   218  	interestOnlyMode bool
   219  	// Name of the remote server
   220  	remoteName string
   221  }
   222  
   223  // Outbound subject interest entry.
   224  type outsie struct {
   225  	sync.RWMutex
   226  	// Indicate that all subs should be stored. This is
   227  	// set to true when receiving the command from the
   228  	// remote that we are about to receive all its subs.
   229  	mode GatewayInterestMode
   230  	// If not nil, used for no-interest for plain subs.
   231  	// If a subject is present in this map, it means that
   232  	// the remote is not interested in that subject.
   233  	// When we have received the command that says that
   234  	// the remote has sent all its subs, this is set to nil.
   235  	ni map[string]struct{}
   236  	// Contains queue subscriptions when in optimistic mode,
   237  	// and all subs when pk is > 0.
   238  	sl *Sublist
   239  	// Number of queue subs
   240  	qsubs int
   241  }
   242  
   243  // Inbound subject interest entry.
   244  // If `ni` is not nil, it stores the subjects for which an
   245  // RS- was sent to the remote gateway. When a subscription
   246  // is created, this is used to know if we need to send
   247  // an RS+ to clear the no-interest in the remote.
   248  // When an account is switched to modeInterestOnly (we send
   249  // all subs of an account to the remote), then `ni` is nil and
   250  // when all subs have been sent, mode is set to modeInterestOnly
   251  type insie struct {
   252  	ni   map[string]struct{} // Record if RS- was sent for given subject
   253  	mode GatewayInterestMode
   254  }
   255  
   256  type gwReplyMap struct {
   257  	ms  string
   258  	exp int64
   259  }
   260  
   261  type gwReplyMapping struct {
   262  	// Indicate if we should check the map or not. Since checking the map is done
   263  	// when processing inbound messages and requires the lock we want to
   264  	// check only when needed. This is set/get using atomic, so needs to
   265  	// be memory aligned.
   266  	check int32
   267  	// To keep track of gateway replies mapping
   268  	mapping map[string]*gwReplyMap
   269  }
   270  
   271  // Returns the corresponding gw routed subject, and `true` to indicate that a
   272  // mapping was found. If no entry is found, the passed subject is returned
   273  // as-is and `false` is returned to indicate that no mapping was found.
   274  // Caller is responsible to ensure the locking.
   275  func (g *gwReplyMapping) get(subject []byte) ([]byte, bool) {
   276  	rm, ok := g.mapping[string(subject)]
   277  	if !ok {
   278  		return subject, false
   279  	}
   280  	subj := []byte(rm.ms)
   281  	return subj, true
   282  }
   283  
   284  // clone returns a deep copy of the RemoteGatewayOpts object
   285  func (r *RemoteGatewayOpts) clone() *RemoteGatewayOpts {
   286  	if r == nil {
   287  		return nil
   288  	}
   289  	clone := &RemoteGatewayOpts{
   290  		Name: r.Name,
   291  		URLs: deepCopyURLs(r.URLs),
   292  	}
   293  	if r.TLSConfig != nil {
   294  		clone.TLSConfig = r.TLSConfig.Clone()
   295  		clone.TLSTimeout = r.TLSTimeout
   296  	}
   297  	return clone
   298  }
   299  
   300  // Ensure that gateway is properly configured.
   301  func validateGatewayOptions(o *Options) error {
   302  	if o.Gateway.Name == "" && o.Gateway.Port == 0 {
   303  		return nil
   304  	}
   305  	if o.Gateway.Name == "" {
   306  		return fmt.Errorf("gateway has no name")
   307  	}
   308  	if o.Gateway.Port == 0 {
   309  		return fmt.Errorf("gateway %q has no port specified (select -1 for random port)", o.Gateway.Name)
   310  	}
   311  	for i, g := range o.Gateway.Gateways {
   312  		if g.Name == "" {
   313  			return fmt.Errorf("gateway in the list %d has no name", i)
   314  		}
   315  		if len(g.URLs) == 0 {
   316  			return fmt.Errorf("gateway %q has no URL", g.Name)
   317  		}
   318  	}
   319  	if err := validatePinnedCerts(o.Gateway.TLSPinnedCerts); err != nil {
   320  		return fmt.Errorf("gateway %q: %v", o.Gateway.Name, err)
   321  	}
   322  	return nil
   323  }
   324  
   325  // Computes a hash of 6 characters for the name.
   326  // This will be used for routing of replies.
   327  func getGWHash(name string) []byte {
   328  	return []byte(getHashSize(name, gwHashLen))
   329  }
   330  
   331  func getOldHash(name string) []byte {
   332  	sha := sha256.New()
   333  	sha.Write([]byte(name))
   334  	fullHash := []byte(fmt.Sprintf("%x", sha.Sum(nil)))
   335  	return fullHash[:4]
   336  }
   337  
   338  // Initialize the s.gateway structure. We do this even if the server
   339  // does not have a gateway configured. In some part of the code, the
   340  // server will check the number of outbound gateways, etc.. and so
   341  // we don't have to check if s.gateway is nil or not.
   342  func (s *Server) newGateway(opts *Options) error {
   343  	gateway := &srvGateway{
   344  		name:     opts.Gateway.Name,
   345  		out:      make(map[string]*client),
   346  		outo:     make([]*client, 0, 4),
   347  		in:       make(map[uint64]*client),
   348  		remotes:  make(map[string]*gatewayCfg),
   349  		URLs:     make(refCountedUrlSet),
   350  		resolver: opts.Gateway.resolver,
   351  		runknown: opts.Gateway.RejectUnknown,
   352  		oldHash:  getOldHash(opts.Gateway.Name),
   353  	}
   354  	gateway.Lock()
   355  	defer gateway.Unlock()
   356  
   357  	gateway.sIDHash = getGWHash(s.info.ID)
   358  	clusterHash := getGWHash(opts.Gateway.Name)
   359  	prefix := make([]byte, 0, gwSubjectOffset)
   360  	prefix = append(prefix, gwReplyPrefix...)
   361  	prefix = append(prefix, clusterHash...)
   362  	prefix = append(prefix, '.')
   363  	prefix = append(prefix, gateway.sIDHash...)
   364  	prefix = append(prefix, '.')
   365  	gateway.replyPfx = prefix
   366  
   367  	prefix = make([]byte, 0, oldGWReplyStart)
   368  	prefix = append(prefix, oldGWReplyPrefix...)
   369  	prefix = append(prefix, gateway.oldHash...)
   370  	prefix = append(prefix, '.')
   371  	gateway.oldReplyPfx = prefix
   372  
   373  	gateway.pasi.m = make(map[string]map[string]*sitally)
   374  
   375  	if gateway.resolver == nil {
   376  		gateway.resolver = netResolver(net.DefaultResolver)
   377  	}
   378  
   379  	// Create remote gateways
   380  	for _, rgo := range opts.Gateway.Gateways {
   381  		// Ignore if there is a remote gateway with our name.
   382  		if rgo.Name == gateway.name {
   383  			gateway.ownCfgURLs = getURLsAsString(rgo.URLs)
   384  			continue
   385  		}
   386  		cfg := &gatewayCfg{
   387  			RemoteGatewayOpts: rgo.clone(),
   388  			hash:              getGWHash(rgo.Name),
   389  			oldHash:           getOldHash(rgo.Name),
   390  			urls:              make(map[string]*url.URL, len(rgo.URLs)),
   391  		}
   392  		if opts.Gateway.TLSConfig != nil && cfg.TLSConfig == nil {
   393  			cfg.TLSConfig = opts.Gateway.TLSConfig.Clone()
   394  		}
   395  		if cfg.TLSTimeout == 0 {
   396  			cfg.TLSTimeout = opts.Gateway.TLSTimeout
   397  		}
   398  		for _, u := range rgo.URLs {
   399  			// For TLS, look for a hostname that we can use for TLSConfig.ServerName
   400  			cfg.saveTLSHostname(u)
   401  			cfg.urls[u.Host] = u
   402  		}
   403  		gateway.remotes[cfg.Name] = cfg
   404  	}
   405  
   406  	gateway.sqbsz = opts.Gateway.sendQSubsBufSize
   407  	if gateway.sqbsz == 0 {
   408  		gateway.sqbsz = maxBufSize
   409  	}
   410  	gateway.recSubExp = defaultGatewayRecentSubExpiration
   411  
   412  	gateway.enabled = opts.Gateway.Name != "" && opts.Gateway.Port != 0
   413  	s.gateway = gateway
   414  	return nil
   415  }
   416  
   417  // Update remote gateways TLS configurations after a config reload.
   418  func (g *srvGateway) updateRemotesTLSConfig(opts *Options) {
   419  	g.Lock()
   420  	defer g.Unlock()
   421  
   422  	for _, ro := range opts.Gateway.Gateways {
   423  		if ro.Name == g.name {
   424  			continue
   425  		}
   426  		if cfg, ok := g.remotes[ro.Name]; ok {
   427  			cfg.Lock()
   428  			// If TLS config is in remote, use that one, otherwise,
   429  			// use the TLS config from the main block.
   430  			if ro.TLSConfig != nil {
   431  				cfg.TLSConfig = ro.TLSConfig.Clone()
   432  			} else if opts.Gateway.TLSConfig != nil {
   433  				cfg.TLSConfig = opts.Gateway.TLSConfig.Clone()
   434  			}
   435  
   436  			// Ensure that OCSP callbacks are always setup after a reload if needed.
   437  			mustStaple := opts.OCSPConfig != nil && opts.OCSPConfig.Mode == OCSPModeAlways
   438  			if mustStaple && opts.Gateway.TLSConfig != nil {
   439  				clientCB := opts.Gateway.TLSConfig.GetClientCertificate
   440  				verifyCB := opts.Gateway.TLSConfig.VerifyConnection
   441  				if mustStaple && cfg.TLSConfig != nil {
   442  					if clientCB != nil && cfg.TLSConfig.GetClientCertificate == nil {
   443  						cfg.TLSConfig.GetClientCertificate = clientCB
   444  					}
   445  					if verifyCB != nil && cfg.TLSConfig.VerifyConnection == nil {
   446  						cfg.TLSConfig.VerifyConnection = verifyCB
   447  					}
   448  				}
   449  			}
   450  
   451  			cfg.Unlock()
   452  		}
   453  	}
   454  }
   455  
   456  // Returns if this server rejects connections from gateways that are not
   457  // explicitly configured.
   458  func (g *srvGateway) rejectUnknown() bool {
   459  	g.RLock()
   460  	reject := g.runknown
   461  	g.RUnlock()
   462  	return reject
   463  }
   464  
   465  // Starts the gateways accept loop and solicit explicit gateways
   466  // after an initial delay. This delay is meant to give a chance to
   467  // the cluster to form and this server gathers gateway URLs for this
   468  // cluster in order to send that as part of the connect/info process.
   469  func (s *Server) startGateways() {
   470  	s.startGatewayAcceptLoop()
   471  
   472  	// Delay start of creation of gateways to give a chance
   473  	// to the local cluster to form.
   474  	s.startGoRoutine(func() {
   475  		defer s.grWG.Done()
   476  
   477  		dur := s.getOpts().gatewaysSolicitDelay
   478  		if dur == 0 {
   479  			dur = time.Duration(atomic.LoadInt64(&gatewaySolicitDelay))
   480  		}
   481  
   482  		select {
   483  		case <-time.After(dur):
   484  			s.solicitGateways()
   485  		case <-s.quitCh:
   486  			return
   487  		}
   488  	})
   489  }
   490  
   491  // This starts the gateway accept loop in a go routine, unless it
   492  // is detected that the server has already been shutdown.
   493  func (s *Server) startGatewayAcceptLoop() {
   494  	if s.isShuttingDown() {
   495  		return
   496  	}
   497  
   498  	// Snapshot server options.
   499  	opts := s.getOpts()
   500  
   501  	port := opts.Gateway.Port
   502  	if port == -1 {
   503  		port = 0
   504  	}
   505  
   506  	s.mu.Lock()
   507  	hp := net.JoinHostPort(opts.Gateway.Host, strconv.Itoa(port))
   508  	l, e := natsListen("tcp", hp)
   509  	s.gatewayListenerErr = e
   510  	if e != nil {
   511  		s.mu.Unlock()
   512  		s.Fatalf("Error listening on gateway port: %d - %v", opts.Gateway.Port, e)
   513  		return
   514  	}
   515  	s.Noticef("Gateway name is %s", s.getGatewayName())
   516  	s.Noticef("Listening for gateways connections on %s",
   517  		net.JoinHostPort(opts.Gateway.Host, strconv.Itoa(l.Addr().(*net.TCPAddr).Port)))
   518  
   519  	tlsReq := opts.Gateway.TLSConfig != nil
   520  	authRequired := opts.Gateway.Username != ""
   521  	info := &Info{
   522  		ID:           s.info.ID,
   523  		Name:         opts.ServerName,
   524  		Version:      s.info.Version,
   525  		AuthRequired: authRequired,
   526  		TLSRequired:  tlsReq,
   527  		TLSVerify:    tlsReq,
   528  		MaxPayload:   s.info.MaxPayload,
   529  		Gateway:      opts.Gateway.Name,
   530  		GatewayNRP:   true,
   531  		Headers:      s.supportsHeaders(),
   532  		Proto:        s.getServerProto(),
   533  	}
   534  	// Unless in some tests we want to keep the old behavior, we are now
   535  	// (since v2.9.0) indicate that this server will switch all accounts
   536  	// to InterestOnly mode when accepting an inbound or when a new
   537  	// account is fetched.
   538  	if !gwDoNotForceInterestOnlyMode {
   539  		info.GatewayIOM = true
   540  	}
   541  
   542  	// If we have selected a random port...
   543  	if port == 0 {
   544  		// Write resolved port back to options.
   545  		opts.Gateway.Port = l.Addr().(*net.TCPAddr).Port
   546  	}
   547  	// Possibly override Host/Port based on Gateway.Advertise
   548  	if err := s.setGatewayInfoHostPort(info, opts); err != nil {
   549  		s.Fatalf("Error setting gateway INFO with Gateway.Advertise value of %s, err=%v", opts.Gateway.Advertise, err)
   550  		l.Close()
   551  		s.mu.Unlock()
   552  		return
   553  	}
   554  	// Setup state that can enable shutdown
   555  	s.gatewayListener = l
   556  
   557  	// Warn if insecure is configured in the main Gateway configuration
   558  	// or any of the RemoteGateway's. This means that we need to check
   559  	// remotes even if TLS would not be configured for the accept.
   560  	warn := tlsReq && opts.Gateway.TLSConfig.InsecureSkipVerify
   561  	if !warn {
   562  		for _, g := range opts.Gateway.Gateways {
   563  			if g.TLSConfig != nil && g.TLSConfig.InsecureSkipVerify {
   564  				warn = true
   565  				break
   566  			}
   567  		}
   568  	}
   569  	if warn {
   570  		s.Warnf(gatewayTLSInsecureWarning)
   571  	}
   572  	go s.acceptConnections(l, "Gateway", func(conn net.Conn) { s.createGateway(nil, nil, conn) }, nil)
   573  	s.mu.Unlock()
   574  }
   575  
   576  // Similar to setInfoHostPortAndGenerateJSON, but for gatewayInfo.
   577  func (s *Server) setGatewayInfoHostPort(info *Info, o *Options) error {
   578  	gw := s.gateway
   579  	gw.Lock()
   580  	defer gw.Unlock()
   581  	gw.URLs.removeUrl(gw.URL)
   582  	if o.Gateway.Advertise != "" {
   583  		advHost, advPort, err := parseHostPort(o.Gateway.Advertise, o.Gateway.Port)
   584  		if err != nil {
   585  			return err
   586  		}
   587  		info.Host = advHost
   588  		info.Port = advPort
   589  	} else {
   590  		info.Host = o.Gateway.Host
   591  		info.Port = o.Gateway.Port
   592  		// If the host is "0.0.0.0" or "::" we need to resolve to a public IP.
   593  		// This will return at most 1 IP.
   594  		hostIsIPAny, ips, err := s.getNonLocalIPsIfHostIsIPAny(info.Host, false)
   595  		if err != nil {
   596  			return err
   597  		}
   598  		if hostIsIPAny {
   599  			if len(ips) == 0 {
   600  				// TODO(ik): Should we fail here (prevent starting)? If not, we
   601  				// are going to "advertise" the 0.0.0.0:<port> url, which means
   602  				// that remote are going to try to connect to 0.0.0.0:<port>,
   603  				// which means a connect to loopback address, which is going
   604  				// to fail with either TLS error, conn refused if the remote
   605  				// is using different gateway port than this one, or error
   606  				// saying that it tried to connect to itself.
   607  				s.Errorf("Could not find any non-local IP for gateway %q with listen specification %q",
   608  					gw.name, info.Host)
   609  			} else {
   610  				// Take the first from the list...
   611  				info.Host = ips[0]
   612  			}
   613  		}
   614  	}
   615  	gw.URL = net.JoinHostPort(info.Host, strconv.Itoa(info.Port))
   616  	if o.Gateway.Advertise != "" {
   617  		s.Noticef("Advertise address for gateway %q is set to %s", gw.name, gw.URL)
   618  	} else {
   619  		s.Noticef("Address for gateway %q is %s", gw.name, gw.URL)
   620  	}
   621  	gw.URLs[gw.URL]++
   622  	gw.info = info
   623  	info.GatewayURL = gw.URL
   624  	// (re)generate the gatewayInfoJSON byte array
   625  	gw.generateInfoJSON()
   626  	return nil
   627  }
   628  
   629  // Generates the Gateway INFO protocol.
   630  // The gateway lock is held on entry
   631  func (g *srvGateway) generateInfoJSON() {
   632  	// We could be here when processing a route INFO that has a gateway URL,
   633  	// but this server is not configured for gateways, so simply ignore here.
   634  	// The configuration mismatch is reported somewhere else.
   635  	if !g.enabled || g.info == nil {
   636  		return
   637  	}
   638  	g.info.GatewayURLs = g.URLs.getAsStringSlice()
   639  	b, err := json.Marshal(g.info)
   640  	if err != nil {
   641  		panic(err)
   642  	}
   643  	g.infoJSON = []byte(fmt.Sprintf(InfoProto, b))
   644  }
   645  
   646  // Goes through the list of registered gateways and try to connect to those.
   647  // The list (remotes) is initially containing the explicit remote gateways,
   648  // but the list is augmented with any implicit (discovered) gateway. Therefore,
   649  // this function only solicit explicit ones.
   650  func (s *Server) solicitGateways() {
   651  	gw := s.gateway
   652  	gw.RLock()
   653  	defer gw.RUnlock()
   654  	for _, cfg := range gw.remotes {
   655  		// Since we delay the creation of gateways, it is
   656  		// possible that server starts to receive inbound from
   657  		// other clusters and in turn create outbounds. So here
   658  		// we create only the ones that are configured.
   659  		if !cfg.isImplicit() {
   660  			cfg := cfg // Create new instance for the goroutine.
   661  			s.startGoRoutine(func() {
   662  				s.solicitGateway(cfg, true)
   663  				s.grWG.Done()
   664  			})
   665  		}
   666  	}
   667  }
   668  
   669  // Reconnect to the gateway after a little wait period. For explicit
   670  // gateways, we also wait for the default reconnect time.
   671  func (s *Server) reconnectGateway(cfg *gatewayCfg) {
   672  	defer s.grWG.Done()
   673  
   674  	delay := time.Duration(rand.Intn(100)) * time.Millisecond
   675  	if !cfg.isImplicit() {
   676  		delay += gatewayReconnectDelay
   677  	}
   678  	select {
   679  	case <-time.After(delay):
   680  	case <-s.quitCh:
   681  		return
   682  	}
   683  	s.solicitGateway(cfg, false)
   684  }
   685  
   686  // This function will loop trying to connect to any URL attached
   687  // to the given Gateway. It will return once a connection has been created.
   688  func (s *Server) solicitGateway(cfg *gatewayCfg, firstConnect bool) {
   689  	var (
   690  		opts       = s.getOpts()
   691  		isImplicit = cfg.isImplicit()
   692  		attempts   int
   693  		typeStr    string
   694  	)
   695  	if isImplicit {
   696  		typeStr = "implicit"
   697  	} else {
   698  		typeStr = "explicit"
   699  	}
   700  
   701  	const connFmt = "Connecting to %s gateway %q (%s) at %s (attempt %v)"
   702  	const connErrFmt = "Error connecting to %s gateway %q (%s) at %s (attempt %v): %v"
   703  
   704  	for s.isRunning() {
   705  		urls := cfg.getURLs()
   706  		if len(urls) == 0 {
   707  			break
   708  		}
   709  		attempts++
   710  		report := s.shouldReportConnectErr(firstConnect, attempts)
   711  		// Iteration is random
   712  		for _, u := range urls {
   713  			address, err := s.getRandomIP(s.gateway.resolver, u.Host, nil)
   714  			if err != nil {
   715  				s.Errorf("Error getting IP for %s gateway %q (%s): %v", typeStr, cfg.Name, u.Host, err)
   716  				continue
   717  			}
   718  			if report {
   719  				s.Noticef(connFmt, typeStr, cfg.Name, u.Host, address, attempts)
   720  			} else {
   721  				s.Debugf(connFmt, typeStr, cfg.Name, u.Host, address, attempts)
   722  			}
   723  			conn, err := natsDialTimeout("tcp", address, DEFAULT_ROUTE_DIAL)
   724  			if err == nil {
   725  				// We could connect, create the gateway connection and return.
   726  				s.createGateway(cfg, u, conn)
   727  				return
   728  			}
   729  			if report {
   730  				s.Errorf(connErrFmt, typeStr, cfg.Name, u.Host, address, attempts, err)
   731  			} else {
   732  				s.Debugf(connErrFmt, typeStr, cfg.Name, u.Host, address, attempts, err)
   733  			}
   734  			// Break this loop if server is being shutdown...
   735  			if !s.isRunning() {
   736  				break
   737  			}
   738  		}
   739  		if isImplicit {
   740  			if opts.Gateway.ConnectRetries == 0 || attempts > opts.Gateway.ConnectRetries {
   741  				s.gateway.Lock()
   742  				// We could have just accepted an inbound for this remote gateway.
   743  				// So if there is an inbound, let's try again to connect.
   744  				if s.gateway.hasInbound(cfg.Name) {
   745  					s.gateway.Unlock()
   746  					continue
   747  				}
   748  				delete(s.gateway.remotes, cfg.Name)
   749  				s.gateway.Unlock()
   750  				return
   751  			}
   752  		}
   753  		select {
   754  		case <-s.quitCh:
   755  			return
   756  		case <-time.After(gatewayConnectDelay):
   757  			continue
   758  		}
   759  	}
   760  }
   761  
   762  // Returns true if there is an inbound for the given `name`.
   763  // Lock held on entry.
   764  func (g *srvGateway) hasInbound(name string) bool {
   765  	for _, ig := range g.in {
   766  		ig.mu.Lock()
   767  		igname := ig.gw.name
   768  		ig.mu.Unlock()
   769  		if igname == name {
   770  			return true
   771  		}
   772  	}
   773  	return false
   774  }
   775  
   776  // Called when a gateway connection is either accepted or solicited.
   777  // If accepted, the gateway is marked as inbound.
   778  // If solicited, the gateway is marked as outbound.
   779  func (s *Server) createGateway(cfg *gatewayCfg, url *url.URL, conn net.Conn) {
   780  	// Snapshot server options.
   781  	opts := s.getOpts()
   782  
   783  	now := time.Now()
   784  	c := &client{srv: s, nc: conn, start: now, last: now, kind: GATEWAY}
   785  
   786  	// Are we creating the gateway based on the configuration
   787  	solicit := cfg != nil
   788  	var tlsRequired bool
   789  
   790  	s.gateway.RLock()
   791  	infoJSON := s.gateway.infoJSON
   792  	s.gateway.RUnlock()
   793  
   794  	// Perform some initialization under the client lock
   795  	c.mu.Lock()
   796  	c.initClient()
   797  	c.gw = &gateway{}
   798  	if solicit {
   799  		// This is an outbound gateway connection
   800  		cfg.RLock()
   801  		tlsRequired = cfg.TLSConfig != nil
   802  		cfgName := cfg.Name
   803  		cfg.RUnlock()
   804  		c.gw.outbound = true
   805  		c.gw.name = cfgName
   806  		c.gw.cfg = cfg
   807  		cfg.bumpConnAttempts()
   808  		// Since we are delaying the connect until after receiving
   809  		// the remote's INFO protocol, save the URL we need to connect to.
   810  		c.gw.connectURL = url
   811  
   812  		c.Noticef("Creating outbound gateway connection to %q", cfgName)
   813  	} else {
   814  		c.flags.set(expectConnect)
   815  		// Inbound gateway connection
   816  		c.Noticef("Processing inbound gateway connection")
   817  		// Check if TLS is required for inbound GW connections.
   818  		tlsRequired = opts.Gateway.TLSConfig != nil
   819  		// We expect a CONNECT from the accepted connection.
   820  		c.setAuthTimer(secondsToDuration(opts.Gateway.AuthTimeout))
   821  	}
   822  
   823  	// Check for TLS
   824  	if tlsRequired {
   825  		var tlsConfig *tls.Config
   826  		var tlsName string
   827  		var timeout float64
   828  
   829  		if solicit {
   830  			var (
   831  				mustStaple = opts.OCSPConfig != nil && opts.OCSPConfig.Mode == OCSPModeAlways
   832  				clientCB   func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
   833  				verifyCB   func(tls.ConnectionState) error
   834  			)
   835  			// Snapshot callbacks for OCSP outside an ongoing reload which might be happening.
   836  			if mustStaple {
   837  				s.reloadMu.RLock()
   838  				s.optsMu.RLock()
   839  				clientCB = s.opts.Gateway.TLSConfig.GetClientCertificate
   840  				verifyCB = s.opts.Gateway.TLSConfig.VerifyConnection
   841  				s.optsMu.RUnlock()
   842  				s.reloadMu.RUnlock()
   843  			}
   844  
   845  			cfg.RLock()
   846  			tlsName = cfg.tlsName
   847  			tlsConfig = cfg.TLSConfig.Clone()
   848  			timeout = cfg.TLSTimeout
   849  
   850  			// Ensure that OCSP callbacks are always setup on gateway reconnect when OCSP policy is set to always.
   851  			if mustStaple {
   852  				if clientCB != nil && tlsConfig.GetClientCertificate == nil {
   853  					tlsConfig.GetClientCertificate = clientCB
   854  				}
   855  				if verifyCB != nil && tlsConfig.VerifyConnection == nil {
   856  					tlsConfig.VerifyConnection = verifyCB
   857  				}
   858  			}
   859  			cfg.RUnlock()
   860  		} else {
   861  			tlsConfig = opts.Gateway.TLSConfig
   862  			timeout = opts.Gateway.TLSTimeout
   863  		}
   864  
   865  		// Perform (either server or client side) TLS handshake.
   866  		if resetTLSName, err := c.doTLSHandshake("gateway", solicit, url, tlsConfig, tlsName, timeout, opts.Gateway.TLSPinnedCerts); err != nil {
   867  			if resetTLSName {
   868  				cfg.Lock()
   869  				cfg.tlsName = _EMPTY_
   870  				cfg.Unlock()
   871  			}
   872  			c.mu.Unlock()
   873  			return
   874  		}
   875  	}
   876  
   877  	// Do final client initialization
   878  	c.in.pacache = make(map[string]*perAccountCache)
   879  	if solicit {
   880  		// This is an outbound gateway connection
   881  		c.gw.outsim = &sync.Map{}
   882  	} else {
   883  		// Inbound gateway connection
   884  		c.gw.insim = make(map[string]*insie)
   885  	}
   886  
   887  	// Register in temp map for now until gateway properly registered
   888  	// in out or in gateways.
   889  	if !s.addToTempClients(c.cid, c) {
   890  		c.mu.Unlock()
   891  		c.closeConnection(ServerShutdown)
   892  		return
   893  	}
   894  
   895  	// Only send if we accept a connection. Will send CONNECT+INFO as an
   896  	// outbound only after processing peer's INFO protocol.
   897  	if !solicit {
   898  		c.enqueueProto(infoJSON)
   899  	}
   900  
   901  	// Spin up the read loop.
   902  	s.startGoRoutine(func() { c.readLoop(nil) })
   903  
   904  	// Spin up the write loop.
   905  	s.startGoRoutine(func() { c.writeLoop() })
   906  
   907  	if tlsRequired {
   908  		c.Debugf("TLS handshake complete")
   909  		cs := c.nc.(*tls.Conn).ConnectionState()
   910  		c.Debugf("TLS version %s, cipher suite %s", tlsVersion(cs.Version), tlsCipher(cs.CipherSuite))
   911  	}
   912  
   913  	c.mu.Unlock()
   914  
   915  	// Announce ourselves again to new connections.
   916  	if solicit && s.EventsEnabled() {
   917  		s.sendStatszUpdate()
   918  	}
   919  }
   920  
   921  // Builds and sends the CONNECT protocol for a gateway.
   922  // Client lock held on entry.
   923  func (c *client) sendGatewayConnect(opts *Options) {
   924  	// FIXME: This can race with updateRemotesTLSConfig
   925  	tlsRequired := c.gw.cfg.TLSConfig != nil
   926  	url := c.gw.connectURL
   927  	c.gw.connectURL = nil
   928  	var user, pass string
   929  	if userInfo := url.User; userInfo != nil {
   930  		user = userInfo.Username()
   931  		pass, _ = userInfo.Password()
   932  	} else if opts != nil {
   933  		user = opts.Gateway.Username
   934  		pass = opts.Gateway.Password
   935  	}
   936  	cinfo := connectInfo{
   937  		Verbose:  false,
   938  		Pedantic: false,
   939  		User:     user,
   940  		Pass:     pass,
   941  		TLS:      tlsRequired,
   942  		Name:     c.srv.info.ID,
   943  		Gateway:  c.srv.gateway.name,
   944  	}
   945  	b, err := json.Marshal(cinfo)
   946  	if err != nil {
   947  		panic(err)
   948  	}
   949  	c.enqueueProto([]byte(fmt.Sprintf(ConProto, b)))
   950  }
   951  
   952  // Process the CONNECT protocol from a gateway connection.
   953  // Returns an error to the connection if the CONNECT is not from a gateway
   954  // (for instance a client or route connecting to the gateway port), or
   955  // if the destination does not match the gateway name of this server.
   956  //
   957  // <Invoked from inbound connection's readLoop>
   958  func (c *client) processGatewayConnect(arg []byte) error {
   959  	connect := &connectInfo{}
   960  	if err := json.Unmarshal(arg, connect); err != nil {
   961  		return err
   962  	}
   963  
   964  	// Coming from a client or a route, reject
   965  	if connect.Gateway == "" {
   966  		c.sendErrAndErr(ErrClientOrRouteConnectedToGatewayPort.Error())
   967  		c.closeConnection(WrongPort)
   968  		return ErrClientOrRouteConnectedToGatewayPort
   969  	}
   970  
   971  	c.mu.Lock()
   972  	s := c.srv
   973  	c.mu.Unlock()
   974  
   975  	// If we reject unknown gateways, make sure we have it configured,
   976  	// otherwise return an error.
   977  	if s.gateway.rejectUnknown() && s.getRemoteGateway(connect.Gateway) == nil {
   978  		c.Errorf("Rejecting connection from gateway %q", connect.Gateway)
   979  		c.sendErr(fmt.Sprintf("Connection to gateway %q rejected", s.getGatewayName()))
   980  		c.closeConnection(WrongGateway)
   981  		return ErrWrongGateway
   982  	}
   983  
   984  	c.mu.Lock()
   985  	c.gw.connected = true
   986  	// Set the Ping timer after sending connect and info.
   987  	c.setFirstPingTimer()
   988  	c.mu.Unlock()
   989  
   990  	return nil
   991  }
   992  
   993  // Process the INFO protocol from a gateway connection.
   994  //
   995  // If the gateway connection is an outbound (this server initiated the connection),
   996  // this function checks that the incoming INFO contains the Gateway field. If empty,
   997  // it means that this is a response from an older server or that this server connected
   998  // to the wrong port.
   999  // The outbound gateway may also receive a gossip INFO protocol from the remote gateway,
  1000  // indicating other gateways that the remote knows about. This server will try to connect
  1001  // to those gateways (if not explicitly configured or already implicitly connected).
  1002  // In both cases (explicit or implicit), the local cluster is notified about the existence
  1003  // of this new gateway. This allows servers in the cluster to ensure that they have an
  1004  // outbound connection to this gateway.
  1005  //
  1006  // For an inbound gateway, the gateway is simply registered and the info protocol
  1007  // is saved to be used after processing the CONNECT.
  1008  //
  1009  // <Invoked from both inbound/outbound readLoop's connection>
  1010  func (c *client) processGatewayInfo(info *Info) {
  1011  	var (
  1012  		gwName string
  1013  		cfg    *gatewayCfg
  1014  	)
  1015  	c.mu.Lock()
  1016  	s := c.srv
  1017  	cid := c.cid
  1018  
  1019  	// Check if this is the first INFO. (this call sets the flag if not already set).
  1020  	isFirstINFO := c.flags.setIfNotSet(infoReceived)
  1021  
  1022  	isOutbound := c.gw.outbound
  1023  	if isOutbound {
  1024  		gwName = c.gw.name
  1025  		cfg = c.gw.cfg
  1026  	} else if isFirstINFO {
  1027  		c.gw.name = info.Gateway
  1028  	}
  1029  	if isFirstINFO {
  1030  		c.opts.Name = info.ID
  1031  		// Get the protocol version from the INFO protocol. This will be checked
  1032  		// to see if this connection supports message tracing for instance.
  1033  		c.opts.Protocol = info.Proto
  1034  		c.gw.remoteName = info.Name
  1035  	}
  1036  	c.mu.Unlock()
  1037  
  1038  	// For an outbound connection...
  1039  	if isOutbound {
  1040  		// Check content of INFO for fields indicating that it comes from a gateway.
  1041  		// If we incorrectly connect to the wrong port (client or route), we won't
  1042  		// have the Gateway field set.
  1043  		if info.Gateway == "" {
  1044  			c.sendErrAndErr(fmt.Sprintf("Attempt to connect to gateway %q using wrong port", gwName))
  1045  			c.closeConnection(WrongPort)
  1046  			return
  1047  		}
  1048  		// Check that the gateway name we got is what we expect
  1049  		if info.Gateway != gwName {
  1050  			// Unless this is the very first INFO, it may be ok if this is
  1051  			// a gossip request to connect to other gateways.
  1052  			if !isFirstINFO && info.GatewayCmd == gatewayCmdGossip {
  1053  				// If we are configured to reject unknown, do not attempt to
  1054  				// connect to one that we don't have configured.
  1055  				if s.gateway.rejectUnknown() && s.getRemoteGateway(info.Gateway) == nil {
  1056  					return
  1057  				}
  1058  				s.processImplicitGateway(info)
  1059  				return
  1060  			}
  1061  			// Otherwise, this is a failure...
  1062  			// We are reporting this error in the log...
  1063  			c.Errorf("Failing connection to gateway %q, remote gateway name is %q",
  1064  				gwName, info.Gateway)
  1065  			// ...and sending this back to the remote so that the error
  1066  			// makes more sense in the remote server's log.
  1067  			c.sendErr(fmt.Sprintf("Connection from %q rejected, wanted to connect to %q, this is %q",
  1068  				s.getGatewayName(), gwName, info.Gateway))
  1069  			c.closeConnection(WrongGateway)
  1070  			return
  1071  		}
  1072  
  1073  		// Check for duplicate server name with servers in our cluster
  1074  		if s.isDuplicateServerName(info.Name) {
  1075  			c.Errorf("Remote server has a duplicate name: %q", info.Name)
  1076  			c.closeConnection(DuplicateServerName)
  1077  			return
  1078  		}
  1079  
  1080  		// Possibly add URLs that we get from the INFO protocol.
  1081  		if len(info.GatewayURLs) > 0 {
  1082  			cfg.updateURLs(info.GatewayURLs)
  1083  		}
  1084  
  1085  		// If this is the first INFO, send our connect
  1086  		if isFirstINFO {
  1087  			s.gateway.RLock()
  1088  			infoJSON := s.gateway.infoJSON
  1089  			s.gateway.RUnlock()
  1090  
  1091  			supportsHeaders := s.supportsHeaders()
  1092  			opts := s.getOpts()
  1093  
  1094  			// Note, if we want to support NKeys, then we would get the nonce
  1095  			// from this INFO protocol and can sign it in the CONNECT we are
  1096  			// going to send now.
  1097  			c.mu.Lock()
  1098  			c.gw.interestOnlyMode = info.GatewayIOM
  1099  			c.sendGatewayConnect(opts)
  1100  			c.Debugf("Gateway connect protocol sent to %q", gwName)
  1101  			// Send INFO too
  1102  			c.enqueueProto(infoJSON)
  1103  			c.gw.useOldPrefix = !info.GatewayNRP
  1104  			c.headers = supportsHeaders && info.Headers
  1105  			c.mu.Unlock()
  1106  
  1107  			// Register as an outbound gateway.. if we had a protocol to ack our connect,
  1108  			// then we should do that when process that ack.
  1109  			if s.registerOutboundGatewayConnection(gwName, c) {
  1110  				c.Noticef("Outbound gateway connection to %q (%s) registered", gwName, info.ID)
  1111  				// Now that the outbound gateway is registered, we can remove from temp map.
  1112  				s.removeFromTempClients(cid)
  1113  				// Set the Ping timer after sending connect and info.
  1114  				c.mu.Lock()
  1115  				c.setFirstPingTimer()
  1116  				c.mu.Unlock()
  1117  			} else {
  1118  				// There was a bug that would cause a connection to possibly
  1119  				// be called twice resulting in reconnection of twice the
  1120  				// same outbound connection. The issue is fixed, but adding
  1121  				// defensive code above that if we did not register this connection
  1122  				// because we already have an outbound for this name, then
  1123  				// close this connection (and make sure it does not try to reconnect)
  1124  				c.mu.Lock()
  1125  				c.flags.set(noReconnect)
  1126  				c.mu.Unlock()
  1127  				c.closeConnection(WrongGateway)
  1128  				return
  1129  			}
  1130  		} else if info.GatewayCmd > 0 {
  1131  			switch info.GatewayCmd {
  1132  			case gatewayCmdAllSubsStart:
  1133  				c.gatewayAllSubsReceiveStart(info)
  1134  				return
  1135  			case gatewayCmdAllSubsComplete:
  1136  				c.gatewayAllSubsReceiveComplete(info)
  1137  				return
  1138  			default:
  1139  				s.Warnf("Received unknown command %v from gateway %q", info.GatewayCmd, gwName)
  1140  				return
  1141  			}
  1142  		}
  1143  
  1144  		// Flood local cluster with information about this gateway.
  1145  		// Servers in this cluster will ensure that they have (or otherwise create)
  1146  		// an outbound connection to this gateway.
  1147  		s.forwardNewGatewayToLocalCluster(info)
  1148  
  1149  	} else if isFirstINFO {
  1150  		// This is the first INFO of an inbound connection...
  1151  
  1152  		// Check for duplicate server name with servers in our cluster
  1153  		if s.isDuplicateServerName(info.Name) {
  1154  			c.Errorf("Remote server has a duplicate name: %q", info.Name)
  1155  			c.closeConnection(DuplicateServerName)
  1156  			return
  1157  		}
  1158  
  1159  		s.registerInboundGatewayConnection(cid, c)
  1160  		c.Noticef("Inbound gateway connection from %q (%s) registered", info.Gateway, info.ID)
  1161  
  1162  		// Now that it is registered, we can remove from temp map.
  1163  		s.removeFromTempClients(cid)
  1164  
  1165  		// Send our QSubs.
  1166  		s.sendQueueSubsToGateway(c)
  1167  
  1168  		// Initiate outbound connection. This function will behave correctly if
  1169  		// we have already one.
  1170  		s.processImplicitGateway(info)
  1171  
  1172  		// Send back to the server that initiated this gateway connection the
  1173  		// list of all remote gateways known on this server.
  1174  		s.gossipGatewaysToInboundGateway(info.Gateway, c)
  1175  
  1176  		// Now make sure if we have any knowledge of connected leafnodes that we resend the
  1177  		// connect events to switch those accounts into interest only mode.
  1178  		s.mu.Lock()
  1179  		s.ensureGWsInterestOnlyForLeafNodes()
  1180  		s.mu.Unlock()
  1181  		js := s.js.Load()
  1182  
  1183  		// If running in some tests, maintain the original behavior.
  1184  		if gwDoNotForceInterestOnlyMode && js != nil {
  1185  			// Switch JetStream accounts to interest-only mode.
  1186  			var accounts []string
  1187  			js.mu.Lock()
  1188  			if len(js.accounts) > 0 {
  1189  				accounts = make([]string, 0, len(js.accounts))
  1190  				for accName := range js.accounts {
  1191  					accounts = append(accounts, accName)
  1192  				}
  1193  			}
  1194  			js.mu.Unlock()
  1195  			for _, accName := range accounts {
  1196  				if acc, err := s.LookupAccount(accName); err == nil && acc != nil {
  1197  					if acc.JetStreamEnabled() {
  1198  						s.switchAccountToInterestMode(acc.GetName())
  1199  					}
  1200  				}
  1201  			}
  1202  		} else if !gwDoNotForceInterestOnlyMode {
  1203  			// Starting 2.9.0, we are phasing out the optimistic mode, so change
  1204  			// all accounts to interest-only mode, unless instructed not to do so
  1205  			// in some tests.
  1206  			s.accounts.Range(func(_, v any) bool {
  1207  				acc := v.(*Account)
  1208  				s.switchAccountToInterestMode(acc.GetName())
  1209  				return true
  1210  			})
  1211  		}
  1212  	}
  1213  }
  1214  
  1215  // Sends to the given inbound gateway connection a gossip INFO protocol
  1216  // for each gateway known by this server. This allows for a "full mesh"
  1217  // of gateways.
  1218  func (s *Server) gossipGatewaysToInboundGateway(gwName string, c *client) {
  1219  	gw := s.gateway
  1220  	gw.RLock()
  1221  	defer gw.RUnlock()
  1222  	for gwCfgName, cfg := range gw.remotes {
  1223  		// Skip the gateway that we just created
  1224  		if gwCfgName == gwName {
  1225  			continue
  1226  		}
  1227  		info := Info{
  1228  			ID:         s.info.ID,
  1229  			GatewayCmd: gatewayCmdGossip,
  1230  		}
  1231  		urls := cfg.getURLsAsStrings()
  1232  		if len(urls) > 0 {
  1233  			info.Gateway = gwCfgName
  1234  			info.GatewayURLs = urls
  1235  			b, _ := json.Marshal(&info)
  1236  			c.mu.Lock()
  1237  			c.enqueueProto([]byte(fmt.Sprintf(InfoProto, b)))
  1238  			c.mu.Unlock()
  1239  		}
  1240  	}
  1241  }
  1242  
  1243  // Sends the INFO protocol of a gateway to all routes known by this server.
  1244  func (s *Server) forwardNewGatewayToLocalCluster(oinfo *Info) {
  1245  	// Need to protect s.routes here, so use server's lock
  1246  	s.mu.Lock()
  1247  	defer s.mu.Unlock()
  1248  
  1249  	// We don't really need the ID to be set, but, we need to make sure
  1250  	// that it is not set to the server ID so that if we were to connect
  1251  	// to an older server that does not expect a "gateway" INFO, it
  1252  	// would think that it needs to create an implicit route (since info.ID
  1253  	// would not match the route's remoteID), but will fail to do so because
  1254  	// the sent protocol will not have host/port defined.
  1255  	info := &Info{
  1256  		ID:          "GW" + s.info.ID,
  1257  		Name:        s.getOpts().ServerName,
  1258  		Gateway:     oinfo.Gateway,
  1259  		GatewayURLs: oinfo.GatewayURLs,
  1260  		GatewayCmd:  gatewayCmdGossip,
  1261  	}
  1262  	b, _ := json.Marshal(info)
  1263  	infoJSON := []byte(fmt.Sprintf(InfoProto, b))
  1264  
  1265  	s.forEachRemote(func(r *client) {
  1266  		r.mu.Lock()
  1267  		r.enqueueProto(infoJSON)
  1268  		r.mu.Unlock()
  1269  	})
  1270  }
  1271  
  1272  // Sends queue subscriptions interest to remote gateway.
  1273  // This is sent from the inbound side, that is, the side that receives
  1274  // messages from the remote's outbound connection. This side is
  1275  // the one sending the subscription interest.
  1276  func (s *Server) sendQueueSubsToGateway(c *client) {
  1277  	s.sendSubsToGateway(c, _EMPTY_)
  1278  }
  1279  
  1280  // Sends all subscriptions for the given account to the remove gateway
  1281  // This is sent from the inbound side, that is, the side that receives
  1282  // messages from the remote's outbound connection. This side is
  1283  // the one sending the subscription interest.
  1284  func (s *Server) sendAccountSubsToGateway(c *client, accName string) {
  1285  	s.sendSubsToGateway(c, accName)
  1286  }
  1287  
  1288  func gwBuildSubProto(buf *bytes.Buffer, accName string, acc map[string]*sitally, doQueues bool) {
  1289  	for saq, si := range acc {
  1290  		if doQueues && si.q || !doQueues && !si.q {
  1291  			buf.Write(rSubBytes)
  1292  			buf.WriteString(accName)
  1293  			buf.WriteByte(' ')
  1294  			// For queue subs (si.q is true), saq will be
  1295  			// subject + ' ' + queue, for plain subs, this is
  1296  			// just the subject.
  1297  			buf.WriteString(saq)
  1298  			if doQueues {
  1299  				buf.WriteString(" 1")
  1300  			}
  1301  			buf.WriteString(CR_LF)
  1302  		}
  1303  	}
  1304  }
  1305  
  1306  // Sends subscriptions to remote gateway.
  1307  func (s *Server) sendSubsToGateway(c *client, accountName string) {
  1308  	var (
  1309  		bufa = [32 * 1024]byte{}
  1310  		bbuf = bytes.NewBuffer(bufa[:0])
  1311  	)
  1312  
  1313  	gw := s.gateway
  1314  
  1315  	// This needs to run under this lock for the whole duration
  1316  	gw.pasi.Lock()
  1317  	defer gw.pasi.Unlock()
  1318  
  1319  	// If account is specified...
  1320  	if accountName != _EMPTY_ {
  1321  		// Simply send all plain subs (no queues) for this specific account
  1322  		gwBuildSubProto(bbuf, accountName, gw.pasi.m[accountName], false)
  1323  		// Instruct to send all subs (RS+/-) for this account from now on.
  1324  		c.mu.Lock()
  1325  		e := c.gw.insim[accountName]
  1326  		if e == nil {
  1327  			e = &insie{}
  1328  			c.gw.insim[accountName] = e
  1329  		}
  1330  		e.mode = InterestOnly
  1331  		c.mu.Unlock()
  1332  	} else {
  1333  		// Send queues for all accounts
  1334  		for accName, acc := range gw.pasi.m {
  1335  			gwBuildSubProto(bbuf, accName, acc, true)
  1336  		}
  1337  	}
  1338  
  1339  	buf := bbuf.Bytes()
  1340  
  1341  	// Nothing to send.
  1342  	if len(buf) == 0 {
  1343  		return
  1344  	}
  1345  	if len(buf) > cap(bufa) {
  1346  		s.Debugf("Sending subscriptions to %q, buffer size: %v", c.gw.name, len(buf))
  1347  	}
  1348  	// Send
  1349  	c.mu.Lock()
  1350  	c.enqueueProto(buf)
  1351  	c.Debugf("Sent queue subscriptions to gateway")
  1352  	c.mu.Unlock()
  1353  }
  1354  
  1355  // This is invoked when getting an INFO protocol for gateway on the ROUTER port.
  1356  // This function will then execute appropriate function based on the command
  1357  // contained in the protocol.
  1358  // <Invoked from a route connection's readLoop>
  1359  func (s *Server) processGatewayInfoFromRoute(info *Info, routeSrvID string) {
  1360  	switch info.GatewayCmd {
  1361  	case gatewayCmdGossip:
  1362  		s.processImplicitGateway(info)
  1363  	default:
  1364  		s.Errorf("Unknown command %d from server %v", info.GatewayCmd, routeSrvID)
  1365  	}
  1366  }
  1367  
  1368  // Sends INFO protocols to the given route connection for each known Gateway.
  1369  // These will be processed by the route and delegated to the gateway code to
  1370  // invoke processImplicitGateway.
  1371  func (s *Server) sendGatewayConfigsToRoute(route *client) {
  1372  	gw := s.gateway
  1373  	gw.RLock()
  1374  	// Send only to gateways for which we have actual outbound connection to.
  1375  	if len(gw.out) == 0 {
  1376  		gw.RUnlock()
  1377  		return
  1378  	}
  1379  	// Collect gateway configs for which we have an outbound connection.
  1380  	gwCfgsa := [16]*gatewayCfg{}
  1381  	gwCfgs := gwCfgsa[:0]
  1382  	for _, c := range gw.out {
  1383  		c.mu.Lock()
  1384  		if c.gw.cfg != nil {
  1385  			gwCfgs = append(gwCfgs, c.gw.cfg)
  1386  		}
  1387  		c.mu.Unlock()
  1388  	}
  1389  	gw.RUnlock()
  1390  	if len(gwCfgs) == 0 {
  1391  		return
  1392  	}
  1393  
  1394  	// Check forwardNewGatewayToLocalCluster() as to why we set ID this way.
  1395  	info := Info{
  1396  		ID:         "GW" + s.info.ID,
  1397  		GatewayCmd: gatewayCmdGossip,
  1398  	}
  1399  	for _, cfg := range gwCfgs {
  1400  		urls := cfg.getURLsAsStrings()
  1401  		if len(urls) > 0 {
  1402  			info.Gateway = cfg.Name
  1403  			info.GatewayURLs = urls
  1404  			b, _ := json.Marshal(&info)
  1405  			route.mu.Lock()
  1406  			route.enqueueProto([]byte(fmt.Sprintf(InfoProto, b)))
  1407  			route.mu.Unlock()
  1408  		}
  1409  	}
  1410  }
  1411  
  1412  // Initiates a gateway connection using the info contained in the INFO protocol.
  1413  // If a gateway with the same name is already registered (either because explicitly
  1414  // configured, or already implicitly connected), this function will augmment the
  1415  // remote URLs with URLs present in the info protocol and return.
  1416  // Otherwise, this function will register this remote (to prevent multiple connections
  1417  // to the same remote) and call solicitGateway (which will run in a different go-routine).
  1418  func (s *Server) processImplicitGateway(info *Info) {
  1419  	s.gateway.Lock()
  1420  	defer s.gateway.Unlock()
  1421  	// Name of the gateway to connect to is the Info.Gateway field.
  1422  	gwName := info.Gateway
  1423  	// If this is our name, bail.
  1424  	if gwName == s.gateway.name {
  1425  		return
  1426  	}
  1427  	// Check if we already have this config, and if so, we are done
  1428  	cfg := s.gateway.remotes[gwName]
  1429  	if cfg != nil {
  1430  		// However, possibly augment the list of URLs with the given
  1431  		// info.GatewayURLs content.
  1432  		cfg.Lock()
  1433  		cfg.addURLs(info.GatewayURLs)
  1434  		cfg.Unlock()
  1435  		return
  1436  	}
  1437  	opts := s.getOpts()
  1438  	cfg = &gatewayCfg{
  1439  		RemoteGatewayOpts: &RemoteGatewayOpts{Name: gwName},
  1440  		hash:              getGWHash(gwName),
  1441  		oldHash:           getOldHash(gwName),
  1442  		urls:              make(map[string]*url.URL, len(info.GatewayURLs)),
  1443  		implicit:          true,
  1444  	}
  1445  	if opts.Gateway.TLSConfig != nil {
  1446  		cfg.TLSConfig = opts.Gateway.TLSConfig.Clone()
  1447  		cfg.TLSTimeout = opts.Gateway.TLSTimeout
  1448  	}
  1449  
  1450  	// Since we know we don't have URLs (no config, so just based on what we
  1451  	// get from INFO), directly call addURLs(). We don't need locking since
  1452  	// we just created that structure and no one else has access to it yet.
  1453  	cfg.addURLs(info.GatewayURLs)
  1454  	// If there is no URL, we can't proceed.
  1455  	if len(cfg.urls) == 0 {
  1456  		return
  1457  	}
  1458  	s.gateway.remotes[gwName] = cfg
  1459  	s.startGoRoutine(func() {
  1460  		s.solicitGateway(cfg, true)
  1461  		s.grWG.Done()
  1462  	})
  1463  }
  1464  
  1465  // NumOutboundGateways is public here mostly for testing.
  1466  func (s *Server) NumOutboundGateways() int {
  1467  	return s.numOutboundGateways()
  1468  }
  1469  
  1470  // Returns the number of outbound gateway connections
  1471  func (s *Server) numOutboundGateways() int {
  1472  	s.gateway.RLock()
  1473  	n := len(s.gateway.out)
  1474  	s.gateway.RUnlock()
  1475  	return n
  1476  }
  1477  
  1478  // Returns the number of inbound gateway connections
  1479  func (s *Server) numInboundGateways() int {
  1480  	s.gateway.RLock()
  1481  	n := len(s.gateway.in)
  1482  	s.gateway.RUnlock()
  1483  	return n
  1484  }
  1485  
  1486  // Returns the remoteGateway (if any) that has the given `name`
  1487  func (s *Server) getRemoteGateway(name string) *gatewayCfg {
  1488  	s.gateway.RLock()
  1489  	cfg := s.gateway.remotes[name]
  1490  	s.gateway.RUnlock()
  1491  	return cfg
  1492  }
  1493  
  1494  // Used in tests
  1495  func (g *gatewayCfg) bumpConnAttempts() {
  1496  	g.Lock()
  1497  	g.connAttempts++
  1498  	g.Unlock()
  1499  }
  1500  
  1501  // Used in tests
  1502  func (g *gatewayCfg) getConnAttempts() int {
  1503  	g.Lock()
  1504  	ca := g.connAttempts
  1505  	g.Unlock()
  1506  	return ca
  1507  }
  1508  
  1509  // Used in tests
  1510  func (g *gatewayCfg) resetConnAttempts() {
  1511  	g.Lock()
  1512  	g.connAttempts = 0
  1513  	g.Unlock()
  1514  }
  1515  
  1516  // Returns if this remote gateway is implicit or not.
  1517  func (g *gatewayCfg) isImplicit() bool {
  1518  	g.RLock()
  1519  	ii := g.implicit
  1520  	g.RUnlock()
  1521  	return ii
  1522  }
  1523  
  1524  // getURLs returns an array of URLs in random order suitable for
  1525  // an iteration to try to connect.
  1526  func (g *gatewayCfg) getURLs() []*url.URL {
  1527  	g.RLock()
  1528  	a := make([]*url.URL, 0, len(g.urls))
  1529  	for _, u := range g.urls {
  1530  		a = append(a, u)
  1531  	}
  1532  	g.RUnlock()
  1533  	// Map iteration is random, but not that good with small maps.
  1534  	rand.Shuffle(len(a), func(i, j int) {
  1535  		a[i], a[j] = a[j], a[i]
  1536  	})
  1537  	return a
  1538  }
  1539  
  1540  // Similar to getURLs but returns the urls as an array of strings.
  1541  func (g *gatewayCfg) getURLsAsStrings() []string {
  1542  	g.RLock()
  1543  	a := make([]string, 0, len(g.urls))
  1544  	for _, u := range g.urls {
  1545  		a = append(a, u.Host)
  1546  	}
  1547  	g.RUnlock()
  1548  	return a
  1549  }
  1550  
  1551  // updateURLs creates the urls map with the content of the config's URLs array
  1552  // and the given array that we get from the INFO protocol.
  1553  func (g *gatewayCfg) updateURLs(infoURLs []string) {
  1554  	g.Lock()
  1555  	// Clear the map...
  1556  	g.urls = make(map[string]*url.URL, len(g.URLs)+len(infoURLs))
  1557  	// Add the urls from the config URLs array.
  1558  	for _, u := range g.URLs {
  1559  		g.urls[u.Host] = u
  1560  	}
  1561  	// Then add the ones from the infoURLs array we got.
  1562  	g.addURLs(infoURLs)
  1563  	// The call above will set varzUpdateURLs only when finding ULRs in infoURLs
  1564  	// that are not present in the config. That does not cover the case where
  1565  	// previously "discovered" URLs are now gone. We could check "before" size
  1566  	// of g.urls and if bigger than current size, set the boolean to true.
  1567  	// Not worth it... simply set this to true to allow a refresh of gateway
  1568  	// URLs in varz.
  1569  	g.varzUpdateURLs = true
  1570  	g.Unlock()
  1571  }
  1572  
  1573  // Saves the hostname of the given URL (if not already done).
  1574  // This may be used as the ServerName of the TLSConfig when initiating a
  1575  // TLS connection.
  1576  // Write lock held on entry.
  1577  func (g *gatewayCfg) saveTLSHostname(u *url.URL) {
  1578  	if g.TLSConfig != nil && g.tlsName == "" && net.ParseIP(u.Hostname()) == nil {
  1579  		g.tlsName = u.Hostname()
  1580  	}
  1581  }
  1582  
  1583  // add URLs from the given array to the urls map only if not already present.
  1584  // remoteGateway write lock is assumed to be held on entry.
  1585  // Write lock is held on entry.
  1586  func (g *gatewayCfg) addURLs(infoURLs []string) {
  1587  	var scheme string
  1588  	if g.TLSConfig != nil {
  1589  		scheme = "tls"
  1590  	} else {
  1591  		scheme = "nats"
  1592  	}
  1593  	for _, iu := range infoURLs {
  1594  		if _, present := g.urls[iu]; !present {
  1595  			// Urls in Info.GatewayURLs come without scheme. Add it to parse
  1596  			// the url (otherwise it fails).
  1597  			if u, err := url.Parse(fmt.Sprintf("%s://%s", scheme, iu)); err == nil {
  1598  				// Also, if a tlsName has not been set yet and we are dealing
  1599  				// with a hostname and not a bare IP, save the hostname.
  1600  				g.saveTLSHostname(u)
  1601  				// Use u.Host for the key.
  1602  				g.urls[u.Host] = u
  1603  				// Signal that we have updated the list. Used by monitoring code.
  1604  				g.varzUpdateURLs = true
  1605  			}
  1606  		}
  1607  	}
  1608  }
  1609  
  1610  // Adds this URL to the set of Gateway URLs.
  1611  // Returns true if the URL has been added, false otherwise.
  1612  // Server lock held on entry
  1613  func (s *Server) addGatewayURL(urlStr string) bool {
  1614  	s.gateway.Lock()
  1615  	added := s.gateway.URLs.addUrl(urlStr)
  1616  	if added {
  1617  		s.gateway.generateInfoJSON()
  1618  	}
  1619  	s.gateway.Unlock()
  1620  	return added
  1621  }
  1622  
  1623  // Removes this URL from the set of gateway URLs.
  1624  // Returns true if the URL has been removed, false otherwise.
  1625  // Server lock held on entry
  1626  func (s *Server) removeGatewayURL(urlStr string) bool {
  1627  	if s.isShuttingDown() {
  1628  		return false
  1629  	}
  1630  	s.gateway.Lock()
  1631  	removed := s.gateway.URLs.removeUrl(urlStr)
  1632  	if removed {
  1633  		s.gateway.generateInfoJSON()
  1634  	}
  1635  	s.gateway.Unlock()
  1636  	return removed
  1637  }
  1638  
  1639  // Sends a Gateway's INFO to all inbound GW connections.
  1640  // Server lock is held on entry
  1641  func (s *Server) sendAsyncGatewayInfo() {
  1642  	s.gateway.RLock()
  1643  	for _, ig := range s.gateway.in {
  1644  		ig.mu.Lock()
  1645  		ig.enqueueProto(s.gateway.infoJSON)
  1646  		ig.mu.Unlock()
  1647  	}
  1648  	s.gateway.RUnlock()
  1649  }
  1650  
  1651  // This returns the URL of the Gateway listen spec, or empty string
  1652  // if the server has no gateway configured.
  1653  func (s *Server) getGatewayURL() string {
  1654  	s.gateway.RLock()
  1655  	url := s.gateway.URL
  1656  	s.gateway.RUnlock()
  1657  	return url
  1658  }
  1659  
  1660  // Returns this server gateway name.
  1661  // Same than calling s.gateway.getName()
  1662  func (s *Server) getGatewayName() string {
  1663  	// This is immutable
  1664  	return s.gateway.name
  1665  }
  1666  
  1667  // All gateway connections (outbound and inbound) are put in the given map.
  1668  func (s *Server) getAllGatewayConnections(conns map[uint64]*client) {
  1669  	gw := s.gateway
  1670  	gw.RLock()
  1671  	for _, c := range gw.out {
  1672  		c.mu.Lock()
  1673  		cid := c.cid
  1674  		c.mu.Unlock()
  1675  		conns[cid] = c
  1676  	}
  1677  	for cid, c := range gw.in {
  1678  		conns[cid] = c
  1679  	}
  1680  	gw.RUnlock()
  1681  }
  1682  
  1683  // Register the given gateway connection (*client) in the inbound gateways
  1684  // map. The key is the connection ID (like for clients and routes).
  1685  func (s *Server) registerInboundGatewayConnection(cid uint64, gwc *client) {
  1686  	s.gateway.Lock()
  1687  	s.gateway.in[cid] = gwc
  1688  	s.gateway.Unlock()
  1689  }
  1690  
  1691  // Register the given gateway connection (*client) in the outbound gateways
  1692  // map with the given name as the key.
  1693  func (s *Server) registerOutboundGatewayConnection(name string, gwc *client) bool {
  1694  	s.gateway.Lock()
  1695  	if _, exist := s.gateway.out[name]; exist {
  1696  		s.gateway.Unlock()
  1697  		return false
  1698  	}
  1699  	s.gateway.out[name] = gwc
  1700  	s.gateway.outo = append(s.gateway.outo, gwc)
  1701  	s.gateway.orderOutboundConnectionsLocked()
  1702  	s.gateway.Unlock()
  1703  	return true
  1704  }
  1705  
  1706  // Returns the outbound gateway connection (*client) with the given name,
  1707  // or nil if not found
  1708  func (s *Server) getOutboundGatewayConnection(name string) *client {
  1709  	s.gateway.RLock()
  1710  	gwc := s.gateway.out[name]
  1711  	s.gateway.RUnlock()
  1712  	return gwc
  1713  }
  1714  
  1715  // Returns all outbound gateway connections in the provided array.
  1716  // The order of the gateways is suited for the sending of a message.
  1717  // Current ordering is based on individual gateway's RTT value.
  1718  func (s *Server) getOutboundGatewayConnections(a *[]*client) {
  1719  	s.gateway.RLock()
  1720  	for i := 0; i < len(s.gateway.outo); i++ {
  1721  		*a = append(*a, s.gateway.outo[i])
  1722  	}
  1723  	s.gateway.RUnlock()
  1724  }
  1725  
  1726  // Orders the array of outbound connections.
  1727  // Current ordering is by lowest RTT.
  1728  // Gateway write lock is held on entry
  1729  func (g *srvGateway) orderOutboundConnectionsLocked() {
  1730  	// Order the gateways by lowest RTT
  1731  	sort.Slice(g.outo, func(i, j int) bool {
  1732  		return g.outo[i].getRTTValue() < g.outo[j].getRTTValue()
  1733  	})
  1734  }
  1735  
  1736  // Orders the array of outbound connections.
  1737  // Current ordering is by lowest RTT.
  1738  func (g *srvGateway) orderOutboundConnections() {
  1739  	g.Lock()
  1740  	g.orderOutboundConnectionsLocked()
  1741  	g.Unlock()
  1742  }
  1743  
  1744  // Returns all inbound gateway connections in the provided array
  1745  func (s *Server) getInboundGatewayConnections(a *[]*client) {
  1746  	s.gateway.RLock()
  1747  	for _, gwc := range s.gateway.in {
  1748  		*a = append(*a, gwc)
  1749  	}
  1750  	s.gateway.RUnlock()
  1751  }
  1752  
  1753  // This is invoked when a gateway connection is closed and the server
  1754  // is removing this connection from its state.
  1755  func (s *Server) removeRemoteGatewayConnection(c *client) {
  1756  	c.mu.Lock()
  1757  	cid := c.cid
  1758  	isOutbound := c.gw.outbound
  1759  	gwName := c.gw.name
  1760  	if isOutbound && c.gw.outsim != nil {
  1761  		// We do this to allow the GC to release this connection.
  1762  		// Since the map is used by the rest of the code without client lock,
  1763  		// we can't simply set it to nil, instead, just make sure we empty it.
  1764  		c.gw.outsim.Range(func(k, _ any) bool {
  1765  			c.gw.outsim.Delete(k)
  1766  			return true
  1767  		})
  1768  	}
  1769  	c.mu.Unlock()
  1770  
  1771  	gw := s.gateway
  1772  	gw.Lock()
  1773  	if isOutbound {
  1774  		delete(gw.out, gwName)
  1775  		louto := len(gw.outo)
  1776  		reorder := false
  1777  		for i := 0; i < len(gw.outo); i++ {
  1778  			if gw.outo[i] == c {
  1779  				// If last, simply remove and no need to reorder
  1780  				if i != louto-1 {
  1781  					gw.outo[i] = gw.outo[louto-1]
  1782  					reorder = true
  1783  				}
  1784  				gw.outo = gw.outo[:louto-1]
  1785  			}
  1786  		}
  1787  		if reorder {
  1788  			gw.orderOutboundConnectionsLocked()
  1789  		}
  1790  	} else {
  1791  		delete(gw.in, cid)
  1792  	}
  1793  	gw.Unlock()
  1794  	s.removeFromTempClients(cid)
  1795  
  1796  	if isOutbound {
  1797  		// Update number of totalQSubs for this gateway
  1798  		qSubsRemoved := int64(0)
  1799  		c.mu.Lock()
  1800  		for _, sub := range c.subs {
  1801  			if sub.queue != nil {
  1802  				qSubsRemoved++
  1803  			}
  1804  		}
  1805  		c.subs = nil
  1806  		c.mu.Unlock()
  1807  		// Update total count of qsubs in remote gateways.
  1808  		atomic.AddInt64(&c.srv.gateway.totalQSubs, -qSubsRemoved)
  1809  
  1810  	} else {
  1811  		var subsa [1024]*subscription
  1812  		var subs = subsa[:0]
  1813  
  1814  		// For inbound GW connection, if we have subs, those are
  1815  		// local subs on "_R_." subjects.
  1816  		c.mu.Lock()
  1817  		for _, sub := range c.subs {
  1818  			subs = append(subs, sub)
  1819  		}
  1820  		c.subs = nil
  1821  		c.mu.Unlock()
  1822  		for _, sub := range subs {
  1823  			c.removeReplySub(sub)
  1824  		}
  1825  	}
  1826  }
  1827  
  1828  // GatewayAddr returns the net.Addr object for the gateway listener.
  1829  func (s *Server) GatewayAddr() *net.TCPAddr {
  1830  	s.mu.Lock()
  1831  	defer s.mu.Unlock()
  1832  	if s.gatewayListener == nil {
  1833  		return nil
  1834  	}
  1835  	return s.gatewayListener.Addr().(*net.TCPAddr)
  1836  }
  1837  
  1838  // A- protocol received from the remote after sending messages
  1839  // on an account that it has no interest in. Mark this account
  1840  // with a "no interest" marker to prevent further messages send.
  1841  // <Invoked from outbound connection's readLoop>
  1842  func (c *client) processGatewayAccountUnsub(accName string) {
  1843  	// Just to indicate activity around "subscriptions" events.
  1844  	c.in.subs++
  1845  	// This account may have an entry because of queue subs.
  1846  	// If that's the case, we can reset the no-interest map,
  1847  	// but not set the entry to nil.
  1848  	setToNil := true
  1849  	if ei, ok := c.gw.outsim.Load(accName); ei != nil {
  1850  		e := ei.(*outsie)
  1851  		e.Lock()
  1852  		// Reset the no-interest map if we have queue subs
  1853  		// and don't set the entry to nil.
  1854  		if e.qsubs > 0 {
  1855  			e.ni = make(map[string]struct{})
  1856  			setToNil = false
  1857  		}
  1858  		e.Unlock()
  1859  	} else if ok {
  1860  		// Already set to nil, so skip
  1861  		setToNil = false
  1862  	}
  1863  	if setToNil {
  1864  		c.gw.outsim.Store(accName, nil)
  1865  	}
  1866  }
  1867  
  1868  // A+ protocol received from remote gateway if it had previously
  1869  // sent an A-. Clear the "no interest" marker for this account.
  1870  // <Invoked from outbound connection's readLoop>
  1871  func (c *client) processGatewayAccountSub(accName string) error {
  1872  	// Just to indicate activity around "subscriptions" events.
  1873  	c.in.subs++
  1874  	// If this account has an entry because of queue subs, we
  1875  	// can't delete the entry.
  1876  	remove := true
  1877  	if ei, ok := c.gw.outsim.Load(accName); ei != nil {
  1878  		e := ei.(*outsie)
  1879  		e.Lock()
  1880  		if e.qsubs > 0 {
  1881  			remove = false
  1882  		}
  1883  		e.Unlock()
  1884  	} else if !ok {
  1885  		// There is no entry, so skip
  1886  		remove = false
  1887  	}
  1888  	if remove {
  1889  		c.gw.outsim.Delete(accName)
  1890  	}
  1891  	return nil
  1892  }
  1893  
  1894  // RS- protocol received from the remote after sending messages
  1895  // on a subject that it has no interest in (but knows about the
  1896  // account). Mark this subject with a "no interest" marker to
  1897  // prevent further messages being sent.
  1898  // If in modeInterestOnly or for a queue sub, remove from
  1899  // the sublist if present.
  1900  // <Invoked from outbound connection's readLoop>
  1901  func (c *client) processGatewayRUnsub(arg []byte) error {
  1902  	accName, subject, queue, err := c.parseUnsubProto(arg)
  1903  	if err != nil {
  1904  		return fmt.Errorf("processGatewaySubjectUnsub %s", err.Error())
  1905  	}
  1906  
  1907  	var (
  1908  		e          *outsie
  1909  		useSl      bool
  1910  		newe       bool
  1911  		callUpdate bool
  1912  		srv        *Server
  1913  		sub        *subscription
  1914  	)
  1915  
  1916  	// Possibly execute this on exit after all locks have been released.
  1917  	// If callUpdate is true, srv and sub will be not nil.
  1918  	defer func() {
  1919  		if callUpdate {
  1920  			srv.updateInterestForAccountOnGateway(accName, sub, -1)
  1921  		}
  1922  	}()
  1923  
  1924  	c.mu.Lock()
  1925  	if c.gw.outsim == nil {
  1926  		c.Errorf("Received RS- from gateway on inbound connection")
  1927  		c.mu.Unlock()
  1928  		c.closeConnection(ProtocolViolation)
  1929  		return nil
  1930  	}
  1931  	defer c.mu.Unlock()
  1932  	// If closed, c.subs map will be nil, so bail out.
  1933  	if c.isClosed() {
  1934  		return nil
  1935  	}
  1936  
  1937  	ei, _ := c.gw.outsim.Load(accName)
  1938  	if ei != nil {
  1939  		e = ei.(*outsie)
  1940  		e.Lock()
  1941  		defer e.Unlock()
  1942  		// If there is an entry, for plain sub we need
  1943  		// to know if we should store the sub
  1944  		useSl = queue != nil || e.mode != Optimistic
  1945  	} else if queue != nil {
  1946  		// should not even happen...
  1947  		c.Debugf("Received RS- without prior RS+ for subject %q, queue %q", subject, queue)
  1948  		return nil
  1949  	} else {
  1950  		// Plain sub, assume optimistic sends, create entry.
  1951  		e = &outsie{ni: make(map[string]struct{}), sl: NewSublistWithCache()}
  1952  		newe = true
  1953  	}
  1954  	// This is when a sub or queue sub is supposed to be in
  1955  	// the sublist. Look for it and remove.
  1956  	if useSl {
  1957  		var ok bool
  1958  		key := arg
  1959  		// m[string()] does not cause mem allocation
  1960  		sub, ok = c.subs[string(key)]
  1961  		// if RS- for a sub that we don't have, just ignore.
  1962  		if !ok {
  1963  			return nil
  1964  		}
  1965  		if e.sl.Remove(sub) == nil {
  1966  			delete(c.subs, bytesToString(key))
  1967  			if queue != nil {
  1968  				e.qsubs--
  1969  				atomic.AddInt64(&c.srv.gateway.totalQSubs, -1)
  1970  			}
  1971  			// If last, we can remove the whole entry only
  1972  			// when in optimistic mode and there is no element
  1973  			// in the `ni` map.
  1974  			if e.sl.Count() == 0 && e.mode == Optimistic && len(e.ni) == 0 {
  1975  				c.gw.outsim.Delete(accName)
  1976  			}
  1977  		}
  1978  		// We are going to call updateInterestForAccountOnGateway on exit.
  1979  		srv = c.srv
  1980  		callUpdate = true
  1981  	} else {
  1982  		e.ni[string(subject)] = struct{}{}
  1983  		if newe {
  1984  			c.gw.outsim.Store(accName, e)
  1985  		}
  1986  	}
  1987  	return nil
  1988  }
  1989  
  1990  // For plain subs, RS+ protocol received from remote gateway if it
  1991  // had previously sent a RS-. Clear the "no interest" marker for
  1992  // this subject (under this account).
  1993  // For queue subs, or if in modeInterestOnly, register interest
  1994  // from remote gateway.
  1995  // <Invoked from outbound connection's readLoop>
  1996  func (c *client) processGatewayRSub(arg []byte) error {
  1997  	// Indicate activity.
  1998  	c.in.subs++
  1999  
  2000  	var (
  2001  		queue []byte
  2002  		qw    int32
  2003  	)
  2004  
  2005  	args := splitArg(arg)
  2006  	switch len(args) {
  2007  	case 2:
  2008  	case 4:
  2009  		queue = args[2]
  2010  		qw = int32(parseSize(args[3]))
  2011  	default:
  2012  		return fmt.Errorf("processGatewaySubjectSub Parse Error: '%s'", arg)
  2013  	}
  2014  	accName := args[0]
  2015  	subject := args[1]
  2016  
  2017  	var (
  2018  		e          *outsie
  2019  		useSl      bool
  2020  		newe       bool
  2021  		callUpdate bool
  2022  		srv        *Server
  2023  		sub        *subscription
  2024  	)
  2025  
  2026  	// Possibly execute this on exit after all locks have been released.
  2027  	// If callUpdate is true, srv and sub will be not nil.
  2028  	defer func() {
  2029  		if callUpdate {
  2030  			srv.updateInterestForAccountOnGateway(string(accName), sub, 1)
  2031  		}
  2032  	}()
  2033  
  2034  	c.mu.Lock()
  2035  	if c.gw.outsim == nil {
  2036  		c.Errorf("Received RS+ from gateway on inbound connection")
  2037  		c.mu.Unlock()
  2038  		c.closeConnection(ProtocolViolation)
  2039  		return nil
  2040  	}
  2041  	defer c.mu.Unlock()
  2042  	// If closed, c.subs map will be nil, so bail out.
  2043  	if c.isClosed() {
  2044  		return nil
  2045  	}
  2046  
  2047  	ei, _ := c.gw.outsim.Load(bytesToString(accName))
  2048  	// We should always have an existing entry for plain subs because
  2049  	// in optimistic mode we would have received RS- first, and
  2050  	// in full knowledge, we are receiving RS+ for an account after
  2051  	// getting many RS- from the remote..
  2052  	if ei != nil {
  2053  		e = ei.(*outsie)
  2054  		e.Lock()
  2055  		defer e.Unlock()
  2056  		useSl = queue != nil || e.mode != Optimistic
  2057  	} else if queue == nil {
  2058  		return nil
  2059  	} else {
  2060  		e = &outsie{ni: make(map[string]struct{}), sl: NewSublistWithCache()}
  2061  		newe = true
  2062  		useSl = true
  2063  	}
  2064  	if useSl {
  2065  		var key []byte
  2066  		// We store remote subs by account/subject[/queue].
  2067  		// For queue, remove the trailing weight
  2068  		if queue != nil {
  2069  			key = arg[:len(arg)-len(args[3])-1]
  2070  		} else {
  2071  			key = arg
  2072  		}
  2073  		// If RS+ for a sub that we already have, ignore.
  2074  		// (m[string()] does not allocate memory)
  2075  		if _, ok := c.subs[string(key)]; ok {
  2076  			return nil
  2077  		}
  2078  		// new subscription. copy subject (and queue) to
  2079  		// not reference the underlying possibly big buffer.
  2080  		var csubject []byte
  2081  		var cqueue []byte
  2082  		if queue != nil {
  2083  			// make single allocation and use different slices
  2084  			// to point to subject and queue name.
  2085  			cbuf := make([]byte, len(subject)+1+len(queue))
  2086  			copy(cbuf, key[len(accName)+1:])
  2087  			csubject = cbuf[:len(subject)]
  2088  			cqueue = cbuf[len(subject)+1:]
  2089  		} else {
  2090  			csubject = make([]byte, len(subject))
  2091  			copy(csubject, subject)
  2092  		}
  2093  		sub = &subscription{client: c, subject: csubject, queue: cqueue, qw: qw}
  2094  		// If no error inserting in sublist...
  2095  		if e.sl.Insert(sub) == nil {
  2096  			c.subs[string(key)] = sub
  2097  			if queue != nil {
  2098  				e.qsubs++
  2099  				atomic.AddInt64(&c.srv.gateway.totalQSubs, 1)
  2100  			}
  2101  			if newe {
  2102  				c.gw.outsim.Store(string(accName), e)
  2103  			}
  2104  		}
  2105  		// We are going to call updateInterestForAccountOnGateway on exit.
  2106  		srv = c.srv
  2107  		callUpdate = true
  2108  	} else {
  2109  		subj := bytesToString(subject)
  2110  		// If this is an RS+ for a wc subject, then
  2111  		// remove from the no interest map all subjects
  2112  		// that are a subset of this wc subject.
  2113  		if subjectHasWildcard(subj) {
  2114  			for k := range e.ni {
  2115  				if subjectIsSubsetMatch(k, subj) {
  2116  					delete(e.ni, k)
  2117  				}
  2118  			}
  2119  		} else {
  2120  			delete(e.ni, subj)
  2121  		}
  2122  	}
  2123  	return nil
  2124  }
  2125  
  2126  // Returns true if this gateway has possible interest in the
  2127  // given account/subject (which means, it does not have a registered
  2128  // no-interest on the account and/or subject) and the sublist result
  2129  // for queue subscriptions.
  2130  // <Outbound connection: invoked when client message is published,
  2131  // so from any client connection's readLoop>
  2132  func (c *client) gatewayInterest(acc, subj string) (bool, *SublistResult) {
  2133  	ei, accountInMap := c.gw.outsim.Load(acc)
  2134  	// If there is an entry for this account and ei is nil,
  2135  	// it means that the remote is not interested at all in
  2136  	// this account and we could not possibly have queue subs.
  2137  	if accountInMap && ei == nil {
  2138  		return false, nil
  2139  	}
  2140  	// Assume interest if account not in map, unless we support
  2141  	// only interest-only mode.
  2142  	psi := !accountInMap && !c.gw.interestOnlyMode
  2143  	var r *SublistResult
  2144  	if accountInMap {
  2145  		// If in map, check for subs interest with sublist.
  2146  		e := ei.(*outsie)
  2147  		e.RLock()
  2148  		// Unless each side has agreed on interest-only mode,
  2149  		// we may be in transition to modeInterestOnly
  2150  		// but until e.ni is nil, use it to know if we
  2151  		// should suppress interest or not.
  2152  		if !c.gw.interestOnlyMode && e.ni != nil {
  2153  			if _, inMap := e.ni[subj]; !inMap {
  2154  				psi = true
  2155  			}
  2156  		}
  2157  		// If we are in modeInterestOnly (e.ni will be nil)
  2158  		// or if we have queue subs, we also need to check sl.Match.
  2159  		if e.ni == nil || e.qsubs > 0 {
  2160  			r = e.sl.Match(subj)
  2161  			if len(r.psubs) > 0 {
  2162  				psi = true
  2163  			}
  2164  		}
  2165  		e.RUnlock()
  2166  		// Since callers may just check if the sublist result is nil or not,
  2167  		// make sure that if what is returned by sl.Match() is the emptyResult, then
  2168  		// we return nil to the caller.
  2169  		if r == emptyResult {
  2170  			r = nil
  2171  		}
  2172  	}
  2173  	return psi, r
  2174  }
  2175  
  2176  // switchAccountToInterestMode will switch an account over to interestMode.
  2177  // Lock should NOT be held.
  2178  func (s *Server) switchAccountToInterestMode(accName string) {
  2179  	gwsa := [16]*client{}
  2180  	gws := gwsa[:0]
  2181  	s.getInboundGatewayConnections(&gws)
  2182  
  2183  	for _, gin := range gws {
  2184  		var e *insie
  2185  		var ok bool
  2186  
  2187  		gin.mu.Lock()
  2188  		if e, ok = gin.gw.insim[accName]; !ok || e == nil {
  2189  			e = &insie{}
  2190  			gin.gw.insim[accName] = e
  2191  		}
  2192  		// Do it only if we are in Optimistic mode
  2193  		if e.mode == Optimistic {
  2194  			gin.gatewaySwitchAccountToSendAllSubs(e, accName)
  2195  		}
  2196  		gin.mu.Unlock()
  2197  	}
  2198  }
  2199  
  2200  // This is invoked when registering (or unregistering) the first
  2201  // (or last) subscription on a given account/subject. For each
  2202  // GWs inbound connections, we will check if we need to send an RS+ or A+
  2203  // protocol.
  2204  func (s *Server) maybeSendSubOrUnsubToGateways(accName string, sub *subscription, added bool) {
  2205  	if sub.queue != nil {
  2206  		return
  2207  	}
  2208  	gwsa := [16]*client{}
  2209  	gws := gwsa[:0]
  2210  	s.getInboundGatewayConnections(&gws)
  2211  	if len(gws) == 0 {
  2212  		return
  2213  	}
  2214  	var (
  2215  		rsProtoa  [512]byte
  2216  		rsProto   []byte
  2217  		accProtoa [256]byte
  2218  		accProto  []byte
  2219  		proto     []byte
  2220  		subject   = bytesToString(sub.subject)
  2221  		hasWC     = subjectHasWildcard(subject)
  2222  	)
  2223  	for _, c := range gws {
  2224  		proto = nil
  2225  		c.mu.Lock()
  2226  		e, inMap := c.gw.insim[accName]
  2227  		// If there is a inbound subject interest entry...
  2228  		if e != nil {
  2229  			sendProto := false
  2230  			// In optimistic mode, we care only about possibly sending RS+ (or A+)
  2231  			// so if e.ni is not nil we do things only when adding a new subscription.
  2232  			if e.ni != nil && added {
  2233  				// For wildcard subjects, we will remove from our no-interest
  2234  				// map, all subjects that are a subset of this wc subject, but we
  2235  				// still send the wc subject and let the remote do its own cleanup.
  2236  				if hasWC {
  2237  					for enis := range e.ni {
  2238  						if subjectIsSubsetMatch(enis, subject) {
  2239  							delete(e.ni, enis)
  2240  							sendProto = true
  2241  						}
  2242  					}
  2243  				} else if _, noInterest := e.ni[subject]; noInterest {
  2244  					delete(e.ni, subject)
  2245  					sendProto = true
  2246  				}
  2247  			} else if e.mode == InterestOnly {
  2248  				// We are in the mode where we always send RS+/- protocols.
  2249  				sendProto = true
  2250  			}
  2251  			if sendProto {
  2252  				if rsProto == nil {
  2253  					// Construct the RS+/- only once
  2254  					proto = rsProtoa[:0]
  2255  					if added {
  2256  						proto = append(proto, rSubBytes...)
  2257  					} else {
  2258  						proto = append(proto, rUnsubBytes...)
  2259  					}
  2260  					proto = append(proto, accName...)
  2261  					proto = append(proto, ' ')
  2262  					proto = append(proto, sub.subject...)
  2263  					proto = append(proto, CR_LF...)
  2264  					rsProto = proto
  2265  				} else {
  2266  					// Point to the already constructed RS+/-
  2267  					proto = rsProto
  2268  				}
  2269  			}
  2270  		} else if added && inMap {
  2271  			// Here, we have a `nil` entry for this account in
  2272  			// the map, which means that we have previously sent
  2273  			// an A-. We have a new subscription, so we need to
  2274  			// send an A+ and delete the entry from the map so
  2275  			// that we do this only once.
  2276  			delete(c.gw.insim, accName)
  2277  			if accProto == nil {
  2278  				// Construct the A+ only once
  2279  				proto = accProtoa[:0]
  2280  				proto = append(proto, aSubBytes...)
  2281  				proto = append(proto, accName...)
  2282  				proto = append(proto, CR_LF...)
  2283  				accProto = proto
  2284  			} else {
  2285  				// Point to the already constructed A+
  2286  				proto = accProto
  2287  			}
  2288  		}
  2289  		if proto != nil {
  2290  			c.enqueueProto(proto)
  2291  			if c.trace {
  2292  				c.traceOutOp("", proto[:len(proto)-LEN_CR_LF])
  2293  			}
  2294  		}
  2295  		c.mu.Unlock()
  2296  	}
  2297  }
  2298  
  2299  // This is invoked when the first (or last) queue subscription on a
  2300  // given subject/group is registered (or unregistered). Sent to all
  2301  // inbound gateways.
  2302  func (s *Server) sendQueueSubOrUnsubToGateways(accName string, qsub *subscription, added bool) {
  2303  	if qsub.queue == nil {
  2304  		return
  2305  	}
  2306  
  2307  	gwsa := [16]*client{}
  2308  	gws := gwsa[:0]
  2309  	s.getInboundGatewayConnections(&gws)
  2310  	if len(gws) == 0 {
  2311  		return
  2312  	}
  2313  
  2314  	var protoa [512]byte
  2315  	var proto []byte
  2316  	for _, c := range gws {
  2317  		if proto == nil {
  2318  			proto = protoa[:0]
  2319  			if added {
  2320  				proto = append(proto, rSubBytes...)
  2321  			} else {
  2322  				proto = append(proto, rUnsubBytes...)
  2323  			}
  2324  			proto = append(proto, accName...)
  2325  			proto = append(proto, ' ')
  2326  			proto = append(proto, qsub.subject...)
  2327  			proto = append(proto, ' ')
  2328  			proto = append(proto, qsub.queue...)
  2329  			if added {
  2330  				// For now, just use 1 for the weight
  2331  				proto = append(proto, ' ', '1')
  2332  			}
  2333  			proto = append(proto, CR_LF...)
  2334  		}
  2335  		c.mu.Lock()
  2336  		// If we add a queue sub, and we had previously sent an A-,
  2337  		// we don't need to send an A+ here, but we need to clear
  2338  		// the fact that we did sent the A- so that we don't send
  2339  		// an A+ when we will get the first non-queue sub registered.
  2340  		if added {
  2341  			if ei, ok := c.gw.insim[accName]; ok && ei == nil {
  2342  				delete(c.gw.insim, accName)
  2343  			}
  2344  		}
  2345  		c.enqueueProto(proto)
  2346  		if c.trace {
  2347  			c.traceOutOp("", proto[:len(proto)-LEN_CR_LF])
  2348  		}
  2349  		c.mu.Unlock()
  2350  	}
  2351  }
  2352  
  2353  // This is invoked when a subscription (plain or queue) is
  2354  // added/removed locally or in our cluster. We use ref counting
  2355  // to know when to update the inbound gateways.
  2356  // <Invoked from client or route connection's readLoop or when such
  2357  // connection is closed>
  2358  func (s *Server) gatewayUpdateSubInterest(accName string, sub *subscription, change int32) {
  2359  	if sub.si {
  2360  		return
  2361  	}
  2362  
  2363  	var (
  2364  		keya  [1024]byte
  2365  		key   = keya[:0]
  2366  		entry *sitally
  2367  		isNew bool
  2368  	)
  2369  
  2370  	s.gateway.pasi.Lock()
  2371  	defer s.gateway.pasi.Unlock()
  2372  
  2373  	accMap := s.gateway.pasi.m
  2374  
  2375  	// First see if we have the account
  2376  	st := accMap[accName]
  2377  	if st == nil {
  2378  		// Ignore remove of something we don't have
  2379  		if change < 0 {
  2380  			return
  2381  		}
  2382  		st = make(map[string]*sitally)
  2383  		accMap[accName] = st
  2384  		isNew = true
  2385  	}
  2386  	// Lookup: build the key as subject[+' '+queue]
  2387  	key = append(key, sub.subject...)
  2388  	if sub.queue != nil {
  2389  		key = append(key, ' ')
  2390  		key = append(key, sub.queue...)
  2391  	}
  2392  	if !isNew {
  2393  		entry = st[string(key)]
  2394  	}
  2395  	first := false
  2396  	last := false
  2397  	if entry == nil {
  2398  		// Ignore remove of something we don't have
  2399  		if change < 0 {
  2400  			return
  2401  		}
  2402  		entry = &sitally{n: 1, q: sub.queue != nil}
  2403  		st[string(key)] = entry
  2404  		first = true
  2405  	} else {
  2406  		entry.n += change
  2407  		if entry.n <= 0 {
  2408  			delete(st, bytesToString(key))
  2409  			last = true
  2410  			if len(st) == 0 {
  2411  				delete(accMap, accName)
  2412  			}
  2413  		}
  2414  	}
  2415  	if sub.client != nil {
  2416  		rsubs := &s.gateway.rsubs
  2417  		acc := sub.client.acc
  2418  		sli, _ := rsubs.Load(acc)
  2419  		if change > 0 {
  2420  			var sl *Sublist
  2421  			if sli == nil {
  2422  				sl = NewSublistNoCache()
  2423  				rsubs.Store(acc, sl)
  2424  			} else {
  2425  				sl = sli.(*Sublist)
  2426  			}
  2427  			sl.Insert(sub)
  2428  			time.AfterFunc(s.gateway.recSubExp, func() {
  2429  				sl.Remove(sub)
  2430  			})
  2431  		} else if sli != nil {
  2432  			sl := sli.(*Sublist)
  2433  			sl.Remove(sub)
  2434  			if sl.Count() == 0 {
  2435  				rsubs.Delete(acc)
  2436  			}
  2437  		}
  2438  	}
  2439  	if first || last {
  2440  		if entry.q {
  2441  			s.sendQueueSubOrUnsubToGateways(accName, sub, first)
  2442  		} else {
  2443  			s.maybeSendSubOrUnsubToGateways(accName, sub, first)
  2444  		}
  2445  	}
  2446  }
  2447  
  2448  // Returns true if the given subject is a GW routed reply subject,
  2449  // that is, starts with $GNR and is long enough to contain cluster/server hash
  2450  // and subject.
  2451  func isGWRoutedReply(subj []byte) bool {
  2452  	return len(subj) > gwSubjectOffset && bytesToString(subj[:gwReplyPrefixLen]) == gwReplyPrefix
  2453  }
  2454  
  2455  // Same than isGWRoutedReply but accepts the old prefix $GR and returns
  2456  // a boolean indicating if this is the old prefix
  2457  func isGWRoutedSubjectAndIsOldPrefix(subj []byte) (bool, bool) {
  2458  	if isGWRoutedReply(subj) {
  2459  		return true, false
  2460  	}
  2461  	if len(subj) > oldGWReplyStart && bytesToString(subj[:oldGWReplyPrefixLen]) == oldGWReplyPrefix {
  2462  		return true, true
  2463  	}
  2464  	return false, false
  2465  }
  2466  
  2467  // Returns true if subject starts with "$GNR.". This is to check that
  2468  // clients can't publish on this subject.
  2469  func hasGWRoutedReplyPrefix(subj []byte) bool {
  2470  	return len(subj) > gwReplyPrefixLen && bytesToString(subj[:gwReplyPrefixLen]) == gwReplyPrefix
  2471  }
  2472  
  2473  // Evaluates if the given reply should be mapped or not.
  2474  func (g *srvGateway) shouldMapReplyForGatewaySend(acc *Account, reply []byte) bool {
  2475  	// If for this account there is a recent matching subscription interest
  2476  	// then we will map.
  2477  	sli, _ := g.rsubs.Load(acc)
  2478  	if sli == nil {
  2479  		return false
  2480  	}
  2481  	sl := sli.(*Sublist)
  2482  	if sl.Count() > 0 {
  2483  		if r := sl.Match(string(reply)); len(r.psubs)+len(r.qsubs) > 0 {
  2484  			return true
  2485  		}
  2486  	}
  2487  
  2488  	return false
  2489  }
  2490  
  2491  var subPool = &sync.Pool{
  2492  	New: func() any {
  2493  		return &subscription{}
  2494  	},
  2495  }
  2496  
  2497  // May send a message to all outbound gateways. It is possible
  2498  // that the message is not sent to a given gateway if for instance
  2499  // it is known that this gateway has no interest in the account or
  2500  // subject, etc..
  2501  // <Invoked from any client connection's readLoop>
  2502  func (c *client) sendMsgToGateways(acc *Account, msg, subject, reply []byte, qgroups [][]byte) bool {
  2503  	// We had some times when we were sending across a GW with no subject, and the other side would break
  2504  	// due to parser error. These need to be fixed upstream but also double check here.
  2505  	if len(subject) == 0 {
  2506  		return false
  2507  	}
  2508  	gwsa := [16]*client{}
  2509  	gws := gwsa[:0]
  2510  	// This is in fast path, so avoid calling functions when possible.
  2511  	// Get the outbound connections in place instead of calling
  2512  	// getOutboundGatewayConnections().
  2513  	srv := c.srv
  2514  	gw := srv.gateway
  2515  	gw.RLock()
  2516  	for i := 0; i < len(gw.outo); i++ {
  2517  		gws = append(gws, gw.outo[i])
  2518  	}
  2519  	thisClusterReplyPrefix := gw.replyPfx
  2520  	thisClusterOldReplyPrefix := gw.oldReplyPfx
  2521  	gw.RUnlock()
  2522  	if len(gws) == 0 {
  2523  		return false
  2524  	}
  2525  
  2526  	mt, _ := c.isMsgTraceEnabled()
  2527  	if mt != nil {
  2528  		pa := c.pa
  2529  		msg = mt.setOriginAccountHeaderIfNeeded(c, acc, msg)
  2530  		defer func() { c.pa = pa }()
  2531  	}
  2532  
  2533  	var (
  2534  		queuesa    = [512]byte{}
  2535  		queues     = queuesa[:0]
  2536  		accName    = acc.Name
  2537  		mreplya    [256]byte
  2538  		mreply     []byte
  2539  		dstHash    []byte
  2540  		checkReply = len(reply) > 0
  2541  		didDeliver bool
  2542  		prodIsMQTT = c.isMqtt()
  2543  		dlvMsgs    int64
  2544  	)
  2545  
  2546  	// Get a subscription from the pool
  2547  	sub := subPool.Get().(*subscription)
  2548  
  2549  	// Check if the subject is on the reply prefix, if so, we
  2550  	// need to send that message directly to the origin cluster.
  2551  	directSend, old := isGWRoutedSubjectAndIsOldPrefix(subject)
  2552  	if directSend {
  2553  		if old {
  2554  			dstHash = subject[oldGWReplyPrefixLen : oldGWReplyStart-1]
  2555  		} else {
  2556  			dstHash = subject[gwClusterOffset : gwClusterOffset+gwHashLen]
  2557  		}
  2558  	}
  2559  	for i := 0; i < len(gws); i++ {
  2560  		gwc := gws[i]
  2561  		if directSend {
  2562  			gwc.mu.Lock()
  2563  			var ok bool
  2564  			if gwc.gw.cfg != nil {
  2565  				if old {
  2566  					ok = bytes.Equal(dstHash, gwc.gw.cfg.oldHash)
  2567  				} else {
  2568  					ok = bytes.Equal(dstHash, gwc.gw.cfg.hash)
  2569  				}
  2570  			}
  2571  			gwc.mu.Unlock()
  2572  			if !ok {
  2573  				continue
  2574  			}
  2575  		} else {
  2576  			// Plain sub interest and queue sub results for this account/subject
  2577  			psi, qr := gwc.gatewayInterest(accName, string(subject))
  2578  			if !psi && qr == nil {
  2579  				continue
  2580  			}
  2581  			queues = queuesa[:0]
  2582  			if qr != nil {
  2583  				for i := 0; i < len(qr.qsubs); i++ {
  2584  					qsubs := qr.qsubs[i]
  2585  					if len(qsubs) > 0 {
  2586  						queue := qsubs[0].queue
  2587  						add := true
  2588  						for _, qn := range qgroups {
  2589  							if bytes.Equal(queue, qn) {
  2590  								add = false
  2591  								break
  2592  							}
  2593  						}
  2594  						if add {
  2595  							qgroups = append(qgroups, queue)
  2596  							queues = append(queues, queue...)
  2597  							queues = append(queues, ' ')
  2598  						}
  2599  					}
  2600  				}
  2601  			}
  2602  			if !psi && len(queues) == 0 {
  2603  				continue
  2604  			}
  2605  		}
  2606  		if checkReply {
  2607  			// Check/map only once
  2608  			checkReply = false
  2609  			// Assume we will use original
  2610  			mreply = reply
  2611  			// Decide if we should map.
  2612  			if gw.shouldMapReplyForGatewaySend(acc, reply) {
  2613  				mreply = mreplya[:0]
  2614  				gwc.mu.Lock()
  2615  				useOldPrefix := gwc.gw.useOldPrefix
  2616  				gwc.mu.Unlock()
  2617  				if useOldPrefix {
  2618  					mreply = append(mreply, thisClusterOldReplyPrefix...)
  2619  				} else {
  2620  					mreply = append(mreply, thisClusterReplyPrefix...)
  2621  				}
  2622  				mreply = append(mreply, reply...)
  2623  			}
  2624  		}
  2625  
  2626  		if mt != nil {
  2627  			msg = mt.setHopHeader(c, msg)
  2628  		}
  2629  
  2630  		// Setup the message header.
  2631  		// Make sure we are an 'R' proto by default
  2632  		c.msgb[0] = 'R'
  2633  		mh := c.msgb[:msgHeadProtoLen]
  2634  		mh = append(mh, accName...)
  2635  		mh = append(mh, ' ')
  2636  		mh = append(mh, subject...)
  2637  		mh = append(mh, ' ')
  2638  		if len(queues) > 0 {
  2639  			if len(reply) > 0 {
  2640  				mh = append(mh, "+ "...) // Signal that there is a reply.
  2641  				mh = append(mh, mreply...)
  2642  				mh = append(mh, ' ')
  2643  			} else {
  2644  				mh = append(mh, "| "...) // Only queues
  2645  			}
  2646  			mh = append(mh, queues...)
  2647  		} else if len(reply) > 0 {
  2648  			mh = append(mh, mreply...)
  2649  			mh = append(mh, ' ')
  2650  		}
  2651  		// Headers
  2652  		hasHeader := c.pa.hdr > 0
  2653  		canReceiveHeader := gwc.headers
  2654  
  2655  		if hasHeader {
  2656  			if canReceiveHeader {
  2657  				mh[0] = 'H'
  2658  				mh = append(mh, c.pa.hdb...)
  2659  				mh = append(mh, ' ')
  2660  				mh = append(mh, c.pa.szb...)
  2661  			} else {
  2662  				// If we are here we need to truncate the payload size
  2663  				nsz := strconv.Itoa(c.pa.size - c.pa.hdr)
  2664  				mh = append(mh, nsz...)
  2665  			}
  2666  		} else {
  2667  			mh = append(mh, c.pa.szb...)
  2668  		}
  2669  
  2670  		mh = append(mh, CR_LF...)
  2671  
  2672  		// We reuse the subscription object that we pass to deliverMsg.
  2673  		// So set/reset important fields.
  2674  		sub.nm, sub.max = 0, 0
  2675  		sub.client = gwc
  2676  		sub.subject = subject
  2677  		if c.deliverMsg(prodIsMQTT, sub, acc, subject, mreply, mh, msg, false) {
  2678  			// We don't count internal deliveries so count only if sub.icb is nil
  2679  			if sub.icb == nil {
  2680  				dlvMsgs++
  2681  			}
  2682  			didDeliver = true
  2683  		}
  2684  	}
  2685  	if dlvMsgs > 0 {
  2686  		totalBytes := dlvMsgs * int64(len(msg))
  2687  		// For non MQTT producers, remove the CR_LF * number of messages
  2688  		if !prodIsMQTT {
  2689  			totalBytes -= dlvMsgs * int64(LEN_CR_LF)
  2690  		}
  2691  		if acc != nil {
  2692  			atomic.AddInt64(&acc.outMsgs, dlvMsgs)
  2693  			atomic.AddInt64(&acc.outBytes, totalBytes)
  2694  		}
  2695  		atomic.AddInt64(&srv.outMsgs, dlvMsgs)
  2696  		atomic.AddInt64(&srv.outBytes, totalBytes)
  2697  	}
  2698  	// Done with subscription, put back to pool. We don't need
  2699  	// to reset content since we explicitly set when using it.
  2700  	// However, make sure to not hold a reference to a connection.
  2701  	sub.client = nil
  2702  	subPool.Put(sub)
  2703  	return didDeliver
  2704  }
  2705  
  2706  // Possibly sends an A- to the remote gateway `c`.
  2707  // Invoked when processing an inbound message and the account is not found.
  2708  // A check under a lock that protects processing of SUBs and UNSUBs is
  2709  // done to make sure that we don't send the A- if a subscription has just
  2710  // been created at the same time, which would otherwise results in the
  2711  // remote never sending messages on this account until a new subscription
  2712  // is created.
  2713  func (s *Server) gatewayHandleAccountNoInterest(c *client, accName []byte) {
  2714  	// Check and possibly send the A- under this lock.
  2715  	s.gateway.pasi.Lock()
  2716  	defer s.gateway.pasi.Unlock()
  2717  
  2718  	si, inMap := s.gateway.pasi.m[string(accName)]
  2719  	if inMap && si != nil && len(si) > 0 {
  2720  		return
  2721  	}
  2722  	c.sendAccountUnsubToGateway(accName)
  2723  }
  2724  
  2725  // Helper that sends an A- to this remote gateway if not already done.
  2726  // This function should not be invoked directly but instead be invoked
  2727  // by functions holding the gateway.pasi's Lock.
  2728  func (c *client) sendAccountUnsubToGateway(accName []byte) {
  2729  	// Check if we have sent the A- or not.
  2730  	c.mu.Lock()
  2731  	e, sent := c.gw.insim[string(accName)]
  2732  	if e != nil || !sent {
  2733  		// Add a nil value to indicate that we have sent an A-
  2734  		// so that we know to send A+ when needed.
  2735  		c.gw.insim[string(accName)] = nil
  2736  		var protoa [256]byte
  2737  		proto := protoa[:0]
  2738  		proto = append(proto, aUnsubBytes...)
  2739  		proto = append(proto, accName...)
  2740  		proto = append(proto, CR_LF...)
  2741  		c.enqueueProto(proto)
  2742  		if c.trace {
  2743  			c.traceOutOp("", proto[:len(proto)-LEN_CR_LF])
  2744  		}
  2745  	}
  2746  	c.mu.Unlock()
  2747  }
  2748  
  2749  // Possibly sends an A- for this account or RS- for this subject.
  2750  // Invoked when processing an inbound message and the account is found
  2751  // but there is no interest on this subject.
  2752  // A test is done under a lock that protects processing of SUBs and UNSUBs
  2753  // and if there is no subscription at this time, we send an A-. If there
  2754  // is at least a subscription, but no interest on this subject, we send
  2755  // an RS- for this subject (if not already done).
  2756  func (s *Server) gatewayHandleSubjectNoInterest(c *client, acc *Account, accName, subject []byte) {
  2757  	s.gateway.pasi.Lock()
  2758  	defer s.gateway.pasi.Unlock()
  2759  
  2760  	// If there is no subscription for this account, we would normally
  2761  	// send an A-, however, if this account has the internal subscription
  2762  	// for service reply, send a specific RS- for the subject instead.
  2763  	// Need to grab the lock here since sublist can change during reload.
  2764  	acc.mu.RLock()
  2765  	hasSubs := acc.sl.Count() > 0 || acc.siReply != nil
  2766  	acc.mu.RUnlock()
  2767  
  2768  	// If there is at least a subscription, possibly send RS-
  2769  	if hasSubs {
  2770  		sendProto := false
  2771  		c.mu.Lock()
  2772  		// Send an RS- protocol if not already done and only if
  2773  		// not in the modeInterestOnly.
  2774  		e := c.gw.insim[string(accName)]
  2775  		if e == nil {
  2776  			e = &insie{ni: make(map[string]struct{})}
  2777  			e.ni[string(subject)] = struct{}{}
  2778  			c.gw.insim[string(accName)] = e
  2779  			sendProto = true
  2780  		} else if e.ni != nil {
  2781  			// If we are not in modeInterestOnly, check if we
  2782  			// have already sent an RS-
  2783  			if _, alreadySent := e.ni[string(subject)]; !alreadySent {
  2784  				// TODO(ik): pick some threshold as to when
  2785  				// we need to switch mode
  2786  				if len(e.ni) >= gatewayMaxRUnsubBeforeSwitch {
  2787  					// If too many RS-, switch to all-subs-mode.
  2788  					c.gatewaySwitchAccountToSendAllSubs(e, string(accName))
  2789  				} else {
  2790  					e.ni[string(subject)] = struct{}{}
  2791  					sendProto = true
  2792  				}
  2793  			}
  2794  		}
  2795  		if sendProto {
  2796  			var (
  2797  				protoa = [512]byte{}
  2798  				proto  = protoa[:0]
  2799  			)
  2800  			proto = append(proto, rUnsubBytes...)
  2801  			proto = append(proto, accName...)
  2802  			proto = append(proto, ' ')
  2803  			proto = append(proto, subject...)
  2804  			proto = append(proto, CR_LF...)
  2805  			c.enqueueProto(proto)
  2806  			if c.trace {
  2807  				c.traceOutOp("", proto[:len(proto)-LEN_CR_LF])
  2808  			}
  2809  		}
  2810  		c.mu.Unlock()
  2811  	} else {
  2812  		// There is not a single subscription, send an A- (if not already done).
  2813  		c.sendAccountUnsubToGateway([]byte(acc.Name))
  2814  	}
  2815  }
  2816  
  2817  // Returns the cluster hash from the gateway reply prefix
  2818  func (g *srvGateway) getClusterHash() []byte {
  2819  	g.RLock()
  2820  	clusterHash := g.replyPfx[gwClusterOffset : gwClusterOffset+gwHashLen]
  2821  	g.RUnlock()
  2822  	return clusterHash
  2823  }
  2824  
  2825  // Store this route in map with the key being the remote server's name hash
  2826  // and the remote server's ID hash used by gateway replies mapping routing.
  2827  func (s *Server) storeRouteByHash(srvIDHash string, c *client) {
  2828  	if !s.gateway.enabled {
  2829  		return
  2830  	}
  2831  	s.gateway.routesIDByHash.Store(srvIDHash, c)
  2832  }
  2833  
  2834  // Remove the route with the given keys from the map.
  2835  func (s *Server) removeRouteByHash(srvIDHash string) {
  2836  	if !s.gateway.enabled {
  2837  		return
  2838  	}
  2839  	s.gateway.routesIDByHash.Delete(srvIDHash)
  2840  }
  2841  
  2842  // Returns the route with given hash or nil if not found.
  2843  // This is for gateways only.
  2844  func (s *Server) getRouteByHash(hash, accName []byte) (*client, bool) {
  2845  	id := bytesToString(hash)
  2846  	var perAccount bool
  2847  	if v, ok := s.accRouteByHash.Load(bytesToString(accName)); ok {
  2848  		if v == nil {
  2849  			id += bytesToString(accName)
  2850  			perAccount = true
  2851  		} else {
  2852  			id += strconv.Itoa(v.(int))
  2853  		}
  2854  	}
  2855  	if v, ok := s.gateway.routesIDByHash.Load(id); ok {
  2856  		return v.(*client), perAccount
  2857  	} else if !perAccount {
  2858  		// Check if we have a "no pool" connection at index 0.
  2859  		if v, ok := s.gateway.routesIDByHash.Load(bytesToString(hash) + "0"); ok {
  2860  			if r := v.(*client); r != nil {
  2861  				r.mu.Lock()
  2862  				noPool := r.route.noPool
  2863  				r.mu.Unlock()
  2864  				if noPool {
  2865  					return r, false
  2866  				}
  2867  			}
  2868  		}
  2869  	}
  2870  	return nil, perAccount
  2871  }
  2872  
  2873  // Returns the subject from the routed reply
  2874  func getSubjectFromGWRoutedReply(reply []byte, isOldPrefix bool) []byte {
  2875  	if isOldPrefix {
  2876  		return reply[oldGWReplyStart:]
  2877  	}
  2878  	return reply[gwSubjectOffset:]
  2879  }
  2880  
  2881  // This should be invoked only from processInboundGatewayMsg() or
  2882  // processInboundRoutedMsg() and is checking if the subject
  2883  // (c.pa.subject) has the _GR_ prefix. If so, this is processed
  2884  // as a GW reply and `true` is returned to indicate to the caller
  2885  // that it should stop processing.
  2886  // If gateway is not enabled on this server or if the subject
  2887  // does not start with _GR_, `false` is returned and caller should
  2888  // process message as usual.
  2889  func (c *client) handleGatewayReply(msg []byte) (processed bool) {
  2890  	// Do not handle GW prefixed messages if this server does not have
  2891  	// gateway enabled or if the subject does not start with the previx.
  2892  	if !c.srv.gateway.enabled {
  2893  		return false
  2894  	}
  2895  	isGWPrefix, oldPrefix := isGWRoutedSubjectAndIsOldPrefix(c.pa.subject)
  2896  	if !isGWPrefix {
  2897  		return false
  2898  	}
  2899  	// Save original subject (in case we have to forward)
  2900  	orgSubject := c.pa.subject
  2901  
  2902  	var clusterHash []byte
  2903  	var srvHash []byte
  2904  	var subject []byte
  2905  
  2906  	if oldPrefix {
  2907  		clusterHash = c.pa.subject[oldGWReplyPrefixLen : oldGWReplyStart-1]
  2908  		// Check if this reply is intended for our cluster.
  2909  		if !bytes.Equal(clusterHash, c.srv.gateway.oldHash) {
  2910  			// We could report, for now, just drop.
  2911  			return true
  2912  		}
  2913  		subject = c.pa.subject[oldGWReplyStart:]
  2914  	} else {
  2915  		clusterHash = c.pa.subject[gwClusterOffset : gwClusterOffset+gwHashLen]
  2916  		// Check if this reply is intended for our cluster.
  2917  		if !bytes.Equal(clusterHash, c.srv.gateway.getClusterHash()) {
  2918  			// We could report, for now, just drop.
  2919  			return true
  2920  		}
  2921  		srvHash = c.pa.subject[gwServerOffset : gwServerOffset+gwHashLen]
  2922  		subject = c.pa.subject[gwSubjectOffset:]
  2923  	}
  2924  
  2925  	var route *client
  2926  	var perAccount bool
  2927  
  2928  	// If the origin is not this server, get the route this should be sent to.
  2929  	if c.kind == GATEWAY && srvHash != nil && !bytes.Equal(srvHash, c.srv.gateway.sIDHash) {
  2930  		route, perAccount = c.srv.getRouteByHash(srvHash, c.pa.account)
  2931  		// This will be possibly nil, and in this case we will try to process
  2932  		// the interest from this server.
  2933  	}
  2934  
  2935  	// Adjust the subject
  2936  	c.pa.subject = subject
  2937  
  2938  	// Use a stack buffer to rewrite c.pa.cache since we only need it for
  2939  	// getAccAndResultFromCache()
  2940  	var _pacache [256]byte
  2941  	pacache := _pacache[:0]
  2942  	// For routes that are dedicated to an account, do not put the account
  2943  	// name in the pacache.
  2944  	if c.kind == GATEWAY || (c.kind == ROUTER && c.route != nil && len(c.route.accName) == 0) {
  2945  		pacache = append(pacache, c.pa.account...)
  2946  		pacache = append(pacache, ' ')
  2947  	}
  2948  	pacache = append(pacache, c.pa.subject...)
  2949  	c.pa.pacache = pacache
  2950  
  2951  	acc, r := c.getAccAndResultFromCache()
  2952  	if acc == nil {
  2953  		typeConn := "routed"
  2954  		if c.kind == GATEWAY {
  2955  			typeConn = "gateway"
  2956  		}
  2957  		c.Debugf("Unknown account %q for %s message on subject: %q", c.pa.account, typeConn, c.pa.subject)
  2958  		if c.kind == GATEWAY {
  2959  			c.srv.gatewayHandleAccountNoInterest(c, c.pa.account)
  2960  		}
  2961  		return true
  2962  	}
  2963  
  2964  	// If route is nil, we will process the incoming message locally.
  2965  	if route == nil {
  2966  		// Check if this is a service reply subject (_R_)
  2967  		isServiceReply := isServiceReply(c.pa.subject)
  2968  
  2969  		var queues [][]byte
  2970  		if len(r.psubs)+len(r.qsubs) > 0 {
  2971  			flags := pmrCollectQueueNames | pmrIgnoreEmptyQueueFilter
  2972  			// If this message came from a ROUTE, allow to pick queue subs
  2973  			// only if the message was directly sent by the "gateway" server
  2974  			// in our cluster that received it.
  2975  			if c.kind == ROUTER {
  2976  				flags |= pmrAllowSendFromRouteToRoute
  2977  			}
  2978  			_, queues = c.processMsgResults(acc, r, msg, nil, c.pa.subject, c.pa.reply, flags)
  2979  		}
  2980  		// Since this was a reply that made it to the origin cluster,
  2981  		// we now need to send the message with the real subject to
  2982  		// gateways in case they have interest on that reply subject.
  2983  		if !isServiceReply {
  2984  			c.sendMsgToGateways(acc, msg, c.pa.subject, c.pa.reply, queues)
  2985  		}
  2986  	} else if c.kind == GATEWAY {
  2987  		// Only if we are a gateway connection should we try to route
  2988  		// to the server where the request originated.
  2989  		var bufa [256]byte
  2990  		var buf = bufa[:0]
  2991  		buf = append(buf, msgHeadProto...)
  2992  		if !perAccount {
  2993  			buf = append(buf, acc.Name...)
  2994  			buf = append(buf, ' ')
  2995  		}
  2996  		buf = append(buf, orgSubject...)
  2997  		buf = append(buf, ' ')
  2998  		if len(c.pa.reply) > 0 {
  2999  			buf = append(buf, c.pa.reply...)
  3000  			buf = append(buf, ' ')
  3001  		}
  3002  		szb := c.pa.szb
  3003  		if c.pa.hdr >= 0 {
  3004  			if route.headers {
  3005  				buf[0] = 'H'
  3006  				buf = append(buf, c.pa.hdb...)
  3007  				buf = append(buf, ' ')
  3008  			} else {
  3009  				szb = []byte(strconv.Itoa(c.pa.size - c.pa.hdr))
  3010  				msg = msg[c.pa.hdr:]
  3011  			}
  3012  		}
  3013  		buf = append(buf, szb...)
  3014  		mhEnd := len(buf)
  3015  		buf = append(buf, _CRLF_...)
  3016  		buf = append(buf, msg...)
  3017  
  3018  		route.mu.Lock()
  3019  		route.enqueueProto(buf)
  3020  		if route.trace {
  3021  			route.traceOutOp("", buf[:mhEnd])
  3022  		}
  3023  		route.mu.Unlock()
  3024  	}
  3025  	return true
  3026  }
  3027  
  3028  // Process a message coming from a remote gateway. Send to any sub/qsub
  3029  // in our cluster that is matching. When receiving a message for an
  3030  // account or subject for which there is no interest in this cluster
  3031  // an A-/RS- protocol may be send back.
  3032  // <Invoked from inbound connection's readLoop>
  3033  func (c *client) processInboundGatewayMsg(msg []byte) {
  3034  	// Update statistics
  3035  	c.in.msgs++
  3036  	// The msg includes the CR_LF, so pull back out for accounting.
  3037  	c.in.bytes += int32(len(msg) - LEN_CR_LF)
  3038  
  3039  	if c.opts.Verbose {
  3040  		c.sendOK()
  3041  	}
  3042  
  3043  	// Mostly under testing scenarios.
  3044  	if c.srv == nil {
  3045  		return
  3046  	}
  3047  
  3048  	// If the subject (c.pa.subject) has the gateway prefix, this function will
  3049  	// handle it.
  3050  	if c.handleGatewayReply(msg) {
  3051  		// We are done here.
  3052  		return
  3053  	}
  3054  
  3055  	acc, r := c.getAccAndResultFromCache()
  3056  	if acc == nil {
  3057  		c.Debugf("Unknown account %q for gateway message on subject: %q", c.pa.account, c.pa.subject)
  3058  		c.srv.gatewayHandleAccountNoInterest(c, c.pa.account)
  3059  		return
  3060  	}
  3061  
  3062  	// Check if this is a service reply subject (_R_)
  3063  	noInterest := len(r.psubs) == 0
  3064  	checkNoInterest := true
  3065  	if acc.NumServiceImports() > 0 {
  3066  		if isServiceReply(c.pa.subject) {
  3067  			checkNoInterest = false
  3068  		} else {
  3069  			// We need to eliminate the subject interest from the service imports here to
  3070  			// make sure we send the proper no interest if the service import is the only interest.
  3071  			noInterest = true
  3072  			for _, sub := range r.psubs {
  3073  				// sub.si indicates that this is a subscription for service import, and is immutable.
  3074  				// So sub.si is false, then this is a subscription for something else, so there is
  3075  				// actually proper interest.
  3076  				if !sub.si {
  3077  					noInterest = false
  3078  					break
  3079  				}
  3080  			}
  3081  		}
  3082  	}
  3083  	if checkNoInterest && noInterest {
  3084  		// If there is no interest on plain subs, possibly send an RS-,
  3085  		// even if there is qsubs interest.
  3086  		c.srv.gatewayHandleSubjectNoInterest(c, acc, c.pa.account, c.pa.subject)
  3087  
  3088  		// If there is also no queue filter, then no point in continuing
  3089  		// (even if r.qsubs i > 0).
  3090  		if len(c.pa.queues) == 0 {
  3091  			return
  3092  		}
  3093  	}
  3094  	c.processMsgResults(acc, r, msg, nil, c.pa.subject, c.pa.reply, pmrNoFlag)
  3095  }
  3096  
  3097  // Indicates that the remote which we are sending messages to
  3098  // has decided to send us all its subs interest so that we
  3099  // stop doing optimistic sends.
  3100  // <Invoked from outbound connection's readLoop>
  3101  func (c *client) gatewayAllSubsReceiveStart(info *Info) {
  3102  	account := getAccountFromGatewayCommand(c, info, "start")
  3103  	if account == "" {
  3104  		return
  3105  	}
  3106  
  3107  	c.Debugf("Gateway %q: switching account %q to %s mode",
  3108  		info.Gateway, account, InterestOnly)
  3109  
  3110  	// Since the remote would send us this start command
  3111  	// only after sending us too many RS- for this account,
  3112  	// we should always have an entry here.
  3113  	// TODO(ik): Should we close connection with protocol violation
  3114  	// error if that happens?
  3115  	ei, _ := c.gw.outsim.Load(account)
  3116  	if ei != nil {
  3117  		e := ei.(*outsie)
  3118  		e.Lock()
  3119  		e.mode = Transitioning
  3120  		e.Unlock()
  3121  	} else {
  3122  		e := &outsie{sl: NewSublistWithCache()}
  3123  		e.mode = Transitioning
  3124  		c.mu.Lock()
  3125  		c.gw.outsim.Store(account, e)
  3126  		c.mu.Unlock()
  3127  	}
  3128  }
  3129  
  3130  // Indicates that the remote has finished sending all its
  3131  // subscriptions and we should now not send unless we know
  3132  // there is explicit interest.
  3133  // <Invoked from outbound connection's readLoop>
  3134  func (c *client) gatewayAllSubsReceiveComplete(info *Info) {
  3135  	account := getAccountFromGatewayCommand(c, info, "complete")
  3136  	if account == _EMPTY_ {
  3137  		return
  3138  	}
  3139  	// Done receiving all subs from remote. Set the `ni`
  3140  	// map to nil so that gatewayInterest() no longer
  3141  	// uses it.
  3142  	ei, _ := c.gw.outsim.Load(account)
  3143  	if ei != nil {
  3144  		e := ei.(*outsie)
  3145  		// Needs locking here since `ni` is checked by
  3146  		// many go-routines calling gatewayInterest()
  3147  		e.Lock()
  3148  		e.ni = nil
  3149  		e.mode = InterestOnly
  3150  		e.Unlock()
  3151  
  3152  		c.Debugf("Gateway %q: switching account %q to %s mode complete",
  3153  			info.Gateway, account, InterestOnly)
  3154  	}
  3155  }
  3156  
  3157  // small helper to get the account name from the INFO command.
  3158  func getAccountFromGatewayCommand(c *client, info *Info, cmd string) string {
  3159  	if info.GatewayCmdPayload == nil {
  3160  		c.sendErrAndErr(fmt.Sprintf("Account absent from receive-all-subscriptions-%s command", cmd))
  3161  		c.closeConnection(ProtocolViolation)
  3162  		return _EMPTY_
  3163  	}
  3164  	return string(info.GatewayCmdPayload)
  3165  }
  3166  
  3167  // Switch to send-all-subs mode for the given gateway and account.
  3168  // This is invoked when processing an inbound message and we
  3169  // reach a point where we had to send a lot of RS- for this
  3170  // account. We will send an INFO protocol to indicate that we
  3171  // start sending all our subs (for this account), followed by
  3172  // all subs (RS+) and finally an INFO to indicate the end of it.
  3173  // The remote will then send messages only if it finds explicit
  3174  // interest in the sublist created based on all RS+ that we just
  3175  // sent.
  3176  // The client's lock is held on entry.
  3177  // <Invoked from inbound connection's readLoop>
  3178  func (c *client) gatewaySwitchAccountToSendAllSubs(e *insie, accName string) {
  3179  	// Set this map to nil so that the no-interest is no longer checked.
  3180  	e.ni = nil
  3181  	// Switch mode to transitioning to prevent switchAccountToInterestMode
  3182  	// to possibly call this function multiple times.
  3183  	e.mode = Transitioning
  3184  	s := c.srv
  3185  
  3186  	remoteGWName := c.gw.name
  3187  	c.Debugf("Gateway %q: switching account %q to %s mode",
  3188  		remoteGWName, accName, InterestOnly)
  3189  
  3190  	// Function that will create an INFO protocol
  3191  	// and set proper command.
  3192  	sendCmd := func(cmd byte, useLock bool) {
  3193  		// Use bare server info and simply set the
  3194  		// gateway name and command
  3195  		info := Info{
  3196  			Gateway:           s.gateway.name,
  3197  			GatewayCmd:        cmd,
  3198  			GatewayCmdPayload: stringToBytes(accName),
  3199  		}
  3200  
  3201  		b, _ := json.Marshal(&info)
  3202  		infoJSON := []byte(fmt.Sprintf(InfoProto, b))
  3203  		if useLock {
  3204  			c.mu.Lock()
  3205  		}
  3206  		c.enqueueProto(infoJSON)
  3207  		if useLock {
  3208  			c.mu.Unlock()
  3209  		}
  3210  	}
  3211  	// Send the start command. When remote receives this,
  3212  	// it may continue to send optimistic messages, but
  3213  	// it will start to register RS+/RS- in sublist instead
  3214  	// of noInterest map.
  3215  	sendCmd(gatewayCmdAllSubsStart, false)
  3216  
  3217  	// Execute this in separate go-routine as to not block
  3218  	// the readLoop (which may cause the otherside to close
  3219  	// the connection due to slow consumer)
  3220  	s.startGoRoutine(func() {
  3221  		defer s.grWG.Done()
  3222  
  3223  		s.sendAccountSubsToGateway(c, accName)
  3224  		// Send the complete command. When the remote receives
  3225  		// this, it will not send a message unless it has a
  3226  		// matching sub from us.
  3227  		sendCmd(gatewayCmdAllSubsComplete, true)
  3228  
  3229  		c.Debugf("Gateway %q: switching account %q to %s mode complete",
  3230  			remoteGWName, accName, InterestOnly)
  3231  	})
  3232  }
  3233  
  3234  // Keeps track of the routed reply to be used when/if application sends back a
  3235  // message on the reply without the prefix.
  3236  // If `client` is not nil, it will be stored in the client gwReplyMapping structure,
  3237  // and client lock is held on entry.
  3238  // If `client` is nil, the mapping is stored in the client's account's gwReplyMapping
  3239  // structure. Account lock will be explicitly acquired.
  3240  // This is a server receiver because we use a timer interval that is avail in
  3241  // Server.gateway object.
  3242  func (s *Server) trackGWReply(c *client, acc *Account, reply, routedReply []byte) {
  3243  	var l sync.Locker
  3244  	var g *gwReplyMapping
  3245  	if acc != nil {
  3246  		acc.mu.Lock()
  3247  		defer acc.mu.Unlock()
  3248  		g = &acc.gwReplyMapping
  3249  		l = &acc.mu
  3250  	} else {
  3251  		g = &c.gwReplyMapping
  3252  		l = &c.mu
  3253  	}
  3254  	ttl := s.gateway.recSubExp
  3255  	wasEmpty := len(g.mapping) == 0
  3256  	if g.mapping == nil {
  3257  		g.mapping = make(map[string]*gwReplyMap)
  3258  	}
  3259  	// The reason we pass both `reply` and `routedReply`, is that in some cases,
  3260  	// `routedReply` may have a deliver subject appended, something look like:
  3261  	// "_GR_.xxx.yyy.$JS.ACK.$MQTT_msgs.someid.1.1.1.1620086713306484000.0@$MQTT.msgs.foo"
  3262  	// but `reply` has already been cleaned up (delivery subject removed from tail):
  3263  	// "$JS.ACK.$MQTT_msgs.someid.1.1.1.1620086713306484000.0"
  3264  	// So we will use that knowledge so we don't have to make any cleaning here.
  3265  	routedReply = routedReply[:gwSubjectOffset+len(reply)]
  3266  	// We need to make a copy so that we don't reference the underlying
  3267  	// read buffer.
  3268  	ms := string(routedReply)
  3269  	grm := &gwReplyMap{ms: ms, exp: time.Now().Add(ttl).UnixNano()}
  3270  	// If we are here with the same key but different mapped replies
  3271  	// (say $GNR._.A.srv1.bar and then $GNR._.B.srv2.bar), we need to
  3272  	// store it otherwise we would take the risk of the reply not
  3273  	// making it back.
  3274  	g.mapping[ms[gwSubjectOffset:]] = grm
  3275  	if wasEmpty {
  3276  		atomic.StoreInt32(&g.check, 1)
  3277  		s.gwrm.m.Store(g, l)
  3278  		if atomic.CompareAndSwapInt32(&s.gwrm.w, 0, 1) {
  3279  			select {
  3280  			case s.gwrm.ch <- ttl:
  3281  			default:
  3282  			}
  3283  		}
  3284  	}
  3285  }
  3286  
  3287  // Starts a long lived go routine that is responsible to
  3288  // remove GW reply mapping that have expired.
  3289  func (s *Server) startGWReplyMapExpiration() {
  3290  	s.mu.Lock()
  3291  	s.gwrm.ch = make(chan time.Duration, 1)
  3292  	s.mu.Unlock()
  3293  	s.startGoRoutine(func() {
  3294  		defer s.grWG.Done()
  3295  
  3296  		t := time.NewTimer(time.Hour)
  3297  		var ttl time.Duration
  3298  		for {
  3299  			select {
  3300  			case <-t.C:
  3301  				if ttl == 0 {
  3302  					t.Reset(time.Hour)
  3303  					continue
  3304  				}
  3305  				now := time.Now().UnixNano()
  3306  				mapEmpty := true
  3307  				s.gwrm.m.Range(func(k, v any) bool {
  3308  					g := k.(*gwReplyMapping)
  3309  					l := v.(sync.Locker)
  3310  					l.Lock()
  3311  					for k, grm := range g.mapping {
  3312  						if grm.exp <= now {
  3313  							delete(g.mapping, k)
  3314  							if len(g.mapping) == 0 {
  3315  								atomic.StoreInt32(&g.check, 0)
  3316  								s.gwrm.m.Delete(g)
  3317  							}
  3318  						}
  3319  					}
  3320  					l.Unlock()
  3321  					mapEmpty = false
  3322  					return true
  3323  				})
  3324  				if mapEmpty && atomic.CompareAndSwapInt32(&s.gwrm.w, 1, 0) {
  3325  					ttl = 0
  3326  					t.Reset(time.Hour)
  3327  				} else {
  3328  					t.Reset(ttl)
  3329  				}
  3330  			case cttl := <-s.gwrm.ch:
  3331  				ttl = cttl
  3332  				if !t.Stop() {
  3333  					select {
  3334  					case <-t.C:
  3335  					default:
  3336  					}
  3337  				}
  3338  				t.Reset(ttl)
  3339  			case <-s.quitCh:
  3340  				return
  3341  			}
  3342  		}
  3343  	})
  3344  }