1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-29 01:12:24 +08:00

net: move Network implementation to own pkg

I needed the network implementation in its own
package, because I'll be writing several services that
will plug into _it_ that shouldn't be part of the core net
package. and then there were dependency conflicts. yay.
mux + identify are good examples of what i mean.
This commit is contained in:
Juan Batiz-Benet
2014-12-24 10:17:26 -08:00
parent 45a1ff0018
commit 4807127def
13 changed files with 165 additions and 150 deletions

View File

@ -21,6 +21,7 @@ import (
merkledag "github.com/jbenet/go-ipfs/merkledag" merkledag "github.com/jbenet/go-ipfs/merkledag"
namesys "github.com/jbenet/go-ipfs/namesys" namesys "github.com/jbenet/go-ipfs/namesys"
inet "github.com/jbenet/go-ipfs/net" inet "github.com/jbenet/go-ipfs/net"
ipfsnet "github.com/jbenet/go-ipfs/net/ipfsnet"
path "github.com/jbenet/go-ipfs/path" path "github.com/jbenet/go-ipfs/path"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
pin "github.com/jbenet/go-ipfs/pin" pin "github.com/jbenet/go-ipfs/pin"
@ -121,7 +122,7 @@ func NewIpfsNode(ctx context.Context, cfg *config.Config, online bool) (n *IpfsN
return nil, debugerror.Wrap(err) return nil, debugerror.Wrap(err)
} }
n.Network, err = inet.NewNetwork(ctx, listenAddrs, n.Identity, n.Peerstore) n.Network, err = ipfsnet.NewNetwork(ctx, listenAddrs, n.Identity, n.Peerstore)
if err != nil { if err != nil {
return nil, debugerror.Wrap(err) return nil, debugerror.Wrap(err)
} }

View File

@ -8,30 +8,15 @@ import (
"time" "time"
inet "github.com/jbenet/go-ipfs/net" inet "github.com/jbenet/go-ipfs/net"
netutil "github.com/jbenet/go-ipfs/net/ipfsnet/util"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
eventlog "github.com/jbenet/go-ipfs/util/eventlog" eventlog "github.com/jbenet/go-ipfs/util/eventlog"
testutil "github.com/jbenet/go-ipfs/util/testutil"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
) )
var log = eventlog.Logger("backpressure") var log = eventlog.Logger("backpressure")
func GenNetwork(t *testing.T, ctx context.Context) (inet.Network, error) {
p := testutil.RandPeerNetParamsOrFatal(t)
ps := peer.NewPeerstore()
ps.AddAddress(p.ID, p.Addr)
ps.AddPubKey(p.ID, p.PubKey)
ps.AddPrivKey(p.ID, p.PrivKey)
return inet.NewNetwork(ctx, ps.Addresses(p.ID), p.ID, ps)
}
func divulgeAddresses(a, b inet.Network) {
id := a.LocalPeer()
addrs := a.Peerstore().Addresses(id)
b.Peerstore().AddAddresses(id, addrs)
}
// TestBackpressureStreamHandler tests whether mux handler // TestBackpressureStreamHandler tests whether mux handler
// ratelimiting works. Meaning, since the handler is sequential // ratelimiting works. Meaning, since the handler is sequential
// it should block senders. // it should block senders.
@ -149,14 +134,8 @@ a problem.
// ok that's enough setup. let's do it! // ok that's enough setup. let's do it!
ctx := context.Background() ctx := context.Background()
n1, err := GenNetwork(t, ctx) n1 := netutil.GenNetwork(t, ctx)
if err != nil { n2 := netutil.GenNetwork(t, ctx)
t.Fatal(err)
}
n2, err := GenNetwork(t, ctx)
if err != nil {
t.Fatal(err)
}
// setup receiver handler // setup receiver handler
n1.SetHandler(inet.ProtocolTesting, receiver) n1.SetHandler(inet.ProtocolTesting, receiver)
@ -291,17 +270,11 @@ func TestStBackpressureStreamWrite(t *testing.T) {
// setup the networks // setup the networks
ctx := context.Background() ctx := context.Background()
n1, err := GenNetwork(t, ctx) n1 := netutil.GenNetwork(t, ctx)
if err != nil { n2 := netutil.GenNetwork(t, ctx)
t.Fatal(err)
}
n2, err := GenNetwork(t, ctx)
if err != nil {
t.Fatal(err)
}
divulgeAddresses(n1, n2) netutil.DivulgeAddresses(n1, n2)
divulgeAddresses(n2, n1) netutil.DivulgeAddresses(n2, n1)
// setup sender handler on 1 // setup sender handler on 1
n1.SetHandler(inet.ProtocolTesting, sender) n1.SetHandler(inet.ProtocolTesting, sender)
@ -313,6 +286,9 @@ func TestStBackpressureStreamWrite(t *testing.T) {
// open a stream, from 2->1, this is our reader // open a stream, from 2->1, this is our reader
s, err := n2.NewStream(inet.ProtocolTesting, n1.LocalPeer()) s, err := n2.NewStream(inet.ProtocolTesting, n1.LocalPeer())
if err != nil {
t.Fatal(err)
}
// let's make sure r/w works. // let's make sure r/w works.
testSenderWrote := func(bytesE int) { testSenderWrote := func(bytesE int) {

View File

@ -23,6 +23,7 @@ const (
ProtocolDHT ProtocolID = "/ipfs/dht" ProtocolDHT ProtocolID = "/ipfs/dht"
ProtocolIdentify ProtocolID = "/ipfs/id" ProtocolIdentify ProtocolID = "/ipfs/id"
ProtocolDiag ProtocolID = "/ipfs/diagnostics" ProtocolDiag ProtocolID = "/ipfs/diagnostics"
ProtocolRelay ProtocolID = "/ipfs/relay"
) )
// MessageSizeMax is a soft (recommended) maximum for network messages. // MessageSizeMax is a soft (recommended) maximum for network messages.
@ -96,11 +97,6 @@ type Network interface {
// CtxGroup returns the network's contextGroup // CtxGroup returns the network's contextGroup
CtxGroup() ctxgroup.ContextGroup CtxGroup() ctxgroup.ContextGroup
// IdentifyProtocol returns the instance of the object running the Identify
// Protocol. This is what runs the ifps handshake-- this should be removed
// if this abstracted out to its own package.
IdentifyProtocol() *IDService
} }
// Dialer represents a service that can dial out to peers // Dialer represents a service that can dial out to peers

View File

@ -5,14 +5,20 @@ import (
"fmt" "fmt"
ic "github.com/jbenet/go-ipfs/crypto" ic "github.com/jbenet/go-ipfs/crypto"
inet "github.com/jbenet/go-ipfs/net"
ids "github.com/jbenet/go-ipfs/net/services/identify"
mux "github.com/jbenet/go-ipfs/net/services/mux"
swarm "github.com/jbenet/go-ipfs/net/swarm" swarm "github.com/jbenet/go-ipfs/net/swarm"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup" ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
eventlog "github.com/jbenet/go-ipfs/util/eventlog"
) )
var log = eventlog.Logger("net/mux")
type stream swarm.Stream type stream swarm.Stream
func (s *stream) SwarmStream() *swarm.Stream { func (s *stream) SwarmStream() *swarm.Stream {
@ -20,7 +26,7 @@ func (s *stream) SwarmStream() *swarm.Stream {
} }
// Conn returns the connection this stream is part of. // Conn returns the connection this stream is part of.
func (s *stream) Conn() Conn { func (s *stream) Conn() inet.Conn {
c := s.SwarmStream().Conn() c := s.SwarmStream().Conn()
return (*conn_)(c) return (*conn_)(c)
} }
@ -50,7 +56,7 @@ func (c *conn_) SwarmConn() *swarm.Conn {
return (*swarm.Conn)(c) return (*swarm.Conn)(c)
} }
func (c *conn_) NewStreamWithProtocol(pr ProtocolID) (Stream, error) { func (c *conn_) NewStreamWithProtocol(pr inet.ProtocolID) (inet.Stream, error) {
s, err := (*swarm.Conn)(c).NewStream() s, err := (*swarm.Conn)(c).NewStream()
if err != nil { if err != nil {
return nil, err return nil, err
@ -58,7 +64,7 @@ func (c *conn_) NewStreamWithProtocol(pr ProtocolID) (Stream, error) {
ss := (*stream)(s) ss := (*stream)(s)
if err := WriteProtocolHeader(pr, ss); err != nil { if err := mux.WriteProtocolHeader(pr, ss); err != nil {
ss.Close() ss.Close()
return nil, err return nil, err
} }
@ -90,30 +96,32 @@ func (c *conn_) RemotePublicKey() ic.PubKey {
return c.SwarmConn().RemotePublicKey() return c.SwarmConn().RemotePublicKey()
} }
// network implements the Network interface, // Network implements the inet.Network interface.
type network struct { // It uses a swarm to connect to remote hosts.
local peer.ID // local peer type Network struct {
mux Mux // protocol multiplexing local peer.ID // local peer
swarm *swarm.Swarm // peer connection multiplexing
ps peer.Peerstore ps peer.Peerstore
ids *IDService
swarm *swarm.Swarm // peer connection multiplexing
mux mux.Mux // protocol multiplexing
ids *ids.IDService
cg ctxgroup.ContextGroup // for Context closing cg ctxgroup.ContextGroup // for Context closing
} }
// NewNetwork constructs a new network and starts listening on given addresses. // NewNetwork constructs a new network and starts listening on given addresses.
func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.ID, func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.ID,
peers peer.Peerstore) (Network, error) { peers peer.Peerstore) (*Network, error) {
s, err := swarm.NewSwarm(ctx, listen, local, peers) s, err := swarm.NewSwarm(ctx, listen, local, peers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n := &network{ n := &Network{
local: local, local: local,
swarm: s, swarm: s,
mux: Mux{Handlers: StreamHandlerMap{}}, mux: mux.Mux{Handlers: inet.StreamHandlerMap{}},
cg: ctxgroup.WithContext(ctx), cg: ctxgroup.WithContext(ctx),
ps: peers, ps: peers,
} }
@ -127,20 +135,20 @@ func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.ID,
// setup a conn handler that immediately "asks the other side about them" // setup a conn handler that immediately "asks the other side about them"
// this is ProtocolIdentify. // this is ProtocolIdentify.
n.ids = NewIDService(n) n.ids = ids.NewIDService(n)
s.SetConnHandler(n.newConnHandler) s.SetConnHandler(n.newConnHandler)
return n, nil return n, nil
} }
func (n *network) newConnHandler(c *swarm.Conn) { func (n *Network) newConnHandler(c *swarm.Conn) {
cc := (*conn_)(c) cc := (*conn_)(c)
n.ids.IdentifyConn(cc) n.ids.IdentifyConn(cc)
} }
// DialPeer attempts to establish a connection to a given peer. // DialPeer attempts to establish a connection to a given peer.
// Respects the context. // Respects the context.
func (n *network) DialPeer(ctx context.Context, p peer.ID) error { func (n *Network) DialPeer(ctx context.Context, p peer.ID) error {
log.Debugf("[%s] network dialing peer [%s]", n.local, p) log.Debugf("[%s] network dialing peer [%s]", n.local, p)
sc, err := n.swarm.Dial(ctx, p) sc, err := n.swarm.Dial(ctx, p)
if err != nil { if err != nil {
@ -165,39 +173,40 @@ func (n *network) DialPeer(ctx context.Context, p peer.ID) error {
return nil return nil
} }
func (n *network) Protocols() []ProtocolID { // Protocols returns the ProtocolIDs of all the registered handlers.
func (n *Network) Protocols() []inet.ProtocolID {
return n.mux.Protocols() return n.mux.Protocols()
} }
// CtxGroup returns the network's ContextGroup // CtxGroup returns the network's ContextGroup
func (n *network) CtxGroup() ctxgroup.ContextGroup { func (n *Network) CtxGroup() ctxgroup.ContextGroup {
return n.cg return n.cg
} }
// Swarm returns the network's peerstream.Swarm // Swarm returns the network's peerstream.Swarm
func (n *network) Swarm() *swarm.Swarm { func (n *Network) Swarm() *swarm.Swarm {
return n.Swarm() return n.Swarm()
} }
// LocalPeer the network's LocalPeer // LocalPeer the network's LocalPeer
func (n *network) LocalPeer() peer.ID { func (n *Network) LocalPeer() peer.ID {
return n.swarm.LocalPeer() return n.swarm.LocalPeer()
} }
// Peers returns the connected peers // Peers returns the connected peers
func (n *network) Peers() []peer.ID { func (n *Network) Peers() []peer.ID {
return n.swarm.Peers() return n.swarm.Peers()
} }
// Peers returns the connected peers // Peers returns the connected peers
func (n *network) Peerstore() peer.Peerstore { func (n *Network) Peerstore() peer.Peerstore {
return n.ps return n.ps
} }
// Conns returns the connected peers // Conns returns the connected peers
func (n *network) Conns() []Conn { func (n *Network) Conns() []inet.Conn {
conns1 := n.swarm.Connections() conns1 := n.swarm.Connections()
out := make([]Conn, len(conns1)) out := make([]inet.Conn, len(conns1))
for i, c := range conns1 { for i, c := range conns1 {
out[i] = (*conn_)(c) out[i] = (*conn_)(c)
} }
@ -205,9 +214,9 @@ func (n *network) Conns() []Conn {
} }
// ConnsToPeer returns the connections in this Netowrk for given peer. // ConnsToPeer returns the connections in this Netowrk for given peer.
func (n *network) ConnsToPeer(p peer.ID) []Conn { func (n *Network) ConnsToPeer(p peer.ID) []inet.Conn {
conns1 := n.swarm.ConnectionsToPeer(p) conns1 := n.swarm.ConnectionsToPeer(p)
out := make([]Conn, len(conns1)) out := make([]inet.Conn, len(conns1))
for i, c := range conns1 { for i, c := range conns1 {
out[i] = (*conn_)(c) out[i] = (*conn_)(c)
} }
@ -215,53 +224,53 @@ func (n *network) ConnsToPeer(p peer.ID) []Conn {
} }
// ClosePeer connection to peer // ClosePeer connection to peer
func (n *network) ClosePeer(p peer.ID) error { func (n *Network) ClosePeer(p peer.ID) error {
return n.swarm.CloseConnection(p) return n.swarm.CloseConnection(p)
} }
// close is the real teardown function // close is the real teardown function
func (n *network) close() error { func (n *Network) close() error {
return n.swarm.Close() return n.swarm.Close()
} }
// Close calls the ContextCloser func // Close calls the ContextCloser func
func (n *network) Close() error { func (n *Network) Close() error {
return n.cg.Close() return n.cg.Close()
} }
// BandwidthTotals returns the total amount of bandwidth transferred // BandwidthTotals returns the total amount of bandwidth transferred
func (n *network) BandwidthTotals() (in uint64, out uint64) { func (n *Network) BandwidthTotals() (in uint64, out uint64) {
// need to implement this. probably best to do it in swarm this time. // need to implement this. probably best to do it in swarm this time.
// need a "metrics" object // need a "metrics" object
return 0, 0 return 0, 0
} }
// ListenAddresses returns a list of addresses at which this network listens. // ListenAddresses returns a list of addresses at which this network listens.
func (n *network) ListenAddresses() []ma.Multiaddr { func (n *Network) ListenAddresses() []ma.Multiaddr {
return n.swarm.ListenAddresses() return n.swarm.ListenAddresses()
} }
// InterfaceListenAddresses returns a list of addresses at which this network // InterfaceListenAddresses returns a list of addresses at which this network
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to // listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces. // use the known local interfaces.
func (n *network) InterfaceListenAddresses() ([]ma.Multiaddr, error) { func (n *Network) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
return swarm.InterfaceListenAddresses(n.swarm) return swarm.InterfaceListenAddresses(n.swarm)
} }
// Connectedness returns a state signaling connection capabilities // Connectedness returns a state signaling connection capabilities
// For now only returns Connected || NotConnected. Expand into more later. // For now only returns Connected || NotConnected. Expand into more later.
func (n *network) Connectedness(p peer.ID) Connectedness { func (n *Network) Connectedness(p peer.ID) inet.Connectedness {
c := n.swarm.ConnectionsToPeer(p) c := n.swarm.ConnectionsToPeer(p)
if c != nil && len(c) > 0 { if c != nil && len(c) > 0 {
return Connected return inet.Connected
} }
return NotConnected return inet.NotConnected
} }
// NewStream returns a new stream to given peer p. // NewStream returns a new stream to given peer p.
// If there is no connection to p, attempts to create one. // If there is no connection to p, attempts to create one.
// If ProtocolID is "", writes no header. // If ProtocolID is "", writes no header.
func (n *network) NewStream(pr ProtocolID, p peer.ID) (Stream, error) { func (n *Network) NewStream(pr inet.ProtocolID, p peer.ID) (inet.Stream, error) {
log.Debugf("[%s] network opening stream to peer [%s]: %s", n.local, p, pr) log.Debugf("[%s] network opening stream to peer [%s]: %s", n.local, p, pr)
s, err := n.swarm.NewStreamWithPeer(p) s, err := n.swarm.NewStreamWithPeer(p)
if err != nil { if err != nil {
@ -270,7 +279,7 @@ func (n *network) NewStream(pr ProtocolID, p peer.ID) (Stream, error) {
ss := (*stream)(s) ss := (*stream)(s)
if err := WriteProtocolHeader(pr, ss); err != nil { if err := mux.WriteProtocolHeader(pr, ss); err != nil {
ss.Close() ss.Close()
return nil, err return nil, err
} }
@ -280,23 +289,16 @@ func (n *network) NewStream(pr ProtocolID, p peer.ID) (Stream, error) {
// SetHandler sets the protocol handler on the Network's Muxer. // SetHandler sets the protocol handler on the Network's Muxer.
// This operation is threadsafe. // This operation is threadsafe.
func (n *network) SetHandler(p ProtocolID, h StreamHandler) { func (n *Network) SetHandler(p inet.ProtocolID, h inet.StreamHandler) {
n.mux.SetHandler(p, h) n.mux.SetHandler(p, h)
} }
func (n *network) String() string { // String returns a string representation of Network.
func (n *Network) String() string {
return fmt.Sprintf("<Network %s>", n.LocalPeer()) return fmt.Sprintf("<Network %s>", n.LocalPeer())
} }
func (n *network) IdentifyProtocol() *IDService { // IdentifyProtocol returns the network's IDService
func (n *Network) IdentifyProtocol() *ids.IDService {
return n.ids return n.ids
} }
func WriteProtocolHeader(pr ProtocolID, s Stream) error {
if pr != "" { // only write proper protocol headers
if err := WriteLengthPrefix(s, string(pr)); err != nil {
return err
}
}
return nil
}

View File

@ -6,7 +6,9 @@ import (
"time" "time"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
inet "github.com/jbenet/go-ipfs/net" inet "github.com/jbenet/go-ipfs/net"
netutil "github.com/jbenet/go-ipfs/net/ipfsnet/util"
) )
// TestConnectednessCorrect starts a few networks, connects a few // TestConnectednessCorrect starts a few networks, connects a few
@ -17,13 +19,13 @@ func TestConnectednessCorrect(t *testing.T) {
nets := make([]inet.Network, 4) nets := make([]inet.Network, 4)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
nets[i] = GenNetwork(t, ctx) nets[i] = netutil.GenNetwork(t, ctx)
} }
// connect 0-1, 0-2, 0-3, 1-2, 2-3 // connect 0-1, 0-2, 0-3, 1-2, 2-3
dial := func(a, b inet.Network) { dial := func(a, b inet.Network) {
DivulgeAddresses(b, a) netutil.DivulgeAddresses(b, a)
if err := a.DialPeer(ctx, b.LocalPeer()); err != nil { if err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
t.Fatalf("Failed to dial: %s", err) t.Fatalf("Failed to dial: %s", err)
} }

31
net/ipfsnet/util/util.go Normal file
View File

@ -0,0 +1,31 @@
package testutil
import (
"testing"
inet "github.com/jbenet/go-ipfs/net"
in "github.com/jbenet/go-ipfs/net/ipfsnet"
peer "github.com/jbenet/go-ipfs/peer"
tu "github.com/jbenet/go-ipfs/util/testutil"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
)
func GenNetwork(t *testing.T, ctx context.Context) *in.Network {
p := tu.RandPeerNetParamsOrFatal(t)
ps := peer.NewPeerstore()
ps.AddAddress(p.ID, p.Addr)
ps.AddPubKey(p.ID, p.PubKey)
ps.AddPrivKey(p.ID, p.PrivKey)
n, err := in.NewNetwork(ctx, ps.Addresses(p.ID), p.ID, ps)
if err != nil {
t.Fatal(err)
}
return n
}
func DivulgeAddresses(a, b inet.Network) {
id := a.LocalPeer()
addrs := a.Peerstore().Addresses(id)
b.Peerstore().AddAddresses(id, addrs)
}

View File

@ -6,6 +6,7 @@ import (
ic "github.com/jbenet/go-ipfs/crypto" ic "github.com/jbenet/go-ipfs/crypto"
inet "github.com/jbenet/go-ipfs/net" inet "github.com/jbenet/go-ipfs/net"
mux "github.com/jbenet/go-ipfs/net/services/mux"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
@ -86,7 +87,7 @@ func (c *conn) NewStreamWithProtocol(pr inet.ProtocolID) (inet.Stream, error) {
log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, c.remote) log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, c.remote)
s := c.openStream() s := c.openStream()
if err := inet.WriteProtocolHeader(pr, s); err != nil { if err := mux.WriteProtocolHeader(pr, s); err != nil {
s.Close() s.Close()
return nil, err return nil, err
} }

View File

@ -7,6 +7,8 @@ import (
ic "github.com/jbenet/go-ipfs/crypto" ic "github.com/jbenet/go-ipfs/crypto"
inet "github.com/jbenet/go-ipfs/net" inet "github.com/jbenet/go-ipfs/net"
ids "github.com/jbenet/go-ipfs/net/services/identify"
mux "github.com/jbenet/go-ipfs/net/services/mux"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
@ -28,8 +30,8 @@ type peernet struct {
connsByLink map[*link]map[*conn]struct{} connsByLink map[*link]map[*conn]struct{}
// needed to implement inet.Network // needed to implement inet.Network
mux inet.Mux mux mux.Mux
ids *inet.IDService ids *ids.IDService
cg ctxgroup.ContextGroup cg ctxgroup.ContextGroup
sync.RWMutex sync.RWMutex
@ -54,7 +56,7 @@ func newPeernet(ctx context.Context, m *mocknet, k ic.PrivKey,
mocknet: m, mocknet: m,
peer: p, peer: p,
ps: ps, ps: ps,
mux: inet.Mux{Handlers: inet.StreamHandlerMap{}}, mux: mux.Mux{Handlers: inet.StreamHandlerMap{}},
cg: ctxgroup.WithContext(ctx), cg: ctxgroup.WithContext(ctx),
connsByPeer: map[peer.ID]map[*conn]struct{}{}, connsByPeer: map[peer.ID]map[*conn]struct{}{},
@ -65,7 +67,7 @@ func newPeernet(ctx context.Context, m *mocknet, k ic.PrivKey,
// setup a conn handler that immediately "asks the other side about them" // setup a conn handler that immediately "asks the other side about them"
// this is ProtocolIdentify. // this is ProtocolIdentify.
n.ids = inet.NewIDService(n) n.ids = ids.NewIDService(n)
return n, nil return n, nil
} }
@ -338,6 +340,6 @@ func (pn *peernet) SetHandler(p inet.ProtocolID, h inet.StreamHandler) {
pn.mux.SetHandler(p, h) pn.mux.SetHandler(p, h)
} }
func (pn *peernet) IdentifyProtocol() *inet.IDService { func (pn *peernet) IdentifyProtocol() *ids.IDService {
return pn.ids return pn.ids
} }

View File

@ -1,15 +1,22 @@
package net package identify
import ( import (
"sync" "sync"
handshake "github.com/jbenet/go-ipfs/net/handshake"
pb "github.com/jbenet/go-ipfs/net/handshake/pb"
ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io" ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
inet "github.com/jbenet/go-ipfs/net"
handshake "github.com/jbenet/go-ipfs/net/handshake"
pb "github.com/jbenet/go-ipfs/net/handshake/pb"
eventlog "github.com/jbenet/go-ipfs/util/eventlog"
) )
var log = eventlog.Logger("net/identify")
// ProtocolIdentify is the ProtocolID of the Identify Service.
const ProtocolIdentify inet.ProtocolID = "/ipfs/identify"
// IDService is a structure that implements ProtocolIdentify. // IDService is a structure that implements ProtocolIdentify.
// It is a trivial service that gives the other peer some // It is a trivial service that gives the other peer some
// useful information about the local peer. A sort of hello. // useful information about the local peer. A sort of hello.
@ -19,24 +26,24 @@ import (
// * Our IPFS Agent Version // * Our IPFS Agent Version
// * Our public Listen Addresses // * Our public Listen Addresses
type IDService struct { type IDService struct {
Network Network Network inet.Network
// connections undergoing identification // connections undergoing identification
// for wait purposes // for wait purposes
currid map[Conn]chan struct{} currid map[inet.Conn]chan struct{}
currmu sync.RWMutex currmu sync.RWMutex
} }
func NewIDService(n Network) *IDService { func NewIDService(n inet.Network) *IDService {
s := &IDService{ s := &IDService{
Network: n, Network: n,
currid: make(map[Conn]chan struct{}), currid: make(map[inet.Conn]chan struct{}),
} }
n.SetHandler(ProtocolIdentify, s.RequestHandler) n.SetHandler(ProtocolIdentify, s.RequestHandler)
return s return s
} }
func (ids *IDService) IdentifyConn(c Conn) { func (ids *IDService) IdentifyConn(c inet.Conn) {
ids.currmu.Lock() ids.currmu.Lock()
if wait, found := ids.currid[c]; found { if wait, found := ids.currid[c]; found {
ids.currmu.Unlock() ids.currmu.Unlock()
@ -70,7 +77,7 @@ func (ids *IDService) IdentifyConn(c Conn) {
close(ch) // release everyone waiting. close(ch) // release everyone waiting.
} }
func (ids *IDService) RequestHandler(s Stream) { func (ids *IDService) RequestHandler(s inet.Stream) {
defer s.Close() defer s.Close()
c := s.Conn() c := s.Conn()
@ -83,7 +90,7 @@ func (ids *IDService) RequestHandler(s Stream) {
c.RemotePeer(), c.RemoteMultiaddr()) c.RemotePeer(), c.RemoteMultiaddr())
} }
func (ids *IDService) ResponseHandler(s Stream) { func (ids *IDService) ResponseHandler(s inet.Stream) {
defer s.Close() defer s.Close()
c := s.Conn() c := s.Conn()
@ -100,7 +107,7 @@ func (ids *IDService) ResponseHandler(s Stream) {
c.RemotePeer(), c.RemoteMultiaddr()) c.RemotePeer(), c.RemoteMultiaddr())
} }
func (ids *IDService) populateMessage(mes *pb.Handshake3, c Conn) { func (ids *IDService) populateMessage(mes *pb.Handshake3, c inet.Conn) {
// set protocols this node is currently handling // set protocols this node is currently handling
protos := ids.Network.Protocols() protos := ids.Network.Protocols()
@ -129,7 +136,7 @@ func (ids *IDService) populateMessage(mes *pb.Handshake3, c Conn) {
mes.H1 = handshake.NewHandshake1("", "") mes.H1 = handshake.NewHandshake1("", "")
} }
func (ids *IDService) consumeMessage(mes *pb.Handshake3, c Conn) { func (ids *IDService) consumeMessage(mes *pb.Handshake3, c inet.Conn) {
p := c.RemotePeer() p := c.RemotePeer()
// mes.Protocols // mes.Protocols
@ -164,7 +171,7 @@ func (ids *IDService) consumeMessage(mes *pb.Handshake3, c Conn) {
// This happens async so the connection can start to be used // This happens async so the connection can start to be used
// even if handshake3 knowledge is not necesary. // even if handshake3 knowledge is not necesary.
// Users **MUST** call IdentifyWait _after_ IdentifyConn // Users **MUST** call IdentifyWait _after_ IdentifyConn
func (ids *IDService) IdentifyWait(c Conn) <-chan struct{} { func (ids *IDService) IdentifyWait(c inet.Conn) <-chan struct{} {
ids.currmu.Lock() ids.currmu.Lock()
ch, found := ids.currid[c] ch, found := ids.currid[c]
ids.currmu.Unlock() ids.currmu.Unlock()

View File

@ -1,4 +1,4 @@
package net_test package identify_test
import ( import (
"testing" "testing"
@ -6,38 +6,19 @@ import (
inet "github.com/jbenet/go-ipfs/net" inet "github.com/jbenet/go-ipfs/net"
handshake "github.com/jbenet/go-ipfs/net/handshake" handshake "github.com/jbenet/go-ipfs/net/handshake"
netutil "github.com/jbenet/go-ipfs/net/ipfsnet/util"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
testutil "github.com/jbenet/go-ipfs/util/testutil"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
) )
func GenNetwork(t *testing.T, ctx context.Context) inet.Network {
p := testutil.RandPeerNetParamsOrFatal(t)
ps := peer.NewPeerstore()
ps.AddAddress(p.ID, p.Addr)
ps.AddPubKey(p.ID, p.PubKey)
ps.AddPrivKey(p.ID, p.PrivKey)
n, err := inet.NewNetwork(ctx, ps.Addresses(p.ID), p.ID, ps)
if err != nil {
t.Fatal(err)
}
return n
}
func DivulgeAddresses(a, b inet.Network) {
id := a.LocalPeer()
addrs := a.Peerstore().Addresses(id)
b.Peerstore().AddAddresses(id, addrs)
}
func subtestIDService(t *testing.T, postDialWait time.Duration) { func subtestIDService(t *testing.T, postDialWait time.Duration) {
// the generated networks should have the id service wired in. // the generated networks should have the id service wired in.
ctx := context.Background() ctx := context.Background()
n1 := GenNetwork(t, ctx) n1 := netutil.GenNetwork(t, ctx)
n2 := GenNetwork(t, ctx) n2 := netutil.GenNetwork(t, ctx)
n1p := n1.LocalPeer() n1p := n1.LocalPeer()
n2p := n2.LocalPeer() n2p := n2.LocalPeer()
@ -46,7 +27,7 @@ func subtestIDService(t *testing.T, postDialWait time.Duration) {
testKnowsAddrs(t, n2, n1p, []ma.Multiaddr{}) // nothing testKnowsAddrs(t, n2, n1p, []ma.Multiaddr{}) // nothing
// have n2 tell n1, so we can dial... // have n2 tell n1, so we can dial...
DivulgeAddresses(n2, n1) netutil.DivulgeAddresses(n2, n1)
testKnowsAddrs(t, n1, n2p, n2.Peerstore().Addresses(n2p)) // has them testKnowsAddrs(t, n1, n2p, n2.Peerstore().Addresses(n2p)) // has them
testKnowsAddrs(t, n2, n1p, []ma.Multiaddr{}) // nothing testKnowsAddrs(t, n2, n1p, []ma.Multiaddr{}) // nothing

View File

@ -1,4 +1,4 @@
package net package mux
import ( import (
"fmt" "fmt"
@ -6,11 +6,13 @@ import (
"sync" "sync"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
inet "github.com/jbenet/go-ipfs/net"
eventlog "github.com/jbenet/go-ipfs/util/eventlog" eventlog "github.com/jbenet/go-ipfs/util/eventlog"
lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables" lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
) )
var log = eventlog.Logger("network") var log = eventlog.Logger("net/mux")
// Mux provides simple stream multixplexing. // Mux provides simple stream multixplexing.
// It helps you precisely when: // It helps you precisely when:
@ -30,16 +32,16 @@ var log = eventlog.Logger("network")
// WARNING: this datastructure IS NOT threadsafe. // WARNING: this datastructure IS NOT threadsafe.
// do not modify it once the network is using it. // do not modify it once the network is using it.
type Mux struct { type Mux struct {
Default StreamHandler // handles unknown protocols. Default inet.StreamHandler // handles unknown protocols.
Handlers StreamHandlerMap Handlers inet.StreamHandlerMap
sync.RWMutex sync.RWMutex
} }
// Protocols returns the list of protocols this muxer has handlers for // Protocols returns the list of protocols this muxer has handlers for
func (m *Mux) Protocols() []ProtocolID { func (m *Mux) Protocols() []inet.ProtocolID {
m.RLock() m.RLock()
l := make([]ProtocolID, 0, len(m.Handlers)) l := make([]inet.ProtocolID, 0, len(m.Handlers))
for p := range m.Handlers { for p := range m.Handlers {
l = append(l, p) l = append(l, p)
} }
@ -49,7 +51,7 @@ func (m *Mux) Protocols() []ProtocolID {
// ReadProtocolHeader reads the stream and returns the next Handler function // ReadProtocolHeader reads the stream and returns the next Handler function
// according to the muxer encoding. // according to the muxer encoding.
func (m *Mux) ReadProtocolHeader(s io.Reader) (string, StreamHandler, error) { func (m *Mux) ReadProtocolHeader(s io.Reader) (string, inet.StreamHandler, error) {
// log.Error("ReadProtocolHeader") // log.Error("ReadProtocolHeader")
name, err := ReadLengthPrefix(s) name, err := ReadLengthPrefix(s)
if err != nil { if err != nil {
@ -58,7 +60,7 @@ func (m *Mux) ReadProtocolHeader(s io.Reader) (string, StreamHandler, error) {
// log.Debug("ReadProtocolHeader got:", name) // log.Debug("ReadProtocolHeader got:", name)
m.RLock() m.RLock()
h, found := m.Handlers[ProtocolID(name)] h, found := m.Handlers[inet.ProtocolID(name)]
m.RUnlock() m.RUnlock()
switch { switch {
@ -80,7 +82,7 @@ func (m *Mux) String() string {
// SetHandler sets the protocol handler on the Network's Muxer. // SetHandler sets the protocol handler on the Network's Muxer.
// This operation is threadsafe. // This operation is threadsafe.
func (m *Mux) SetHandler(p ProtocolID, h StreamHandler) { func (m *Mux) SetHandler(p inet.ProtocolID, h inet.StreamHandler) {
log.Debugf("%s setting handler for protocol: %s (%d)", m, p, len(p)) log.Debugf("%s setting handler for protocol: %s (%d)", m, p, len(p))
m.Lock() m.Lock()
m.Handlers[p] = h m.Handlers[p] = h
@ -88,7 +90,8 @@ func (m *Mux) SetHandler(p ProtocolID, h StreamHandler) {
} }
// Handle reads the next name off the Stream, and calls a function // Handle reads the next name off the Stream, and calls a function
func (m *Mux) Handle(s Stream) { func (m *Mux) Handle(s inet.Stream) {
ctx := context.Background() ctx := context.Background()
name, handler, err := m.ReadProtocolHeader(s) name, handler, err := m.ReadProtocolHeader(s)
@ -133,3 +136,14 @@ func WriteLengthPrefix(w io.Writer, name string) error {
_, err := w.Write(s) _, err := w.Write(s)
return err return err
} }
// WriteProtocolHeader defines how a protocol is written into the header of
// a stream. This is so the muxer can multiplex between services.
func WriteProtocolHeader(pr inet.ProtocolID, s inet.Stream) error {
if pr != "" { // only write proper protocol headers
if err := WriteLengthPrefix(s, string(pr)); err != nil {
return err
}
}
return nil
}

View File

@ -1,8 +1,10 @@
package net package mux
import ( import (
"bytes" "bytes"
"testing" "testing"
inet "github.com/jbenet/go-ipfs/net"
) )
var testCases = map[string]string{ var testCases = map[string]string{
@ -28,13 +30,13 @@ func TestHandler(t *testing.T) {
outs := make(chan string, 10) outs := make(chan string, 10)
h := func(n string) func(s Stream) { h := func(n string) func(s inet.Stream) {
return func(s Stream) { return func(s inet.Stream) {
outs <- n outs <- n
} }
} }
m := Mux{Handlers: StreamHandlerMap{}} m := Mux{Handlers: inet.StreamHandlerMap{}}
m.Default = h("default") m.Default = h("default")
m.Handlers["dht"] = h("bitswap") m.Handlers["dht"] = h("bitswap")
// m.Handlers["ipfs"] = h("bitswap") // default! // m.Handlers["ipfs"] = h("bitswap") // default!

View File

@ -14,7 +14,7 @@ import (
dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync" dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
inet "github.com/jbenet/go-ipfs/net" ipfsnet "github.com/jbenet/go-ipfs/net/ipfsnet"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
routing "github.com/jbenet/go-ipfs/routing" routing "github.com/jbenet/go-ipfs/routing"
u "github.com/jbenet/go-ipfs/util" u "github.com/jbenet/go-ipfs/util"
@ -49,7 +49,7 @@ func setupDHT(ctx context.Context, t *testing.T, addr ma.Multiaddr) *IpfsDHT {
peerstore.AddPubKey(p, pk) peerstore.AddPubKey(p, pk)
peerstore.AddAddress(p, addr) peerstore.AddAddress(p, addr)
n, err := inet.NewNetwork(ctx, []ma.Multiaddr{addr}, p, peerstore) n, err := ipfsnet.NewNetwork(ctx, []ma.Multiaddr{addr}, p, peerstore)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }