handshake.go 2.5 KB
Newer Older
1 2 3 4 5 6 7
package conn

import (
	"errors"
	"fmt"

	handshake "github.com/jbenet/go-ipfs/net/handshake"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8
	hspb "github.com/jbenet/go-ipfs/net/handshake/pb"
9 10 11 12 13

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14
// Handshake1 exchanges local and remote versions and compares them
15
// closes remote and returns an error in case of major difference
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
16
func Handshake1(ctx context.Context, c Conn) error {
17 18 19
	rpeer := c.RemotePeer()
	lpeer := c.LocalPeer()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20 21
	var remoteH, localH *hspb.Handshake1
	localH = handshake.Handshake1Msg()
22 23 24 25 26 27 28

	myVerBytes, err := proto.Marshal(localH)
	if err != nil {
		return err
	}

	c.Out() <- myVerBytes
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29
	log.Debugf("Sent my version (%s) to %s", localH, rpeer)
30 31 32 33 34

	select {
	case <-ctx.Done():
		return ctx.Err()

35
	case <-c.Closing():
36 37 38 39 40 41 42
		return errors.New("remote closed connection during version exchange")

	case data, ok := <-c.In():
		if !ok {
			return fmt.Errorf("error retrieving from conn: %v", rpeer)
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43
		remoteH = new(hspb.Handshake1)
44 45 46 47 48 49 50 51
		err = proto.Unmarshal(data, remoteH)
		if err != nil {
			return fmt.Errorf("could not decode remote version: %q", err)
		}

		log.Debug("Received remote version (%s) from %s", remoteH, rpeer)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
52
	if err := handshake.Handshake1Compatible(localH, remoteH); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
53
		log.Infof("%s (%s) incompatible version with %s (%s)", lpeer, localH, rpeer, remoteH)
54 55 56
		return err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
57
	log.Debugf("%s version handshake compatible %s", lpeer, rpeer)
58 59
	return nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73

// Handshake3 exchanges local and remote service information
func Handshake3(ctx context.Context, c Conn) error {
	rpeer := c.RemotePeer()
	lpeer := c.LocalPeer()

	var remoteH, localH *hspb.Handshake3
	localH = handshake.Handshake3Msg(lpeer)
	localB, err := proto.Marshal(localH)
	if err != nil {
		return err
	}

	c.Out() <- localB
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
74
	log.Debugf("Handshake1: sent to %s", rpeer)
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 91 92 93

	select {
	case <-ctx.Done():
		return ctx.Err()

	case <-c.Closing():
		return errors.New("Handshake3: error remote connection closed")

	case remoteB, ok := <-c.In():
		if !ok {
			return fmt.Errorf("Handshake3 error receiving from conn: %v", rpeer)
		}

		remoteH = new(hspb.Handshake3)
		err = proto.Unmarshal(remoteB, remoteH)
		if err != nil {
			return fmt.Errorf("Handshake3 could not decode remote msg: %q", err)
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
94
		log.Debugf("Handshake3 received from %s", rpeer)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95 96 97
	}

	if err := handshake.Handshake3UpdatePeer(rpeer, remoteH); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
98
		log.Errorf("Handshake3 failed to update %s", rpeer)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99 100 101 102 103
		return err
	}

	return nil
}