From 5c2d2e01ee186594d12d6087055a46af73b51336 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 21 Apr 2022 17:02:57 +0100 Subject: [PATCH] deprecate NegotiateLazy (#85) --- lazyServer.go | 51 ------------------------- multistream.go | 90 ++------------------------------------------- multistream_test.go | 18 +-------- 3 files changed, 4 insertions(+), 155 deletions(-) delete mode 100644 lazyServer.go diff --git a/lazyServer.go b/lazyServer.go deleted file mode 100644 index b2c795b..0000000 --- a/lazyServer.go +++ /dev/null @@ -1,51 +0,0 @@ -package multistream - -import ( - "io" - "sync" -) - -// lazyServerConn is an io.ReadWriteCloser adapter used for negotiating inbound -// streams (see NegotiateLazy). -// -// This is "lazy" because it doesn't wait for the write half to succeed before -// allowing us to read from the stream. -type lazyServerConn struct { - waitForHandshake sync.Once - werr error - - con io.ReadWriteCloser -} - -func (l *lazyServerConn) Write(b []byte) (int, error) { - l.waitForHandshake.Do(func() { panic("didn't initiate handshake") }) - if l.werr != nil { - return 0, l.werr - } - return l.con.Write(b) -} - -func (l *lazyServerConn) Read(b []byte) (int, error) { - if len(b) == 0 { - return 0, nil - } - return l.con.Read(b) -} - -func (l *lazyServerConn) Close() error { - // As the server, we MUST flush the handshake on close. Otherwise, if - // the other side is actually waiting for our close (i.e., reading until - // EOF), they may get an error even though we received the request. - // - // However, we MUST NOT return any errors from Flush. The initiator may - // have already closed their side for reading. Basically, _we_ don't - // care about the outcome of this flush, only the other side does. - _ = l.Flush() - return l.con.Close() -} - -// Flush sends the handshake. -func (l *lazyServerConn) Flush() error { - l.waitForHandshake.Do(func() { panic("didn't initiate handshake") }) - return l.werr -} diff --git a/multistream.go b/multistream.go index 97101f5..ff57554 100644 --- a/multistream.go +++ b/multistream.go @@ -188,94 +188,10 @@ func (msm *MultistreamMuxer) findHandler(proto string) *Handler { // a multistream, the protocol used, the handler and an error. It is lazy // because the write-handshake is performed on a subroutine, allowing this // to return before that handshake is completed. +// Deprecated: use Negotiate instead. func (msm *MultistreamMuxer) NegotiateLazy(rwc io.ReadWriteCloser) (rwc_ io.ReadWriteCloser, proto string, handler HandlerFunc, err error) { - defer func() { - if rerr := recover(); rerr != nil { - fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack()) - err = fmt.Errorf("panic in lazy multistream negotiation: %s", rerr) - } - }() - - pval := make(chan string, 1) - writeErr := make(chan error, 1) - defer close(pval) - - lzc := &lazyServerConn{ - con: rwc, - } - - started := make(chan struct{}) - go lzc.waitForHandshake.Do(func() { - defer func() { - if rerr := recover(); rerr != nil { - fmt.Fprintf(os.Stderr, "caught panic: %s\n%s\n", rerr, debug.Stack()) - err := fmt.Errorf("panic in lazy multistream negotiation, waiting for handshake: %s", rerr) - lzc.werr = err - writeErr <- err - } - }() - - close(started) - - defer close(writeErr) - - if err := delimWriteBuffered(rwc, []byte(ProtocolID)); err != nil { - lzc.werr = err - writeErr <- err - return - } - - for proto := range pval { - if err := delimWriteBuffered(rwc, []byte(proto)); err != nil { - lzc.werr = err - writeErr <- err - return - } - } - }) - <-started - - line, err := ReadNextToken(rwc) - if err != nil { - return nil, "", nil, err - } - - if line != ProtocolID { - rwc.Close() - return nil, "", nil, ErrIncorrectVersion - } - -loop: - for { - // Now read and respond to commands until they send a valid protocol id - tok, err := ReadNextToken(rwc) - if err != nil { - rwc.Close() - return nil, "", nil, err - } - - h := msm.findHandler(tok) - if h == nil { - select { - case pval <- "na": - case err := <-writeErr: - rwc.Close() - return nil, "", nil, err - } - continue loop - } - - select { - case pval <- tok: - case <-writeErr: - // explicitly ignore this error. It will be returned to any - // writers and if we don't plan on writing anything, we still - // want to complete the handshake - } - - // hand off processing to the sub-protocol handler - return lzc, tok, h.Handle, nil - } + proto, handler, err = msm.Negotiate(rwc) + return rwc, proto, handler, err } // Negotiate performs protocol selection and returns the protocol name and diff --git a/multistream_test.go b/multistream_test.go index 8b3c4ec..0de859e 100644 --- a/multistream_test.go +++ b/multistream_test.go @@ -248,12 +248,6 @@ func TestNegLazyStressWrite(t *testing.T) { return } - _, err = m.Read(nil) - if err != nil { - t.Error(err) - return - } - _, err = m.Write(message) if err != nil { t.Error(err) @@ -690,17 +684,7 @@ func TestNegotiateFail(t *testing.T) { rob := &readonlyBuffer{bytes.NewReader(buf.Bytes())} _, _, err = mux.Negotiate(rob) if err == nil { - t.Fatal("normal negotiate should fail here") - } - - rob = &readonlyBuffer{bytes.NewReader(buf.Bytes())} - _, out, _, err := mux.NegotiateLazy(rob) - if err != nil { - t.Fatal("expected lazy negoatiate to succeed") - } - - if out != "foo" { - t.Fatal("got wrong protocol") + t.Fatal("Negotiate should fail here") } }