update to work with go-ipfs fork that doesn't use go modules and so can play nice with our forked dependencies; update documentation and dockerfile

This commit is contained in:
Ian Norden
2019-12-02 13:24:54 -06:00
parent 5356cd50bb
commit 230e782e6c
2033 changed files with 224479 additions and 83670 deletions
-5
View File
@@ -135,11 +135,6 @@ func main() {
}
```
## Maintainers
Captain: [@whyrusleeping](https://github.com/whyrusleeping).
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multistream/issues).
+53 -17
View File
@@ -1,6 +1,7 @@
package multistream
import (
"bytes"
"errors"
"io"
)
@@ -9,28 +10,58 @@ import (
// the protocol specified for the handshake.
var ErrNotSupported = errors.New("protocol not supported")
// ErrNoProtocols is the error returned when the no protocols have been
// specified.
var ErrNoProtocols = errors.New("no protocols specified")
// SelectProtoOrFail performs the initial multistream handshake
// to inform the muxer of the protocol that will be used to communicate
// on this ReadWriteCloser. It returns an error if, for example,
// the muxer does not know how to handle this protocol.
func SelectProtoOrFail(proto string, rwc io.ReadWriteCloser) error {
err := handshake(rwc)
if err != nil {
return err
errCh := make(chan error, 1)
go func() {
var buf bytes.Buffer
delimWrite(&buf, []byte(ProtocolID))
delimWrite(&buf, []byte(proto))
_, err := io.Copy(rwc, &buf)
errCh <- err
}()
// We have to read *both* errors.
err1 := readMultistreamHeader(rwc)
err2 := readProto(proto, rwc)
if werr := <-errCh; werr != nil {
return werr
}
return trySelect(proto, rwc)
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
return nil
}
// SelectOneOf will perform handshakes with the protocols on the given slice
// until it finds one which is supported by the muxer.
func SelectOneOf(protos []string, rwc io.ReadWriteCloser) (string, error) {
err := handshake(rwc)
if err != nil {
return "", err
if len(protos) == 0 {
return "", ErrNoProtocols
}
for _, p := range protos {
// Use SelectProtoOrFail to pipeline the /multistream/1.0.0 handshake
// with an attempt to negotiate the first protocol. If that fails, we
// can continue negotiating the rest of the protocols normally.
//
// This saves us a round trip.
switch err := SelectProtoOrFail(protos[0], rwc); err {
case nil:
return protos[0], nil
case ErrNotSupported: // try others
default:
return "", err
}
for _, p := range protos[1:] {
err := trySelect(p, rwc)
switch err {
case nil:
@@ -49,14 +80,16 @@ func handshake(rwc io.ReadWriteCloser) error {
errCh <- delimWriteBuffered(rwc, []byte(ProtocolID))
}()
tok, readErr := ReadNextToken(rwc)
writeErr := <-errCh
if writeErr != nil {
return writeErr
if err := readMultistreamHeader(rwc); err != nil {
return err
}
if readErr != nil {
return readErr
return <-errCh
}
func readMultistreamHeader(r io.ReadWriter) error {
tok, err := ReadNextToken(r)
if err != nil {
return err
}
if tok != ProtocolID {
@@ -70,8 +103,11 @@ func trySelect(proto string, rwc io.ReadWriteCloser) error {
if err != nil {
return err
}
return readProto(proto, rwc)
}
tok, err := ReadNextToken(rwc)
func readProto(proto string, rw io.ReadWriter) error {
tok, err := ReadNextToken(rw)
if err != nil {
return err
}
+3 -2
View File
@@ -1,7 +1,6 @@
package multistream
import (
"bufio"
"fmt"
"io"
"sync"
@@ -98,7 +97,9 @@ func (l *lazyClientConn) doWriteHandshake() {
// Perform the write handshake but *also* write some extra data.
func (l *lazyClientConn) doWriteHandshakeWithData(extra []byte) int {
buf := bufio.NewWriter(l.con)
buf := getWriter(l.con)
defer putWriter(buf)
for _, proto := range l.protos {
l.werr = delimWrite(buf, []byte(proto))
if l.werr != nil {
Binary file not shown.
+36 -12
View File
@@ -19,9 +19,15 @@ var ErrTooLarge = errors.New("incoming message was too large")
// the multistream muxers on both sides of a channel can work with each other.
const ProtocolID = "/multistream/1.0.0"
var writerPool = sync.Pool{
New: func() interface{} {
return bufio.NewWriter(nil)
},
}
// HandlerFunc is a user-provided function used by the MultistreamMuxer to
// handle a protocol/stream.
type HandlerFunc func(protocol string, rwc io.ReadWriteCloser) error
type HandlerFunc = func(protocol string, rwc io.ReadWriteCloser) error
// Handler is a wrapper to HandlerFunc which attaches a name (protocol) and a
// match function which can optionally be used to select a handler by other
@@ -35,7 +41,7 @@ type Handler struct {
// MultistreamMuxer is a muxer for multistream. Depending on the stream
// protocol tag it will select the right handler and hand the stream off to it.
type MultistreamMuxer struct {
handlerlock sync.Mutex
handlerlock sync.RWMutex
handlers []Handler
}
@@ -55,7 +61,9 @@ func writeUvarint(w io.Writer, i uint64) error {
}
func delimWriteBuffered(w io.Writer, mes []byte) error {
bw := bufio.NewWriter(w)
bw := getWriter(w)
defer putWriter(bw)
err := delimWrite(bw, mes)
if err != nil {
return err
@@ -123,13 +131,14 @@ func (msm *MultistreamMuxer) AddHandler(protocol string, handler HandlerFunc) {
// will be selected even if the handler name and protocol tags are different.
func (msm *MultistreamMuxer) AddHandlerWithFunc(protocol string, match func(string) bool, handler HandlerFunc) {
msm.handlerlock.Lock()
defer msm.handlerlock.Unlock()
msm.removeHandler(protocol)
msm.handlers = append(msm.handlers, Handler{
MatchFunc: match,
Handle: handler,
AddName: protocol,
})
msm.handlerlock.Unlock()
}
// RemoveHandler removes the handler with the given name from the muxer.
@@ -151,12 +160,14 @@ func (msm *MultistreamMuxer) removeHandler(protocol string) {
// Protocols returns the list of handler-names added to this this muxer.
func (msm *MultistreamMuxer) Protocols() []string {
msm.handlerlock.RLock()
defer msm.handlerlock.RUnlock()
var out []string
msm.handlerlock.Lock()
for _, h := range msm.handlers {
out = append(out, h.AddName)
}
msm.handlerlock.Unlock()
return out
}
@@ -165,8 +176,8 @@ func (msm *MultistreamMuxer) Protocols() []string {
var ErrIncorrectVersion = errors.New("client connected with incorrect version")
func (msm *MultistreamMuxer) findHandler(proto string) *Handler {
msm.handlerlock.Lock()
defer msm.handlerlock.Unlock()
msm.handlerlock.RLock()
defer msm.handlerlock.RUnlock()
for _, h := range msm.handlers {
if h.MatchFunc(proto) {
@@ -181,7 +192,7 @@ 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.
func (msm *MultistreamMuxer) NegotiateLazy(rwc io.ReadWriteCloser) (Multistream, string, HandlerFunc, error) {
func (msm *MultistreamMuxer) NegotiateLazy(rwc io.ReadWriteCloser) (io.ReadWriteCloser, string, HandlerFunc, error) {
pval := make(chan string, 1)
writeErr := make(chan error, 1)
defer close(pval)
@@ -324,7 +335,8 @@ loop:
// supported protocols to the given Writer.
func (msm *MultistreamMuxer) Ls(w io.Writer) error {
buf := new(bytes.Buffer)
msm.handlerlock.Lock()
msm.handlerlock.RLock()
err := writeUvarint(buf, uint64(len(msm.handlers)))
if err != nil {
return err
@@ -333,11 +345,12 @@ func (msm *MultistreamMuxer) Ls(w io.Writer) error {
for _, h := range msm.handlers {
err := delimWrite(buf, []byte(h.AddName))
if err != nil {
msm.handlerlock.Unlock()
msm.handlerlock.RUnlock()
return err
}
}
msm.handlerlock.Unlock()
msm.handlerlock.RUnlock()
ll := make([]byte, 16)
nw := binary.PutUvarint(ll, uint64(buf.Len()))
@@ -438,3 +451,14 @@ func (br *byteReader) ReadByte() (byte, error) {
}
return 0, err
}
func getWriter(w io.Writer) *bufio.Writer {
bw := writerPool.Get().(*bufio.Writer)
bw.Reset(w)
return bw
}
func putWriter(bw *bufio.Writer) {
bw.Reset(nil)
writerPool.Put(bw)
}
+28
View File
@@ -0,0 +1,28 @@
// +build gofuzz
package multistream
import "bytes"
type rwc struct {
*bytes.Reader
}
func (*rwc) Write(b []byte) (int, error) {
return len(b), nil
}
func (*rwc) Close() error {
return nil
}
func Fuzz(b []byte) int {
readStream := bytes.NewReader(b)
input := &rwc{readStream}
mux := NewMultistreamMuxer()
mux.AddHandler("/a", nil)
mux.AddHandler("/b", nil)
_ = mux.Handle(input)
return 1
}