func NewRandomUnreliableTransport(f trace.Frame, nok, ndrop int, expa, expb time.Duration) *Transport { return NewTransport(f, func(f0, f1 trace.Frame, a0, a1 net.Addr) (net.Conn, net.Conn) { nok, ndrop := rand.Intn(nok+1), rand.Intn(ndrop+1) nok = max(nok, 1) f.Printf("TRANSPORT PROFILE NOK=%d, NDROP=%d", nok, ndrop) return NewSievePipe(f0, f1, a0, a1, nok, ndrop, expa, expb) }) }
func NewTransport(frame trace.Frame, sub *codec.Transport) *Transport { t := &Transport{ frame: frame, sub: sub, Dialer: NewDialer(frame.Refine("dialer"), sub), } frame.Bind(t) return t }
// NewBuffer creates a new buffer with limit m. func NewBuffer(frame trace.Frame, m int) *Buffer { b := &Buffer{ wch: make(chan struct{}, m+1), // +1 for the final EOF, so it does not block // The capacity of rch is chosen so that writers to rch will never block. rch: make(chan struct{}, 4*m+2), } frame.Bind(b) b.Frame = frame for i := 0; i < m; i++ { b.wch <- struct{}{} } return b }
// NewSievePipe returns the two net.Conn endpoints of a new bi-directional drop tail pipe. func NewSievePipe(f0, f1 trace.Frame, a0, a1 net.Addr, nok, ndrop int, expa, expb time.Duration) (p, q net.Conn) { a, b := NewHalfConn(f0), NewHalfConn(f1) ax, bx, xa, xb := newChan(), newChan(), newChan(), newChan() axk, bxk := newBackChan(), newBackChan() a.RecvFrom(xa, a1) b.RecvFrom(xb, a0) a.SendTo(ax, axk, a0) b.SendTo(bx, bxk, a1) ab, ba := StartSieve(f0.Refine("sieve"), f1.Refine("sieve"), ax, bx, xa, xb, axk, bxk, nok, ndrop, expa, expb) a.in, a.out = ba, ab b.in, b.out = ab, ba return a, b }
func testWrite(fr trace.Frame, t *testing.T, c *Conn, ready chan<- int) { defer func() { ready <- 1 }() for i := 0; i < N; i++ { if err := c.Write([]byte{byte(i), byte(i + 1), byte(i + 2)}); err != nil { t.Errorf("write (%s)", err) failNow() } fr.Printf("WROTE %d/%d", i+1, N) } if err := c.Close(); err != nil { t.Fatalf("write-side close (%s)", err) failNow() } fr.Printf("CLOSED WRITE") }
func (a *Conn) Start(frame trace.Frame, id chainID, addr net.Addr, linker linker, scrb func()) { frame.Bind(a) a.frame = frame a.scrb = scrb a.id = id a.addr = addr a.linker = linker a.cascade = MakeCascade(frame) // A buffer size 1 on rch, helps remove a deadlock in the TestConn. // Essentially it ensures that Read and Write (on two ends of a // connection) cannot deadlock each other when a successful Write also // requires a stitch. We throw in a couple of extra buffer spaces to // prevent any potential deadlock between Read and Kill. a.rch = make(chan interface{}, 3) a.kch = make(chan struct{}) go a.readLoop() }
func testRead(fr trace.Frame, t *testing.T, c *Conn, ready chan<- int) { defer func() { ready <- 1 }() for i := 0; i < N; i++ { q, err := c.Read() if err != nil { t.Fatalf("read (%s)", err) failNow() } z := []byte{byte(i), byte(i + 1), byte(i + 2)} if !reflect.DeepEqual(q, z) { t.Fatalf("expecting %#v, got %#v", z, q) failNow() } fr.Printf("READ %d/%d", i+1, N) } if err := c.Close(); err != nil { t.Fatalf("read-side close (%s)", err) failNow() } fr.Printf("CLOSED READ") }
func NewConn(frame trace.Frame, under *chain.Conn) *Conn { // Only 1 needed in readLoop; get 3 just to be safe rch := make(chan interface{}, 3) // Capacity 1 (below) unblocks writeSync, invoked in readLoop right after a connection stitch // stitch is received, racing with a user write waiting on waitForLink. // In particular, if execUserWrite is waiting on waitForLink, it would prevent readLoop from // moving on to adopt the new connection. sch := make(chan *control, 1) // Abort channel ach := make(chan struct{}) // User-facing Conn c := &Conn{ frame: frame, sub: under, rch: rch, ach: ach, bfr: NewBuffer(frame.Refine("buffer"), MemoryCap), } c.frame.Bind(c) // readConn rc := &readConn{ frame: frame.Refine("R∞"), sub: c.sub, rch: rch, sch: sch, ach: ach, bfr: c.bfr, } rc.frame.Bind(rc) go rc.loop() // writeConn wc := &writeConn{ frame: frame.Refine("W∞"), sub: c.sub, bfr: c.bfr, sch: sch, } wc.frame.Bind(wc) go wc.loop() return c }
func NewListener(frame trace.Frame, sub *codec.Listener) *Listener { l := &Listener{frame: frame, sub: sub} frame.Bind(l) return l }
func NewUnreliableTransport(f trace.Frame, nok, ndrop int, expa, expb time.Duration) *Transport { return NewTransport(f, func(f0, f1 trace.Frame, a0, a1 net.Addr) (net.Conn, net.Conn) { f.Printf("TRANSPORT PROFILE NOK=%d, NDROP=%d", nok, ndrop) return NewSievePipe(f0, f1, a0, a1, nok, ndrop, expa, expb) }) }