kubo/p2p/protocol/mux.go
Henry 92d08db7a5 rewrote import paths of go.net/context to use golang.org/x/context
- updated go-ctxgroup and goprocess
ctxgroup: AddChildGroup was changed to AddChild. Used in two files:
- p2p/net/mock/mock_net.go
- routing/dht/dht.go

- updated context from hg repo to git
prev. commit in hg was ad01a6fcc8a19d3a4478c836895ffe883bd2ceab. (context: make parentCancelCtx iterative)
represents commit 84f8955a887232b6308d79c68b8db44f64df455c in git repo

- updated context to master (b6fdb7d8a4ccefede406f8fe0f017fb58265054c)

Aaron Jacobs (2):
net/context: Don't accept a context in the DoSomethingSlow example.
context: Be clear that users must cancel the result of WithCancel.

Andrew Gerrand (1):
go.net: use golang.org/x/... import paths

Bryan C. Mills (1):
net/context: Don't leak goroutines in Done example.

Damien Neil (1):
context: fix removal of cancelled timer contexts from parent

David Symonds (2):
context: Fix WithValue example code.
net: add import comments.

Sameer Ajmani (1):
context: fix TestAllocs to account for ints in interfaces
2015-02-25 11:58:19 +01:00

143 lines
3.5 KiB
Go

package protocol
import (
"fmt"
"io"
"sync"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
inet "github.com/jbenet/go-ipfs/p2p/net"
eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
)
var log = eventlog.Logger("net/mux")
type streamHandlerMap map[ID]inet.StreamHandler
// Mux provides simple stream multixplexing.
// It helps you precisely when:
// * You have many streams
// * You have function handlers
//
// It contains the handlers for each protocol accepted.
// It dispatches handlers for streams opened by remote peers.
type Mux struct {
lock sync.RWMutex
handlers streamHandlerMap
defaultHandler inet.StreamHandler
}
func NewMux() *Mux {
return &Mux{
handlers: streamHandlerMap{},
}
}
// Protocols returns the list of protocols this muxer has handlers for
func (m *Mux) Protocols() []ID {
m.lock.RLock()
l := make([]ID, 0, len(m.handlers))
for p := range m.handlers {
l = append(l, p)
}
m.lock.RUnlock()
return l
}
// readHeader reads the stream and returns the next Handler function
// according to the muxer encoding.
func (m *Mux) readHeader(s io.Reader) (ID, inet.StreamHandler, error) {
p, err := ReadHeader(s)
if err != nil {
return "", nil, err
}
m.lock.RLock()
defer m.lock.RUnlock()
h, found := m.handlers[p]
switch {
case !found && m.defaultHandler != nil:
return p, m.defaultHandler, nil
case !found && m.defaultHandler == nil:
return p, nil, fmt.Errorf("%s no handler with name: %s (%d)", m, p, len(p))
default:
return p, h, nil
}
}
// String returns the muxer's printing representation
func (m *Mux) String() string {
m.lock.RLock()
defer m.lock.RUnlock()
return fmt.Sprintf("<Muxer %p %d>", m, len(m.handlers))
}
func (m *Mux) SetDefaultHandler(h inet.StreamHandler) {
m.lock.Lock()
m.defaultHandler = h
m.lock.Unlock()
}
// SetHandler sets the protocol handler on the Network's Muxer.
// This operation is threadsafe.
func (m *Mux) SetHandler(p ID, h inet.StreamHandler) {
log.Debugf("%s setting handler for protocol: %s (%d)", m, p, len(p))
m.lock.Lock()
m.handlers[p] = h
m.lock.Unlock()
}
// RemoveHandler removes the protocol handler on the Network's Muxer.
// This operation is threadsafe.
func (m *Mux) RemoveHandler(p ID) {
log.Debugf("%s removing handler for protocol: %s (%d)", m, p, len(p))
m.lock.Lock()
delete(m.handlers, p)
m.lock.Unlock()
}
// Handle reads the next name off the Stream, and calls a handler function
// This is done in its own goroutine, to avoid blocking the caller.
func (m *Mux) Handle(s inet.Stream) {
go m.HandleSync(s)
}
// HandleSync reads the next name off the Stream, and calls a handler function
// This is done synchronously. The handler function will return before
// HandleSync returns.
func (m *Mux) HandleSync(s inet.Stream) {
ctx := context.Background()
name, handler, err := m.readHeader(s)
if err != nil {
err = fmt.Errorf("protocol mux error: %s", err)
log.Event(ctx, "muxError", lgbl.Error(err))
s.Close()
return
}
log.Debugf("muxer handle protocol %s: %s", s.Conn().RemotePeer(), name)
handler(s)
}
// ReadLengthPrefix reads the name from Reader with a length-byte-prefix.
func ReadLengthPrefix(r io.Reader) (string, error) {
// c-string identifier
// the first byte is our length
l := make([]byte, 1)
if _, err := io.ReadFull(r, l); err != nil {
return "", err
}
length := int(l[0])
// the next are our identifier
name := make([]byte, length)
if _, err := io.ReadFull(r, name); err != nil {
return "", err
}
return string(name), nil
}