switch.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package socktest provides utilities for socket testing.
  5. package socktest
  6. import (
  7. "fmt"
  8. "sync"
  9. )
  10. // A Switch represents a callpath point switch for socket system
  11. // calls.
  12. type Switch struct {
  13. once sync.Once
  14. fmu sync.RWMutex
  15. fltab map[FilterType]Filter
  16. smu sync.RWMutex
  17. sotab Sockets
  18. stats stats
  19. }
  20. func (sw *Switch) init() {
  21. sw.fltab = make(map[FilterType]Filter)
  22. sw.sotab = make(Sockets)
  23. sw.stats = make(stats)
  24. }
  25. // Stats returns a list of per-cookie socket statistics.
  26. func (sw *Switch) Stats() []Stat {
  27. var st []Stat
  28. sw.smu.RLock()
  29. for _, s := range sw.stats {
  30. ns := *s
  31. st = append(st, ns)
  32. }
  33. sw.smu.RUnlock()
  34. return st
  35. }
  36. // Sockets returns mappings of socket descriptor to socket status.
  37. func (sw *Switch) Sockets() Sockets {
  38. sw.smu.RLock()
  39. tab := make(Sockets, len(sw.sotab))
  40. for i, s := range sw.sotab {
  41. tab[i] = s
  42. }
  43. sw.smu.RUnlock()
  44. return tab
  45. }
  46. // A Cookie represents a 3-tuple of a socket; address family, socket
  47. // type and protocol number.
  48. type Cookie uint64
  49. // Family returns an address family.
  50. func (c Cookie) Family() int { return int(c >> 48) }
  51. // Type returns a socket type.
  52. func (c Cookie) Type() int { return int(c << 16 >> 32) }
  53. // Protocol returns a protocol number.
  54. func (c Cookie) Protocol() int { return int(c & 0xff) }
  55. func cookie(family, sotype, proto int) Cookie {
  56. return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff
  57. }
  58. // A Status represents the status of a socket.
  59. type Status struct {
  60. Cookie Cookie
  61. Err error // error status of socket system call
  62. SocketErr error // error status of socket by SO_ERROR
  63. }
  64. func (so Status) String() string {
  65. return fmt.Sprintf("(%s, %s, %s): syscallerr=%v socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
  66. }
  67. // A Stat represents a per-cookie socket statistics.
  68. type Stat struct {
  69. Family int // address family
  70. Type int // socket type
  71. Protocol int // protocol number
  72. Opened uint64 // number of sockets opened
  73. Connected uint64 // number of sockets connected
  74. Listened uint64 // number of sockets listened
  75. Accepted uint64 // number of sockets accepted
  76. Closed uint64 // number of sockets closed
  77. OpenFailed uint64 // number of sockets open failed
  78. ConnectFailed uint64 // number of sockets connect failed
  79. ListenFailed uint64 // number of sockets listen failed
  80. AcceptFailed uint64 // number of sockets accept failed
  81. CloseFailed uint64 // number of sockets close failed
  82. }
  83. func (st Stat) String() string {
  84. return fmt.Sprintf("(%s, %s, %s): opened=%d connected=%d listened=%d accepted=%d closed=%d openfailed=%d connectfailed=%d listenfailed=%d acceptfailed=%d closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
  85. }
  86. type stats map[Cookie]*Stat
  87. func (st stats) getLocked(c Cookie) *Stat {
  88. s, ok := st[c]
  89. if !ok {
  90. s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()}
  91. st[c] = s
  92. }
  93. return s
  94. }
  95. // A FilterType represents a filter type.
  96. type FilterType int
  97. const (
  98. FilterSocket FilterType = iota // for Socket
  99. FilterConnect // for Connect or ConnectEx
  100. FilterListen // for Listen
  101. FilterAccept // for Accept, Accept4 or AcceptEx
  102. FilterGetsockoptInt // for GetsockoptInt
  103. FilterClose // for Close or Closesocket
  104. )
  105. // A Filter represents a socket system call filter.
  106. //
  107. // It will only be executed before a system call for a socket that has
  108. // an entry in internal table.
  109. // If the filter returns a non-nil error, the execution of system call
  110. // will be canceled and the system call function returns the non-nil
  111. // error.
  112. // It can return a non-nil AfterFilter for filtering after the
  113. // execution of the system call.
  114. type Filter func(*Status) (AfterFilter, error)
  115. func (f Filter) apply(st *Status) (AfterFilter, error) {
  116. if f == nil {
  117. return nil, nil
  118. }
  119. return f(st)
  120. }
  121. // An AfterFilter represents a socket system call filter after an
  122. // execution of a system call.
  123. //
  124. // It will only be executed after a system call for a socket that has
  125. // an entry in internal table.
  126. // If the filter returns a non-nil error, the system call function
  127. // returns the non-nil error.
  128. type AfterFilter func(*Status) error
  129. func (f AfterFilter) apply(st *Status) error {
  130. if f == nil {
  131. return nil
  132. }
  133. return f(st)
  134. }
  135. // Set deploys the socket system call filter f for the filter type t.
  136. func (sw *Switch) Set(t FilterType, f Filter) {
  137. sw.once.Do(sw.init)
  138. sw.fmu.Lock()
  139. sw.fltab[t] = f
  140. sw.fmu.Unlock()
  141. }