|
|
@ -1,7 +1,6 @@ |
|
|
|
package p2p |
|
|
|
|
|
|
|
import ( |
|
|
|
"fmt" |
|
|
|
"math/rand" |
|
|
|
"net" |
|
|
|
"sync" |
|
|
@ -15,6 +14,19 @@ const ( |
|
|
|
FuzzModeDelay |
|
|
|
) |
|
|
|
|
|
|
|
// 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 sync.Mutex |
|
|
|
start <-chan time.Time |
|
|
|
active bool |
|
|
|
|
|
|
|
config *FuzzConnConfig |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConnConfig is a FuzzedConnection configuration.
|
|
|
|
type FuzzConnConfig struct { |
|
|
|
Mode int |
|
|
|
MaxDelay time.Duration |
|
|
@ -23,7 +35,8 @@ type FuzzConnConfig struct { |
|
|
|
ProbSleep float64 |
|
|
|
} |
|
|
|
|
|
|
|
func defaultFuzzConnConfig() *FuzzConnConfig { |
|
|
|
// DefaultFuzzConnConfig returns the default config.
|
|
|
|
func DefaultFuzzConnConfig() *FuzzConnConfig { |
|
|
|
return &FuzzConnConfig{ |
|
|
|
Mode: FuzzModeDrop, |
|
|
|
MaxDelay: 3 * time.Second, |
|
|
@ -33,86 +46,85 @@ func defaultFuzzConnConfig() *FuzzConnConfig { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConn creates a new FuzzedConnection. Fuzzing starts immediately.
|
|
|
|
func FuzzConn(conn net.Conn) net.Conn { |
|
|
|
return FuzzConnFromConfig(conn, defaultFuzzConnConfig()) |
|
|
|
return FuzzConnFromConfig(conn, DefaultFuzzConnConfig()) |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConnFromConfig creates a new FuzzedConnection from a config. Fuzzing
|
|
|
|
// starts immediately.
|
|
|
|
func FuzzConnFromConfig(conn net.Conn, config *FuzzConnConfig) net.Conn { |
|
|
|
return &FuzzedConnection{ |
|
|
|
conn: conn, |
|
|
|
start: make(<-chan time.Time), |
|
|
|
active: true, |
|
|
|
mode: config.Mode, |
|
|
|
maxDelay: config.MaxDelay, |
|
|
|
probDropRW: config.ProbDropRW, |
|
|
|
probDropConn: config.ProbDropConn, |
|
|
|
probSleep: config.ProbSleep, |
|
|
|
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, defaultFuzzConnConfig()) |
|
|
|
return FuzzConnAfterFromConfig(conn, d, DefaultFuzzConnConfig()) |
|
|
|
} |
|
|
|
|
|
|
|
// FuzzConnAfterFromConfig creates a new FuzzedConnection from a config.
|
|
|
|
// Fuzzing starts when the duration elapses.
|
|
|
|
func FuzzConnAfterFromConfig(conn net.Conn, d time.Duration, config *FuzzConnConfig) net.Conn { |
|
|
|
return &FuzzedConnection{ |
|
|
|
conn: conn, |
|
|
|
start: time.After(d), |
|
|
|
active: false, |
|
|
|
mode: config.Mode, |
|
|
|
maxDelay: config.MaxDelay, |
|
|
|
probDropRW: config.ProbDropRW, |
|
|
|
probDropConn: config.ProbDropConn, |
|
|
|
probSleep: config.ProbSleep, |
|
|
|
conn: conn, |
|
|
|
start: time.After(d), |
|
|
|
active: false, |
|
|
|
config: config, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 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 sync.Mutex |
|
|
|
start <-chan time.Time |
|
|
|
active bool |
|
|
|
|
|
|
|
mode int |
|
|
|
maxDelay time.Duration |
|
|
|
probDropRW float64 |
|
|
|
probDropConn float64 |
|
|
|
probSleep float64 |
|
|
|
// Config returns the connection's config.
|
|
|
|
func (fc *FuzzedConnection) Config() *FuzzConnConfig { |
|
|
|
return fc.config |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) randomDuration() time.Duration { |
|
|
|
maxDelayMillis := int(fc.maxDelay.Nanoseconds() / 1000) |
|
|
|
return time.Millisecond * time.Duration(rand.Int()%maxDelayMillis) |
|
|
|
// 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) |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) SetMode(mode int) { |
|
|
|
switch mode { |
|
|
|
case FuzzModeDrop: |
|
|
|
fc.mode = FuzzModeDrop |
|
|
|
case FuzzModeDelay: |
|
|
|
fc.mode = FuzzModeDelay |
|
|
|
default: |
|
|
|
panic(fmt.Sprintf("Unknown mode %d", mode)) |
|
|
|
// 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) |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) SetProbDropRW(prob float64) { |
|
|
|
fc.probDropRW = prob |
|
|
|
} |
|
|
|
// 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) } |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) SetProbDropConn(prob float64) { |
|
|
|
fc.probDropConn = prob |
|
|
|
// SetReadDeadline implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) SetReadDeadline(t time.Time) error { |
|
|
|
return fc.conn.SetReadDeadline(t) |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) SetProbSleep(prob float64) { |
|
|
|
fc.probSleep = prob |
|
|
|
// SetWriteDeadline implements net.Conn.
|
|
|
|
func (fc *FuzzedConnection) SetWriteDeadline(t time.Time) error { |
|
|
|
return fc.conn.SetWriteDeadline(t) |
|
|
|
} |
|
|
|
|
|
|
|
func (fc *FuzzedConnection) SetMaxDelay(d time.Duration) { |
|
|
|
fc.maxDelay = d |
|
|
|
func (fc *FuzzedConnection) randomDuration() time.Duration { |
|
|
|
maxDelayMillis := int(fc.config.MaxDelay.Nanoseconds() / 1000) |
|
|
|
return time.Millisecond * time.Duration(rand.Int()%maxDelayMillis) |
|
|
|
} |
|
|
|
|
|
|
|
// implements the fuzz (delay, kill conn)
|
|
|
@ -122,18 +134,18 @@ func (fc *FuzzedConnection) fuzz() bool { |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
switch fc.mode { |
|
|
|
switch fc.config.Mode { |
|
|
|
case FuzzModeDrop: |
|
|
|
// randomly drop the r/w, drop the conn, or sleep
|
|
|
|
r := rand.Float64() |
|
|
|
if r <= fc.probDropRW { |
|
|
|
if r <= fc.config.ProbDropRW { |
|
|
|
return true |
|
|
|
} else if r < fc.probDropRW+fc.probDropConn { |
|
|
|
} else if 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 |
|
|
|
} else if r < fc.probDropRW+fc.probDropConn+fc.probSleep { |
|
|
|
} else if r < fc.config.ProbDropRW+fc.config.ProbDropConn+fc.config.ProbSleep { |
|
|
|
time.Sleep(fc.randomDuration()) |
|
|
|
} |
|
|
|
case FuzzModeDelay: |
|
|
@ -143,7 +155,6 @@ func (fc *FuzzedConnection) fuzz() bool { |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
// we don't fuzz until start chan fires
|
|
|
|
func (fc *FuzzedConnection) shouldFuzz() bool { |
|
|
|
if fc.active { |
|
|
|
return true |
|
|
@ -160,31 +171,3 @@ func (fc *FuzzedConnection) shouldFuzz() bool { |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 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) |
|
|
|
} |
|
|
|
|
|
|
|
// Implements net.Conn
|
|
|
|
func (fc *FuzzedConnection) Close() error { return fc.conn.Close() } |
|
|
|
func (fc *FuzzedConnection) LocalAddr() net.Addr { return fc.conn.LocalAddr() } |
|
|
|
func (fc *FuzzedConnection) RemoteAddr() net.Addr { return fc.conn.RemoteAddr() } |
|
|
|
func (fc *FuzzedConnection) SetDeadline(t time.Time) error { return fc.conn.SetDeadline(t) } |
|
|
|
func (fc *FuzzedConnection) SetReadDeadline(t time.Time) error { |
|
|
|
return fc.conn.SetReadDeadline(t) |
|
|
|
} |
|
|
|
func (fc *FuzzedConnection) SetWriteDeadline(t time.Time) error { |
|
|
|
return fc.conn.SetWriteDeadline(t) |
|
|
|
} |