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

import (
4
	"fmt"
5 6
	"net"

7 8
	msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 10
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
11 12
)

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
13
// ChanBuffer is the size of the buffer in the Conn Chan
14 15
const ChanBuffer = 10

16 17
// 1 MB
const MaxMessageSize = 1 << 20
18

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
19
// Conn represents a connection to another Peer (IPFS Node).
20
type Conn struct {
21 22 23
	Peer *peer.Peer
	Addr *ma.Multiaddr
	Conn net.Conn
24

25 26 27
	Closed   chan bool
	Outgoing *msgio.Chan
	Incoming *msgio.Chan
28 29
	secIn    <-chan []byte
	secOut   chan<- []byte
30 31
}

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

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
// NewConn constructs a new connection
func NewConn(peer *peer.Peer, addr *ma.Multiaddr, nconn net.Conn) (*Conn, error) {
	conn := &Conn{
		Peer: peer,
		Addr: addr,
		Conn: nconn,
	}

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

	return conn, nil
}

// NewNetConn constructs a new connection with given net.Conn
func NewNetConn(nconn net.Conn) (*Conn, error) {

	addr, err := ma.FromNetAddr(nconn.RemoteAddr())
	if err != nil {
		return nil, err
	}

	return NewConn(new(peer.Peer), addr, nconn)
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
61 62
// Dial connects to a particular peer, over a given network
// Example: Dial("udp", peer)
63
func Dial(network string, peer *peer.Peer) (*Conn, error) {
64 65 66 67
	addr := peer.NetAddress(network)
	if addr == nil {
		return nil, fmt.Errorf("No address for network %s", network)
	}
68

69 70 71 72
	network, host, err := addr.DialArgs()
	if err != nil {
		return nil, err
	}
73

74 75 76 77
	nconn, err := net.Dial(network, host)
	if err != nil {
		return nil, err
	}
78

79
	return NewConn(peer, addr, nconn)
80 81 82
}

// Construct new channels for given Conn.
83
func (c *Conn) newChans() error {
84 85
	if c.Outgoing != nil || c.Incoming != nil {
		return fmt.Errorf("Conn already initialized")
86
	}
87

88 89 90
	c.Outgoing = msgio.NewChan(10)
	c.Incoming = msgio.NewChan(10)
	c.Closed = make(chan bool, 1)
91

92
	go c.Outgoing.WriteTo(c.Conn)
93
	go c.Incoming.ReadFrom(c.Conn, MaxMessageSize)
94 95

	return nil
96 97
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
98
// Close closes the connection, and associated channels.
99
func (c *Conn) Close() error {
100
	u.DOut("Closing Conn.\n")
101
	if c.Conn == nil {
102
		return fmt.Errorf("Already closed") // already closed
103
	}
104

105
	// closing net connection
106 107
	err := c.Conn.Close()
	c.Conn = nil
108
	// closing channels
109 110 111
	c.Incoming.Close()
	c.Outgoing.Close()
	c.Closed <- true
112
	return err
113
}