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 }