conn.go 3.69 KB
Newer Older
1
package conn
2 3

import (
4
	"fmt"
5
	"time"
6

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

12 13
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
14 15
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
16 17
var log = u.Logger("conn")

18 19 20
const (
	// ChanBuffer is the size of the buffer in the Conn Chan
	ChanBuffer = 10
21

22 23 24 25 26 27
	// MaxMessageSize is the size of the largest single message
	MaxMessageSize = 1 << 20 // 1 MB

	// HandshakeTimeout for when nodes first connect
	HandshakeTimeout = time.Second * 5
)
28

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29 30 31 32 33
// msgioPipe is a pipe using msgio channels.
type msgioPipe struct {
	outgoing *msgio.Chan
	incoming *msgio.Chan
}
34

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35 36 37 38 39 40 41 42 43 44 45 46
func newMsgioPipe(size int) *msgioPipe {
	return &msgioPipe{
		outgoing: msgio.NewChan(10),
		incoming: msgio.NewChan(10),
	}
}

// singleConn represents a single connection to another Peer (IPFS Node).
type singleConn struct {
	local  *peer.Peer
	remote *peer.Peer
	maconn manet.Conn
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47
	msgio  *msgioPipe
48 49

	ContextCloser
50 51
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
52 53
// newConn constructs a new connection
func newSingleConn(ctx context.Context, local, remote *peer.Peer,
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54
	maconn manet.Conn) (Conn, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55 56

	conn := &singleConn{
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
57 58 59 60
		local:  local,
		remote: remote,
		maconn: maconn,
		msgio:  newMsgioPipe(10),
61 62
	}

63 64
	conn.ContextCloser = NewContextCloser(ctx, conn.close)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65 66 67
	log.Info("newSingleConn: %v to %v", local, remote)

	// setup the various io goroutines
68 69 70 71 72 73 74 75 76 77
	go func() {
		conn.Children().Add(1)
		conn.msgio.outgoing.WriteTo(maconn)
		conn.Children().Done()
	}()
	go func() {
		conn.Children().Add(1)
		conn.msgio.incoming.ReadFrom(maconn, MaxMessageSize)
		conn.Children().Done()
	}()
78

79 80 81 82 83 84 85
	// version handshake
	ctxT, _ := context.WithTimeout(ctx, HandshakeTimeout)
	if err := VersionHandshake(ctxT, conn); err != nil {
		conn.Close()
		return nil, fmt.Errorf("Version handshake: %s", err)
	}

86 87 88
	return conn, nil
}

89 90 91
// close is the internal close function, called by ContextCloser.Close
func (c *singleConn) close() error {
	log.Debug("%s closing Conn with %s", c.local, c.remote)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92 93

	// close underlying connection
94
	err := c.maconn.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95
	c.msgio.outgoing.Close()
96
	return err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
97 98
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99 100 101 102 103
// ID is an identifier unique to this connection.
func (c *singleConn) ID() string {
	return ID(c)
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
104 105 106 107
func (c *singleConn) String() string {
	return String(c, "singleConn")
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
108 109 110 111 112 113 114 115 116 117
// LocalMultiaddr is the Multiaddr on this side
func (c *singleConn) LocalMultiaddr() ma.Multiaddr {
	return c.maconn.LocalMultiaddr()
}

// RemoteMultiaddr is the Multiaddr on the remote side
func (c *singleConn) RemoteMultiaddr() ma.Multiaddr {
	return c.maconn.RemoteMultiaddr()
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
118 119 120 121 122 123 124 125 126 127
// LocalPeer is the Peer on this side
func (c *singleConn) LocalPeer() *peer.Peer {
	return c.local
}

// RemotePeer is the Peer on the remote side
func (c *singleConn) RemotePeer() *peer.Peer {
	return c.remote
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
128 129
// In returns a readable message channel
func (c *singleConn) In() <-chan []byte {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
130
	return c.msgio.incoming.MsgChan
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
131 132
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
133 134
// Out returns a writable message channel
func (c *singleConn) Out() chan<- []byte {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
135
	return c.msgio.outgoing.MsgChan
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
136 137
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
138
// ID returns the ID of a given Conn.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
139 140 141 142 143 144 145 146 147
func ID(c Conn) string {
	l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().ID)
	r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().ID)
	lh := u.Hash([]byte(l))
	rh := u.Hash([]byte(r))
	ch := u.XOR(lh, rh)
	return u.Key(ch).Pretty()
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
148 149 150 151
// String returns the user-friendly String representation of a conn
func String(c Conn, typ string) string {
	return fmt.Sprintf("%s (%s) <-- %s --> (%s) %s",
		c.LocalPeer(), c.LocalMultiaddr(), typ, c.RemoteMultiaddr(), c.RemotePeer())
152
}