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