handshake.go 2.49 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 29 30 31 32 33 34

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

	c.Out() <- myVerBytes
	log.Debug("Sent my version (%s) to %s", localH, rpeer)

	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 {
53 54 55 56 57 58 59
		log.Info("%s (%s) incompatible version with %s (%s)", lpeer, localH, rpeer, remoteH)
		return err
	}

	log.Debug("%s version handshake compatible %s", lpeer, rpeer)
	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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

// 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
	log.Debug("Handshake1: sent to %s", rpeer)

	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)
		}

		log.Debug("Handshake3 received from %s", rpeer)
	}

	if err := handshake.Handshake3UpdatePeer(rpeer, remoteH); err != nil {
		log.Error("Handshake3 failed to update %s", rpeer)
		return err
	}

	return nil
}