forked from cerc-io/ipld-eth-server
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:
-5
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
BIN
Binary file not shown.
+36
-12
@@ -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
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user