You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
1.6 KiB

  1. package p2p
  2. import (
  3. "fmt"
  4. "net"
  5. "sync"
  6. "time"
  7. )
  8. type connectionTracker interface {
  9. AddConn(net.IP) error
  10. RemoveConn(net.IP)
  11. Len() int
  12. }
  13. type connTrackerImpl struct {
  14. cache map[string]uint
  15. lastConnect map[string]time.Time
  16. mutex sync.RWMutex
  17. max uint
  18. window time.Duration
  19. }
  20. func newConnTracker(max uint, window time.Duration) connectionTracker {
  21. return &connTrackerImpl{
  22. cache: make(map[string]uint),
  23. lastConnect: make(map[string]time.Time),
  24. max: max,
  25. }
  26. }
  27. func (rat *connTrackerImpl) Len() int {
  28. rat.mutex.RLock()
  29. defer rat.mutex.RUnlock()
  30. return len(rat.cache)
  31. }
  32. func (rat *connTrackerImpl) AddConn(addr net.IP) error {
  33. address := addr.String()
  34. rat.mutex.Lock()
  35. defer rat.mutex.Unlock()
  36. if num := rat.cache[address]; num >= rat.max {
  37. return fmt.Errorf("%q has %d connections [max=%d]", address, num, rat.max)
  38. } else if num == 0 {
  39. // if there is already at least connection, check to
  40. // see if it was established before within the window,
  41. // and error if so.
  42. if last := rat.lastConnect[address]; time.Since(last) < rat.window {
  43. return fmt.Errorf("%q tried to connect within window of last %s", address, rat.window)
  44. }
  45. }
  46. rat.cache[address]++
  47. rat.lastConnect[address] = time.Now()
  48. return nil
  49. }
  50. func (rat *connTrackerImpl) RemoveConn(addr net.IP) {
  51. address := addr.String()
  52. rat.mutex.Lock()
  53. defer rat.mutex.Unlock()
  54. if num := rat.cache[address]; num > 0 {
  55. rat.cache[address]--
  56. }
  57. if num := rat.cache[address]; num <= 0 {
  58. delete(rat.cache, address)
  59. }
  60. if last, ok := rat.lastConnect[address]; ok && time.Since(last) > rat.window {
  61. delete(rat.lastConnect, address)
  62. }
  63. }