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

import (
4
	"fmt"
5

6
	msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
7
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8 9

	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
10 11
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
12 13
)

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

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
16
// ChanBuffer is the size of the buffer in the Conn Chan
17 18
const ChanBuffer = 10

19 20
// 1 MB
const MaxMessageSize = 1 << 20
21

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
22
// Conn represents a connection to another Peer (IPFS Node).
23
type Conn struct {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25 26
	Local  *peer.Peer
	Remote *peer.Peer
	Conn   manet.Conn
27

28 29 30
	Closed   chan bool
	Outgoing *msgio.Chan
	Incoming *msgio.Chan
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
31
	Secure   *spipe.SecurePipe
32 33
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
34 35
// Map maps Keys (Peer.IDs) to Connections.
type Map map[u.Key]*Conn
36

37
// NewConn constructs a new connection
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38
func NewConn(local, remote *peer.Peer, mconn manet.Conn) (*Conn, error) {
39
	conn := &Conn{
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
40 41 42
		Local:  local,
		Remote: remote,
		Conn:   mconn,
43 44 45 46 47 48 49 50 51
	}

	if err := conn.newChans(); err != nil {
		return nil, err
	}

	return conn, nil
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
52 53
// Dial connects to a particular peer, over a given network
// Example: Dial("udp", peer)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54 55 56 57
func Dial(network string, local, remote *peer.Peer) (*Conn, error) {
	laddr := local.NetAddress(network)
	if laddr == nil {
		return nil, fmt.Errorf("No local address for network %s", network)
58
	}
59

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
60 61 62 63 64 65 66 67 68 69 70
	raddr := remote.NetAddress(network)
	if raddr == nil {
		return nil, fmt.Errorf("No remote address for network %s", network)
	}

	// TODO: try to get reusing addr/ports to work.
	// dialer := manet.Dialer{LocalAddr: laddr}
	dialer := manet.Dialer{}

	log.Info("%s %s dialing %s %s", local, laddr, remote, raddr)
	nconn, err := dialer.Dial(raddr)
71 72 73
	if err != nil {
		return nil, err
	}
74

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
75
	return NewConn(local, remote, nconn)
76 77 78
}

// Construct new channels for given Conn.
79
func (c *Conn) newChans() error {
80 81
	if c.Outgoing != nil || c.Incoming != nil {
		return fmt.Errorf("Conn already initialized")
82
	}
83

84 85 86
	c.Outgoing = msgio.NewChan(10)
	c.Incoming = msgio.NewChan(10)
	c.Closed = make(chan bool, 1)
87

88
	go c.Outgoing.WriteTo(c.Conn)
89
	go c.Incoming.ReadFrom(c.Conn, MaxMessageSize)
90 91

	return nil
92 93
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
94
// Close closes the connection, and associated channels.
95
func (c *Conn) Close() error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96
	log.Debug("%s closing Conn with %s", c.Local, c.Remote)
97
	if c.Conn == nil {
98
		return fmt.Errorf("Already closed") // already closed
99
	}
100

101
	// closing net connection
102 103
	err := c.Conn.Close()
	c.Conn = nil
104
	// closing channels
105 106 107
	c.Incoming.Close()
	c.Outgoing.Close()
	c.Closed <- true
108
	return err
109
}