...
Run Format

Source file src/net/internal/socktest/switch.go

Documentation: net/internal/socktest

  // Copyright 2015 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // Package socktest provides utilities for socket testing.
  package socktest
  
  import (
  	"fmt"
  	"sync"
  )
  
  // A Switch represents a callpath point switch for socket system
  // calls.
  type Switch struct {
  	once sync.Once
  
  	fmu   sync.RWMutex
  	fltab map[FilterType]Filter
  
  	smu   sync.RWMutex
  	sotab Sockets
  	stats stats
  }
  
  func (sw *Switch) init() {
  	sw.fltab = make(map[FilterType]Filter)
  	sw.sotab = make(Sockets)
  	sw.stats = make(stats)
  }
  
  // Stats returns a list of per-cookie socket statistics.
  func (sw *Switch) Stats() []Stat {
  	var st []Stat
  	sw.smu.RLock()
  	for _, s := range sw.stats {
  		ns := *s
  		st = append(st, ns)
  	}
  	sw.smu.RUnlock()
  	return st
  }
  
  // Sockets returns mappings of socket descriptor to socket status.
  func (sw *Switch) Sockets() Sockets {
  	sw.smu.RLock()
  	tab := make(Sockets, len(sw.sotab))
  	for i, s := range sw.sotab {
  		tab[i] = s
  	}
  	sw.smu.RUnlock()
  	return tab
  }
  
  // A Cookie represents a 3-tuple of a socket; address family, socket
  // type and protocol number.
  type Cookie uint64
  
  // Family returns an address family.
  func (c Cookie) Family() int { return int(c >> 48) }
  
  // Type returns a socket type.
  func (c Cookie) Type() int { return int(c << 16 >> 32) }
  
  // Protocol returns a protocol number.
  func (c Cookie) Protocol() int { return int(c & 0xff) }
  
  func cookie(family, sotype, proto int) Cookie {
  	return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff
  }
  
  // A Status represents the status of a socket.
  type Status struct {
  	Cookie    Cookie
  	Err       error // error status of socket system call
  	SocketErr error // error status of socket by SO_ERROR
  }
  
  func (so Status) String() string {
  	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)
  }
  
  // A Stat represents a per-cookie socket statistics.
  type Stat struct {
  	Family   int // address family
  	Type     int // socket type
  	Protocol int // protocol number
  
  	Opened    uint64 // number of sockets opened
  	Connected uint64 // number of sockets connected
  	Listened  uint64 // number of sockets listened
  	Accepted  uint64 // number of sockets accepted
  	Closed    uint64 // number of sockets closed
  
  	OpenFailed    uint64 // number of sockets open failed
  	ConnectFailed uint64 // number of sockets connect failed
  	ListenFailed  uint64 // number of sockets listen failed
  	AcceptFailed  uint64 // number of sockets accept failed
  	CloseFailed   uint64 // number of sockets close failed
  }
  
  func (st Stat) String() string {
  	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)
  }
  
  type stats map[Cookie]*Stat
  
  func (st stats) getLocked(c Cookie) *Stat {
  	s, ok := st[c]
  	if !ok {
  		s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()}
  		st[c] = s
  	}
  	return s
  }
  
  // A FilterType represents a filter type.
  type FilterType int
  
  const (
  	FilterSocket        FilterType = iota // for Socket
  	FilterConnect                         // for Connect or ConnectEx
  	FilterListen                          // for Listen
  	FilterAccept                          // for Accept, Accept4 or AcceptEx
  	FilterGetsockoptInt                   // for GetsockoptInt
  	FilterClose                           // for Close or Closesocket
  )
  
  // A Filter represents a socket system call filter.
  //
  // It will only be executed before a system call for a socket that has
  // an entry in internal table.
  // If the filter returns a non-nil error, the execution of system call
  // will be canceled and the system call function returns the non-nil
  // error.
  // It can return a non-nil AfterFilter for filtering after the
  // execution of the system call.
  type Filter func(*Status) (AfterFilter, error)
  
  func (f Filter) apply(st *Status) (AfterFilter, error) {
  	if f == nil {
  		return nil, nil
  	}
  	return f(st)
  }
  
  // An AfterFilter represents a socket system call filter after an
  // execution of a system call.
  //
  // It will only be executed after a system call for a socket that has
  // an entry in internal table.
  // If the filter returns a non-nil error, the system call function
  // returns the non-nil error.
  type AfterFilter func(*Status) error
  
  func (f AfterFilter) apply(st *Status) error {
  	if f == nil {
  		return nil
  	}
  	return f(st)
  }
  
  // Set deploys the socket system call filter f for the filter type t.
  func (sw *Switch) Set(t FilterType, f Filter) {
  	sw.once.Do(sw.init)
  	sw.fmu.Lock()
  	sw.fltab[t] = f
  	sw.fmu.Unlock()
  }
  

View as plain text