github.com/nsqio/nsq@v1.3.0/nsqd/client_v2.go (about) 1 package nsqd 2 3 import ( 4 "bufio" 5 "compress/flate" 6 "crypto/tls" 7 "fmt" 8 "net" 9 "strings" 10 "sync" 11 "sync/atomic" 12 "time" 13 14 "github.com/golang/snappy" 15 "github.com/nsqio/nsq/internal/auth" 16 ) 17 18 const defaultBufferSize = 16 * 1024 19 20 const ( 21 stateInit = iota 22 stateDisconnected 23 stateConnected 24 stateSubscribed 25 stateClosing 26 ) 27 28 type identifyDataV2 struct { 29 ClientID string `json:"client_id"` 30 Hostname string `json:"hostname"` 31 HeartbeatInterval int `json:"heartbeat_interval"` 32 OutputBufferSize int `json:"output_buffer_size"` 33 OutputBufferTimeout int `json:"output_buffer_timeout"` 34 FeatureNegotiation bool `json:"feature_negotiation"` 35 TLSv1 bool `json:"tls_v1"` 36 Deflate bool `json:"deflate"` 37 DeflateLevel int `json:"deflate_level"` 38 Snappy bool `json:"snappy"` 39 SampleRate int32 `json:"sample_rate"` 40 UserAgent string `json:"user_agent"` 41 MsgTimeout int `json:"msg_timeout"` 42 } 43 44 type identifyEvent struct { 45 OutputBufferTimeout time.Duration 46 HeartbeatInterval time.Duration 47 SampleRate int32 48 MsgTimeout time.Duration 49 } 50 51 type PubCount struct { 52 Topic string `json:"topic"` 53 Count uint64 `json:"count"` 54 } 55 56 type ClientV2Stats struct { 57 ClientID string `json:"client_id"` 58 Hostname string `json:"hostname"` 59 Version string `json:"version"` 60 RemoteAddress string `json:"remote_address"` 61 State int32 `json:"state"` 62 ReadyCount int64 `json:"ready_count"` 63 InFlightCount int64 `json:"in_flight_count"` 64 MessageCount uint64 `json:"message_count"` 65 FinishCount uint64 `json:"finish_count"` 66 RequeueCount uint64 `json:"requeue_count"` 67 ConnectTime int64 `json:"connect_ts"` 68 SampleRate int32 `json:"sample_rate"` 69 Deflate bool `json:"deflate"` 70 Snappy bool `json:"snappy"` 71 UserAgent string `json:"user_agent"` 72 Authed bool `json:"authed,omitempty"` 73 AuthIdentity string `json:"auth_identity,omitempty"` 74 AuthIdentityURL string `json:"auth_identity_url,omitempty"` 75 76 PubCounts []PubCount `json:"pub_counts,omitempty"` 77 78 TLS bool `json:"tls"` 79 CipherSuite string `json:"tls_cipher_suite"` 80 TLSVersion string `json:"tls_version"` 81 TLSNegotiatedProtocol string `json:"tls_negotiated_protocol"` 82 TLSNegotiatedProtocolIsMutual bool `json:"tls_negotiated_protocol_is_mutual"` 83 } 84 85 func (s ClientV2Stats) String() string { 86 connectTime := time.Unix(s.ConnectTime, 0) 87 duration := time.Since(connectTime).Truncate(time.Second) 88 89 _, port, _ := net.SplitHostPort(s.RemoteAddress) 90 id := fmt.Sprintf("%s:%s %s", s.Hostname, port, s.UserAgent) 91 92 // producer 93 if len(s.PubCounts) > 0 { 94 var total uint64 95 var topicOut []string 96 for _, v := range s.PubCounts { 97 total += v.Count 98 topicOut = append(topicOut, fmt.Sprintf("%s=%d", v.Topic, v.Count)) 99 } 100 return fmt.Sprintf("[%s %-21s] msgs: %-8d topics: %s connected: %s", 101 s.Version, 102 id, 103 total, 104 strings.Join(topicOut, ","), 105 duration, 106 ) 107 } 108 109 // consumer 110 return fmt.Sprintf("[%s %-21s] state: %d inflt: %-4d rdy: %-4d fin: %-8d re-q: %-8d msgs: %-8d connected: %s", 111 s.Version, 112 id, 113 s.State, 114 s.InFlightCount, 115 s.ReadyCount, 116 s.FinishCount, 117 s.RequeueCount, 118 s.MessageCount, 119 duration, 120 ) 121 } 122 123 type clientV2 struct { 124 // 64bit atomic vars need to be first for proper alignment on 32bit platforms 125 ReadyCount int64 126 InFlightCount int64 127 MessageCount uint64 128 FinishCount uint64 129 RequeueCount uint64 130 131 pubCounts map[string]uint64 132 133 writeLock sync.RWMutex 134 metaLock sync.RWMutex 135 136 ID int64 137 nsqd *NSQD 138 UserAgent string 139 140 // original connection 141 net.Conn 142 143 // connections based on negotiated features 144 tlsConn *tls.Conn 145 flateWriter *flate.Writer 146 147 // reading/writing interfaces 148 Reader *bufio.Reader 149 Writer *bufio.Writer 150 151 OutputBufferSize int 152 OutputBufferTimeout time.Duration 153 154 HeartbeatInterval time.Duration 155 156 MsgTimeout time.Duration 157 158 State int32 159 ConnectTime time.Time 160 Channel *Channel 161 ReadyStateChan chan int 162 ExitChan chan int 163 164 ClientID string 165 Hostname string 166 167 SampleRate int32 168 169 IdentifyEventChan chan identifyEvent 170 SubEventChan chan *Channel 171 172 TLS int32 173 Snappy int32 174 Deflate int32 175 176 // re-usable buffer for reading the 4-byte lengths off the wire 177 lenBuf [4]byte 178 lenSlice []byte 179 180 AuthSecret string 181 AuthState *auth.State 182 } 183 184 func newClientV2(id int64, conn net.Conn, nsqd *NSQD) *clientV2 { 185 var identifier string 186 if conn != nil { 187 identifier, _, _ = net.SplitHostPort(conn.RemoteAddr().String()) 188 } 189 190 c := &clientV2{ 191 ID: id, 192 nsqd: nsqd, 193 194 Conn: conn, 195 196 Reader: bufio.NewReaderSize(conn, defaultBufferSize), 197 Writer: bufio.NewWriterSize(conn, defaultBufferSize), 198 199 OutputBufferSize: defaultBufferSize, 200 OutputBufferTimeout: nsqd.getOpts().OutputBufferTimeout, 201 202 MsgTimeout: nsqd.getOpts().MsgTimeout, 203 204 // ReadyStateChan has a buffer of 1 to guarantee that in the event 205 // there is a race the state update is not lost 206 ReadyStateChan: make(chan int, 1), 207 ExitChan: make(chan int), 208 ConnectTime: time.Now(), 209 State: stateInit, 210 211 ClientID: identifier, 212 Hostname: identifier, 213 214 SubEventChan: make(chan *Channel, 1), 215 IdentifyEventChan: make(chan identifyEvent, 1), 216 217 // heartbeats are client configurable but default to 30s 218 HeartbeatInterval: nsqd.getOpts().ClientTimeout / 2, 219 220 pubCounts: make(map[string]uint64), 221 } 222 c.lenSlice = c.lenBuf[:] 223 return c 224 } 225 226 func (c *clientV2) String() string { 227 return c.RemoteAddr().String() 228 } 229 230 func (c *clientV2) Type() int { 231 c.metaLock.RLock() 232 hasPublished := len(c.pubCounts) > 0 233 c.metaLock.RUnlock() 234 if hasPublished { 235 return typeProducer 236 } 237 return typeConsumer 238 } 239 240 func (c *clientV2) Identify(data identifyDataV2) error { 241 c.nsqd.logf(LOG_INFO, "[%s] IDENTIFY: %+v", c, data) 242 243 c.metaLock.Lock() 244 c.ClientID = data.ClientID 245 c.Hostname = data.Hostname 246 c.UserAgent = data.UserAgent 247 c.metaLock.Unlock() 248 249 err := c.SetHeartbeatInterval(data.HeartbeatInterval) 250 if err != nil { 251 return err 252 } 253 254 err = c.SetOutputBuffer(data.OutputBufferSize, data.OutputBufferTimeout) 255 if err != nil { 256 return err 257 } 258 259 err = c.SetSampleRate(data.SampleRate) 260 if err != nil { 261 return err 262 } 263 264 err = c.SetMsgTimeout(data.MsgTimeout) 265 if err != nil { 266 return err 267 } 268 269 ie := identifyEvent{ 270 OutputBufferTimeout: c.OutputBufferTimeout, 271 HeartbeatInterval: c.HeartbeatInterval, 272 SampleRate: c.SampleRate, 273 MsgTimeout: c.MsgTimeout, 274 } 275 276 // update the client's message pump 277 select { 278 case c.IdentifyEventChan <- ie: 279 default: 280 } 281 282 return nil 283 } 284 285 func (c *clientV2) Stats(topicName string) ClientStats { 286 c.metaLock.RLock() 287 clientID := c.ClientID 288 hostname := c.Hostname 289 userAgent := c.UserAgent 290 var identity string 291 var identityURL string 292 if c.AuthState != nil { 293 identity = c.AuthState.Identity 294 identityURL = c.AuthState.IdentityURL 295 } 296 pubCounts := make([]PubCount, 0, len(c.pubCounts)) 297 for topic, count := range c.pubCounts { 298 if len(topicName) > 0 && topic != topicName { 299 continue 300 } 301 pubCounts = append(pubCounts, PubCount{ 302 Topic: topic, 303 Count: count, 304 }) 305 break 306 } 307 c.metaLock.RUnlock() 308 stats := ClientV2Stats{ 309 Version: "V2", 310 RemoteAddress: c.RemoteAddr().String(), 311 ClientID: clientID, 312 Hostname: hostname, 313 UserAgent: userAgent, 314 State: atomic.LoadInt32(&c.State), 315 ReadyCount: atomic.LoadInt64(&c.ReadyCount), 316 InFlightCount: atomic.LoadInt64(&c.InFlightCount), 317 MessageCount: atomic.LoadUint64(&c.MessageCount), 318 FinishCount: atomic.LoadUint64(&c.FinishCount), 319 RequeueCount: atomic.LoadUint64(&c.RequeueCount), 320 ConnectTime: c.ConnectTime.Unix(), 321 SampleRate: atomic.LoadInt32(&c.SampleRate), 322 TLS: atomic.LoadInt32(&c.TLS) == 1, 323 Deflate: atomic.LoadInt32(&c.Deflate) == 1, 324 Snappy: atomic.LoadInt32(&c.Snappy) == 1, 325 Authed: c.HasAuthorizations(), 326 AuthIdentity: identity, 327 AuthIdentityURL: identityURL, 328 PubCounts: pubCounts, 329 } 330 if stats.TLS { 331 p := prettyConnectionState{c.tlsConn.ConnectionState()} 332 stats.CipherSuite = p.GetCipherSuite() 333 stats.TLSVersion = p.GetVersion() 334 stats.TLSNegotiatedProtocol = p.NegotiatedProtocol 335 stats.TLSNegotiatedProtocolIsMutual = p.NegotiatedProtocolIsMutual 336 } 337 return stats 338 } 339 340 // struct to convert from integers to the human readable strings 341 type prettyConnectionState struct { 342 tls.ConnectionState 343 } 344 345 func (p *prettyConnectionState) GetCipherSuite() string { 346 switch p.CipherSuite { 347 case tls.TLS_RSA_WITH_RC4_128_SHA: 348 return "TLS_RSA_WITH_RC4_128_SHA" 349 case tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: 350 return "TLS_RSA_WITH_3DES_EDE_CBC_SHA" 351 case tls.TLS_RSA_WITH_AES_128_CBC_SHA: 352 return "TLS_RSA_WITH_AES_128_CBC_SHA" 353 case tls.TLS_RSA_WITH_AES_256_CBC_SHA: 354 return "TLS_RSA_WITH_AES_256_CBC_SHA" 355 case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: 356 return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA" 357 case tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: 358 return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" 359 case tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: 360 return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" 361 case tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: 362 return "TLS_ECDHE_RSA_WITH_RC4_128_SHA" 363 case tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: 364 return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA" 365 case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: 366 return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" 367 case tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: 368 return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" 369 case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: 370 return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" 371 case tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: 372 return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" 373 } 374 return fmt.Sprintf("Unknown %d", p.CipherSuite) 375 } 376 377 func (p *prettyConnectionState) GetVersion() string { 378 switch p.Version { 379 case tls.VersionTLS10: 380 return "TLS1.0" 381 case tls.VersionTLS11: 382 return "TLS1.1" 383 case tls.VersionTLS12: 384 return "TLS1.2" 385 case tls.VersionTLS13: 386 return "TLS1.3" 387 default: 388 return fmt.Sprintf("Unknown %d", p.Version) 389 } 390 } 391 392 func (c *clientV2) IsReadyForMessages() bool { 393 if c.Channel.IsPaused() { 394 return false 395 } 396 397 readyCount := atomic.LoadInt64(&c.ReadyCount) 398 inFlightCount := atomic.LoadInt64(&c.InFlightCount) 399 400 c.nsqd.logf(LOG_DEBUG, "[%s] state rdy: %4d inflt: %4d", c, readyCount, inFlightCount) 401 402 if inFlightCount >= readyCount || readyCount <= 0 { 403 return false 404 } 405 406 return true 407 } 408 409 func (c *clientV2) SetReadyCount(count int64) { 410 oldCount := atomic.SwapInt64(&c.ReadyCount, count) 411 412 if oldCount != count { 413 c.tryUpdateReadyState() 414 } 415 } 416 417 func (c *clientV2) tryUpdateReadyState() { 418 // you can always *try* to write to ReadyStateChan because in the cases 419 // where you cannot the message pump loop would have iterated anyway. 420 // the atomic integer operations guarantee correctness of the value. 421 select { 422 case c.ReadyStateChan <- 1: 423 default: 424 } 425 } 426 427 func (c *clientV2) FinishedMessage() { 428 atomic.AddUint64(&c.FinishCount, 1) 429 atomic.AddInt64(&c.InFlightCount, -1) 430 c.tryUpdateReadyState() 431 } 432 433 func (c *clientV2) Empty() { 434 atomic.StoreInt64(&c.InFlightCount, 0) 435 c.tryUpdateReadyState() 436 } 437 438 func (c *clientV2) SendingMessage() { 439 atomic.AddInt64(&c.InFlightCount, 1) 440 atomic.AddUint64(&c.MessageCount, 1) 441 } 442 443 func (c *clientV2) PublishedMessage(topic string, count uint64) { 444 c.metaLock.Lock() 445 c.pubCounts[topic] += count 446 c.metaLock.Unlock() 447 } 448 449 func (c *clientV2) TimedOutMessage() { 450 atomic.AddInt64(&c.InFlightCount, -1) 451 c.tryUpdateReadyState() 452 } 453 454 func (c *clientV2) RequeuedMessage() { 455 atomic.AddUint64(&c.RequeueCount, 1) 456 atomic.AddInt64(&c.InFlightCount, -1) 457 c.tryUpdateReadyState() 458 } 459 460 func (c *clientV2) StartClose() { 461 // Force the client into ready 0 462 c.SetReadyCount(0) 463 // mark this client as closing 464 atomic.StoreInt32(&c.State, stateClosing) 465 } 466 467 func (c *clientV2) Pause() { 468 c.tryUpdateReadyState() 469 } 470 471 func (c *clientV2) UnPause() { 472 c.tryUpdateReadyState() 473 } 474 475 func (c *clientV2) SetHeartbeatInterval(desiredInterval int) error { 476 c.writeLock.Lock() 477 defer c.writeLock.Unlock() 478 479 switch { 480 case desiredInterval == -1: 481 c.HeartbeatInterval = 0 482 case desiredInterval == 0: 483 // do nothing (use default) 484 case desiredInterval >= 1000 && 485 desiredInterval <= int(c.nsqd.getOpts().MaxHeartbeatInterval/time.Millisecond): 486 c.HeartbeatInterval = time.Duration(desiredInterval) * time.Millisecond 487 default: 488 return fmt.Errorf("heartbeat interval (%d) is invalid", desiredInterval) 489 } 490 491 return nil 492 } 493 494 func (c *clientV2) SetOutputBuffer(desiredSize int, desiredTimeout int) error { 495 c.writeLock.Lock() 496 defer c.writeLock.Unlock() 497 498 switch { 499 case desiredTimeout == -1: 500 c.OutputBufferTimeout = 0 501 case desiredTimeout == 0: 502 // do nothing (use default) 503 case true && 504 desiredTimeout >= int(c.nsqd.getOpts().MinOutputBufferTimeout/time.Millisecond) && 505 desiredTimeout <= int(c.nsqd.getOpts().MaxOutputBufferTimeout/time.Millisecond): 506 507 c.OutputBufferTimeout = time.Duration(desiredTimeout) * time.Millisecond 508 default: 509 return fmt.Errorf("output buffer timeout (%d) is invalid", desiredTimeout) 510 } 511 512 switch { 513 case desiredSize == -1: 514 // effectively no buffer (every write will go directly to the wrapped net.Conn) 515 c.OutputBufferSize = 1 516 c.OutputBufferTimeout = 0 517 case desiredSize == 0: 518 // do nothing (use default) 519 case desiredSize >= 64 && desiredSize <= int(c.nsqd.getOpts().MaxOutputBufferSize): 520 c.OutputBufferSize = desiredSize 521 default: 522 return fmt.Errorf("output buffer size (%d) is invalid", desiredSize) 523 } 524 525 if desiredSize != 0 { 526 err := c.Writer.Flush() 527 if err != nil { 528 return err 529 } 530 c.Writer = bufio.NewWriterSize(c.Conn, c.OutputBufferSize) 531 } 532 533 return nil 534 } 535 536 func (c *clientV2) SetSampleRate(sampleRate int32) error { 537 if sampleRate < 0 || sampleRate > 99 { 538 return fmt.Errorf("sample rate (%d) is invalid", sampleRate) 539 } 540 atomic.StoreInt32(&c.SampleRate, sampleRate) 541 return nil 542 } 543 544 func (c *clientV2) SetMsgTimeout(msgTimeout int) error { 545 c.writeLock.Lock() 546 defer c.writeLock.Unlock() 547 548 switch { 549 case msgTimeout == 0: 550 // do nothing (use default) 551 case msgTimeout >= 1000 && 552 msgTimeout <= int(c.nsqd.getOpts().MaxMsgTimeout/time.Millisecond): 553 c.MsgTimeout = time.Duration(msgTimeout) * time.Millisecond 554 default: 555 return fmt.Errorf("msg timeout (%d) is invalid", msgTimeout) 556 } 557 558 return nil 559 } 560 561 func (c *clientV2) UpgradeTLS() error { 562 c.writeLock.Lock() 563 defer c.writeLock.Unlock() 564 565 tlsConn := tls.Server(c.Conn, c.nsqd.tlsConfig) 566 tlsConn.SetDeadline(time.Now().Add(5 * time.Second)) 567 err := tlsConn.Handshake() 568 if err != nil { 569 return err 570 } 571 c.tlsConn = tlsConn 572 573 c.Reader = bufio.NewReaderSize(c.tlsConn, defaultBufferSize) 574 c.Writer = bufio.NewWriterSize(c.tlsConn, c.OutputBufferSize) 575 576 atomic.StoreInt32(&c.TLS, 1) 577 578 return nil 579 } 580 581 func (c *clientV2) UpgradeDeflate(level int) error { 582 c.writeLock.Lock() 583 defer c.writeLock.Unlock() 584 585 conn := c.Conn 586 if c.tlsConn != nil { 587 conn = c.tlsConn 588 } 589 590 c.Reader = bufio.NewReaderSize(flate.NewReader(conn), defaultBufferSize) 591 592 fw, _ := flate.NewWriter(conn, level) 593 c.flateWriter = fw 594 c.Writer = bufio.NewWriterSize(fw, c.OutputBufferSize) 595 596 atomic.StoreInt32(&c.Deflate, 1) 597 598 return nil 599 } 600 601 func (c *clientV2) UpgradeSnappy() error { 602 c.writeLock.Lock() 603 defer c.writeLock.Unlock() 604 605 conn := c.Conn 606 if c.tlsConn != nil { 607 conn = c.tlsConn 608 } 609 610 c.Reader = bufio.NewReaderSize(snappy.NewReader(conn), defaultBufferSize) 611 //lint:ignore SA1019 NewWriter is deprecated by NewBufferedWriter, but we're doing our own buffering 612 c.Writer = bufio.NewWriterSize(snappy.NewWriter(conn), c.OutputBufferSize) 613 614 atomic.StoreInt32(&c.Snappy, 1) 615 616 return nil 617 } 618 619 func (c *clientV2) Flush() error { 620 var zeroTime time.Time 621 if c.HeartbeatInterval > 0 { 622 c.SetWriteDeadline(time.Now().Add(c.HeartbeatInterval)) 623 } else { 624 c.SetWriteDeadline(zeroTime) 625 } 626 627 err := c.Writer.Flush() 628 if err != nil { 629 return err 630 } 631 632 if c.flateWriter != nil { 633 return c.flateWriter.Flush() 634 } 635 636 return nil 637 } 638 639 func (c *clientV2) QueryAuthd() error { 640 remoteIP := "" 641 if c.RemoteAddr().Network() == "tcp" { 642 ip, _, err := net.SplitHostPort(c.String()) 643 if err != nil { 644 return err 645 } 646 remoteIP = ip 647 } 648 649 tlsEnabled := atomic.LoadInt32(&c.TLS) == 1 650 commonName := "" 651 if tlsEnabled { 652 tlsConnState := c.tlsConn.ConnectionState() 653 if len(tlsConnState.PeerCertificates) > 0 { 654 commonName = tlsConnState.PeerCertificates[0].Subject.CommonName 655 } 656 } 657 658 authState, err := auth.QueryAnyAuthd(c.nsqd.getOpts().AuthHTTPAddresses, 659 remoteIP, tlsEnabled, commonName, c.AuthSecret, 660 c.nsqd.clientTLSConfig, 661 c.nsqd.getOpts().HTTPClientConnectTimeout, 662 c.nsqd.getOpts().HTTPClientRequestTimeout) 663 if err != nil { 664 return err 665 } 666 c.AuthState = authState 667 return nil 668 } 669 670 func (c *clientV2) Auth(secret string) error { 671 c.AuthSecret = secret 672 return c.QueryAuthd() 673 } 674 675 func (c *clientV2) IsAuthorized(topic, channel string) (bool, error) { 676 if c.AuthState == nil { 677 return false, nil 678 } 679 if c.AuthState.IsExpired() { 680 err := c.QueryAuthd() 681 if err != nil { 682 return false, err 683 } 684 } 685 if c.AuthState.IsAllowed(topic, channel) { 686 return true, nil 687 } 688 return false, nil 689 } 690 691 func (c *clientV2) HasAuthorizations() bool { 692 if c.AuthState != nil { 693 return len(c.AuthState.Authorizations) != 0 694 } 695 return false 696 }