|
|
@ -1,153 +0,0 @@ |
|
|
|
package p2p |
|
|
|
|
|
|
|
import ( |
|
|
|
"net" |
|
|
|
"time" |
|
|
|
|
|
|
|
"github.com/tendermint/tendermint/config" |
|
|
|
tmrand "github.com/tendermint/tendermint/libs/rand" |
|
|
|
tmsync "github.com/tendermint/tendermint/libs/sync" |
|
|
|
) |
|
|
|
|
|
|
|
// FuzzedConnection wraps any net.Conn and depending on the mode either delays
|
|
|
|
// reads/writes or randomly drops reads/writes/connections.
|
|
|
|
type FuzzedConnection struct { |
|
|
|
conn net.Conn |
|
|
|
|
|
|
|
mtx tmsync.Mutex |
|
|
|
start <-chan time.Time |
|
|
|
active bool |
|
|
|
|
|
|
|
config *config.FuzzConnConfig |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConn creates a new FuzzedConnection. Fuzzing starts immediately.
|
|
|
|
func FuzzConn(conn net.Conn) net.Conn { |
|
|
|
return FuzzConnFromConfig(conn, config.DefaultFuzzConnConfig()) |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConnFromConfig creates a new FuzzedConnection from a config. Fuzzing
|
|
|
|
// starts immediately.
|
|
|
|
func FuzzConnFromConfig(conn net.Conn, config *config.FuzzConnConfig) net.Conn { |
|
|
|
return &FuzzedConnection{ |
|
|
|
conn: conn, |
|
|
|
start: make(<-chan time.Time), |
|
|
|
active: true, |
|
|
|
config: config, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConnAfter creates a new FuzzedConnection. Fuzzing starts when the
|
|
|
|
// duration elapses.
|
|
|
|
func FuzzConnAfter(conn net.Conn, d time.Duration) net.Conn { |
|
|
|
return FuzzConnAfterFromConfig(conn, d, config.DefaultFuzzConnConfig()) |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConnAfterFromConfig creates a new FuzzedConnection from a config.
|
|
|
|
// Fuzzing starts when the duration elapses.
|
|
|
|
func FuzzConnAfterFromConfig( |
|
|
|
conn net.Conn, |
|
|
|
d time.Duration, |
|
|
|
config *config.FuzzConnConfig, |
|
|
|
) net.Conn { |
|
|
|
return &FuzzedConnection{ |
|
|
|
conn: conn, |
|
|
|
start: time.After(d), |
|
|
|
active: false, |
|
|
|
config: config, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Config returns the connection's config.
|
|
|
|
func (fc *FuzzedConnection) Config() *config.FuzzConnConfig { |
|
|
|
return fc.config |
|
|
|
} |
|
|
|
|
|
|
|
// Read implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) Read(data []byte) (n int, err error) { |
|
|
|
if fc.fuzz() { |
|
|
|
return 0, nil |
|
|
|
} |
|
|
|
return fc.conn.Read(data) |
|
|
|
} |
|
|
|
|
|
|
|
// Write implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) Write(data []byte) (n int, err error) { |
|
|
|
if fc.fuzz() { |
|
|
|
return 0, nil |
|
|
|
} |
|
|
|
return fc.conn.Write(data) |
|
|
|
} |
|
|
|
|
|
|
|
// Close implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) Close() error { return fc.conn.Close() } |
|
|
|
|
|
|
|
// LocalAddr implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) LocalAddr() net.Addr { return fc.conn.LocalAddr() } |
|
|
|
|
|
|
|
// RemoteAddr implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) RemoteAddr() net.Addr { return fc.conn.RemoteAddr() } |
|
|
|
|
|
|
|
// SetDeadline implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) SetDeadline(t time.Time) error { return fc.conn.SetDeadline(t) } |
|
|
|
|
|
|
|
// SetReadDeadline implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) SetReadDeadline(t time.Time) error { |
|
|
|
return fc.conn.SetReadDeadline(t) |
|
|
|
} |
|
|
|
|
|
|
|
// SetWriteDeadline implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) SetWriteDeadline(t time.Time) error { |
|
|
|
return fc.conn.SetWriteDeadline(t) |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) randomDuration() time.Duration { |
|
|
|
maxDelayMillis := int(fc.config.MaxDelay.Nanoseconds() / 1000) |
|
|
|
return time.Millisecond * time.Duration(tmrand.Int()%maxDelayMillis) // nolint: gas
|
|
|
|
} |
|
|
|
|
|
|
|
// implements the fuzz (delay, kill conn)
|
|
|
|
// and returns whether or not the read/write should be ignored
|
|
|
|
func (fc *FuzzedConnection) fuzz() bool { |
|
|
|
if !fc.shouldFuzz() { |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
switch fc.config.Mode { |
|
|
|
case config.FuzzModeDrop: |
|
|
|
// randomly drop the r/w, drop the conn, or sleep
|
|
|
|
r := tmrand.Float64() |
|
|
|
switch { |
|
|
|
case r <= fc.config.ProbDropRW: |
|
|
|
return true |
|
|
|
case r < fc.config.ProbDropRW+fc.config.ProbDropConn: |
|
|
|
// XXX: can't this fail because machine precision?
|
|
|
|
// XXX: do we need an error?
|
|
|
|
fc.Close() |
|
|
|
return true |
|
|
|
case r < fc.config.ProbDropRW+fc.config.ProbDropConn+fc.config.ProbSleep: |
|
|
|
time.Sleep(fc.randomDuration()) |
|
|
|
} |
|
|
|
case config.FuzzModeDelay: |
|
|
|
// sleep a bit
|
|
|
|
time.Sleep(fc.randomDuration()) |
|
|
|
} |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) shouldFuzz() bool { |
|
|
|
if fc.active { |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
fc.mtx.Lock() |
|
|
|
defer fc.mtx.Unlock() |
|
|
|
|
|
|
|
select { |
|
|
|
case <-fc.start: |
|
|
|
fc.active = true |
|
|
|
return true |
|
|
|
default: |
|
|
|
return false |
|
|
|
} |
|
|
|
} |