net.go 5.74 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1
// Package net provides an interface for ipfs to interact with the network through
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
2 3 4
package net

import (
5
	swarm "github.com/jbenet/go-ipfs/net/swarm2"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
6 7
	peer "github.com/jbenet/go-ipfs/peer"

8
	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
9
	ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
10
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11 12
)

13
type stream swarm.Stream
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14

15 16 17
func (s *stream) SwarmStream() *swarm.Stream {
	return (*swarm.Stream)(s)
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18

19 20 21 22 23
// Conn returns the connection this stream is part of.
func (s *stream) Conn() Conn {
	c := s.SwarmStream().Conn()
	return (*conn_)(c)
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24

25 26 27 28
// Conn returns the connection this stream is part of.
func (s *stream) Close() error {
	return s.SwarmStream().Close()
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29

30 31 32
// Read reads bytes from a stream.
func (s *stream) Read(p []byte) (n int, err error) {
	return s.SwarmStream().Read(p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
33 34
}

35 36 37 38
// Write writes bytes to a stream, flushing for each call.
func (s *stream) Write(p []byte) (n int, err error) {
	return s.SwarmStream().Write(p)
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39

40
type conn_ swarm.Conn
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41

42 43 44 45
func (c *conn_) SwarmConn() *swarm.Conn {
	return (*swarm.Conn)(c)
}

46
func (c *conn_) NewStreamWithProtocol(pr ProtocolID, p peer.Peer) (Stream, error) {
47
	s, err := (*swarm.Conn)(c).NewStream()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
48 49 50
	if err != nil {
		return nil, err
	}
51 52 53

	ss := (*stream)(s)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54
	if err := WriteProtocolHeader(pr, ss); err != nil {
55 56 57 58 59
		ss.Close()
		return nil, err
	}

	return ss, nil
60
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
61

62 63 64 65
// LocalMultiaddr is the Multiaddr on this side
func (c *conn_) LocalMultiaddr() ma.Multiaddr {
	return c.SwarmConn().LocalMultiaddr()
}
66

67 68 69 70
// LocalPeer is the Peer on our side of the connection
func (c *conn_) LocalPeer() peer.Peer {
	return c.SwarmConn().LocalPeer()
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71

72 73 74
// RemoteMultiaddr is the Multiaddr on the remote side
func (c *conn_) RemoteMultiaddr() ma.Multiaddr {
	return c.SwarmConn().RemoteMultiaddr()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
75 76
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90
// RemotePeer is the Peer on the remote side
func (c *conn_) RemotePeer() peer.Peer {
	return c.SwarmConn().RemotePeer()
}

// network implements the Network interface,
type network struct {
	local peer.Peer    // local peer
	mux   Mux          // protocol multiplexing
	swarm *swarm.Swarm // peer connection multiplexing

	cg ctxgroup.ContextGroup // for Context closing
}

91 92
// NewNetwork constructs a new network and starts listening on given addresses.
func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.Peer,
93
	peers peer.Peerstore) (Network, error) {
94 95 96 97 98 99 100 101 102

	s, err := swarm.NewSwarm(ctx, listen, local, peers)
	if err != nil {
		return nil, err
	}

	n := &network{
		local: local,
		swarm: s,
103
		mux:   Mux{Handlers: StreamHandlerMap{}},
104 105 106 107
		cg:    ctxgroup.WithContext(ctx),
	}

	s.SetStreamHandler(func(s *swarm.Stream) {
108
		n.mux.Handle((*stream)(s))
109 110
	})

111
	n.cg.SetTeardown(n.close)
112 113 114
	n.cg.AddChildGroup(s.CtxGroup())
	return n, nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
115

116 117
// DialPeer attempts to establish a connection to a given peer.
// Respects the context.
118
func (n *network) DialPeer(ctx context.Context, p peer.Peer) error {
119
	_, err := n.swarm.Dial(ctx, p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121 122
	return err
}

123 124 125 126 127 128 129 130 131 132
// CtxGroup returns the network's ContextGroup
func (n *network) CtxGroup() ctxgroup.ContextGroup {
	return n.cg
}

// Swarm returns the network's peerstream.Swarm
func (n *network) Swarm() *swarm.Swarm {
	return n.Swarm()
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
133
// LocalPeer the network's LocalPeer
134
func (n *network) LocalPeer() peer.Peer {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
135 136 137
	return n.swarm.LocalPeer()
}

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
// Peers returns the connected peers
func (n *network) Peers() []peer.Peer {
	return n.swarm.Peers()
}

// Conns returns the connected peers
func (n *network) Conns() []Conn {
	conns1 := n.swarm.Connections()
	out := make([]Conn, len(conns1))
	for i, c := range conns1 {
		out[i] = (*conn_)(c)
	}
	return out
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
153
// ClosePeer connection to peer
154
func (n *network) ClosePeer(p peer.Peer) error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
155 156 157
	return n.swarm.CloseConnection(p)
}

158 159 160 161 162 163 164 165 166 167
// close is the real teardown function
func (n *network) close() error {
	return n.swarm.Close()
}

// Close calls the ContextCloser func
func (n *network) Close() error {
	return n.cg.Close()
}

168 169 170 171 172
// BandwidthTotals returns the total amount of bandwidth transferred
func (n *network) BandwidthTotals() (in uint64, out uint64) {
	// need to implement this. probably best to do it in swarm this time.
	// need a "metrics" object
	return 0, 0
Jeromy's avatar
Jeromy committed
173 174
}

175
// ListenAddresses returns a list of addresses at which this network listens.
176
func (n *network) ListenAddresses() []ma.Multiaddr {
177 178 179 180 181 182
	return n.swarm.ListenAddresses()
}

// InterfaceListenAddresses returns a list of addresses at which this network
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces.
183 184
func (n *network) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
	return swarm.InterfaceListenAddresses(n.swarm)
185
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
186 187

// Connectedness returns a state signaling connection capabilities
Brian Tiger Chow's avatar
Brian Tiger Chow committed
188
// For now only returns Connected || NotConnected. Expand into more later.
189 190 191
func (n *network) Connectedness(p peer.Peer) Connectedness {
	c := n.swarm.ConnectionsToPeer(p)
	if c != nil && len(c) < 1 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
192 193 194 195
		return Connected
	}
	return NotConnected
}
196

197 198 199
// NewStream returns a new stream to given peer p.
// If there is no connection to p, attempts to create one.
// If ProtocolID is "", writes no header.
200
func (c *network) NewStream(pr ProtocolID, p peer.Peer) (Stream, error) {
201 202 203 204 205 206 207
	s, err := c.swarm.NewStreamWithPeer(p)
	if err != nil {
		return nil, err
	}

	ss := (*stream)(s)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
208
	if err := WriteProtocolHeader(pr, ss); err != nil {
209 210 211 212 213 214 215
		ss.Close()
		return nil, err
	}

	return ss, nil
}

216 217 218 219 220
// SetHandler sets the protocol handler on the Network's Muxer.
// This operation is threadsafe.
func (n *network) SetHandler(p ProtocolID, h StreamHandler) {
	n.mux.SetHandler(p, h)
}
221

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
222
func WriteProtocolHeader(pr ProtocolID, s Stream) error {
223 224 225 226 227 228 229
	if pr != "" { // only write proper protocol headers
		if err := WriteLengthPrefix(s, string(pr)); err != nil {
			return err
		}
	}
	return nil
}