conn.go 3.74 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"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14
	ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
15 16
)

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

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

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

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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36 37 38 39 40 41 42 43 44
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 {
45 46
	local  peer.Peer
	remote peer.Peer
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47
	maconn manet.Conn
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
48
	msgio  *msgioPipe
49

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
50
	ctxc.ContextCloser
51 52
}

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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64
	conn.ContextCloser = ctxc.NewContextCloser(ctx, conn.close)
65

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

	// setup the various io goroutines
69 70 71 72 73 74 75 76 77 78
	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()
	}()
79

80 81
	// version handshake
	ctxT, _ := context.WithTimeout(ctx, HandshakeTimeout)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82
	if err := Handshake1(ctxT, conn); err != nil {
83
		conn.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
84
		return nil, fmt.Errorf("Handshake1 failed: %s", err)
85 86
	}

87 88 89
	return conn, nil
}

90 91 92
// 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
93 94

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
100 101 102 103 104
// 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
105 106 107 108
func (c *singleConn) String() string {
	return String(c, "singleConn")
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
109 110 111 112 113 114 115 116 117 118
// 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
119
// LocalPeer is the Peer on this side
120
func (c *singleConn) LocalPeer() peer.Peer {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
121 122 123 124
	return c.local
}

// RemotePeer is the Peer on the remote side
125
func (c *singleConn) RemotePeer() peer.Peer {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
126 127 128
	return c.remote
}

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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
139
// ID returns the ID of a given Conn.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
140
func ID(c Conn) string {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
141 142
	l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().ID())
	r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().ID())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
143 144 145 146 147 148
	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
149 150 151 152
// 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())
153
}