github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/net/conn/handshake.go (about)

     1  package conn
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	handshake "github.com/jbenet/go-ipfs/net/handshake"
     8  	hspb "github.com/jbenet/go-ipfs/net/handshake/pb"
     9  
    10  	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
    11  	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
    12  )
    13  
    14  // Handshake1 exchanges local and remote versions and compares them
    15  // closes remote and returns an error in case of major difference
    16  func Handshake1(ctx context.Context, c Conn) error {
    17  	rpeer := c.RemotePeer()
    18  	lpeer := c.LocalPeer()
    19  
    20  	var remoteH, localH *hspb.Handshake1
    21  	localH = handshake.Handshake1Msg()
    22  
    23  	myVerBytes, err := proto.Marshal(localH)
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	c.Out() <- myVerBytes
    29  	log.Debugf("Sent my version (%s) to %s", localH, rpeer)
    30  
    31  	select {
    32  	case <-ctx.Done():
    33  		return ctx.Err()
    34  
    35  	case <-c.Closing():
    36  		return errors.New("remote closed connection during version exchange")
    37  
    38  	case data, ok := <-c.In():
    39  		if !ok {
    40  			return fmt.Errorf("error retrieving from conn: %v", rpeer)
    41  		}
    42  
    43  		remoteH = new(hspb.Handshake1)
    44  		err = proto.Unmarshal(data, remoteH)
    45  		if err != nil {
    46  			return fmt.Errorf("could not decode remote version: %q", err)
    47  		}
    48  
    49  		log.Debugf("Received remote version (%s) from %s", remoteH, rpeer)
    50  	}
    51  
    52  	if err := handshake.Handshake1Compatible(localH, remoteH); err != nil {
    53  		log.Infof("%s (%s) incompatible version with %s (%s)", lpeer, localH, rpeer, remoteH)
    54  		return err
    55  	}
    56  
    57  	log.Debugf("%s version handshake compatible %s", lpeer, rpeer)
    58  	return nil
    59  }
    60  
    61  // Handshake3 exchanges local and remote service information
    62  func Handshake3(ctx context.Context, c Conn) (*handshake.Handshake3Result, error) {
    63  	rpeer := c.RemotePeer()
    64  	lpeer := c.LocalPeer()
    65  
    66  	// setup + send the message to remote
    67  	var remoteH, localH *hspb.Handshake3
    68  	localH = handshake.Handshake3Msg(lpeer, c.RemoteMultiaddr())
    69  	localB, err := proto.Marshal(localH)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	c.Out() <- localB
    75  	log.Debugf("Handshake1: sent to %s", rpeer)
    76  
    77  	// wait + listen for response
    78  	select {
    79  	case <-ctx.Done():
    80  		return nil, ctx.Err()
    81  
    82  	case <-c.Closing():
    83  		return nil, errors.New("Handshake3: error remote connection closed")
    84  
    85  	case remoteB, ok := <-c.In():
    86  		if !ok {
    87  			return nil, fmt.Errorf("Handshake3 error receiving from conn: %v", rpeer)
    88  		}
    89  
    90  		remoteH = new(hspb.Handshake3)
    91  		err = proto.Unmarshal(remoteB, remoteH)
    92  		if err != nil {
    93  			return nil, fmt.Errorf("Handshake3 could not decode remote msg: %q", err)
    94  		}
    95  
    96  		log.Debugf("Handshake3 received from %s", rpeer)
    97  	}
    98  
    99  	// actually update our state based on the new knowledge
   100  	res, err := handshake.Handshake3Update(lpeer, rpeer, remoteH)
   101  	if err != nil {
   102  		log.Errorf("Handshake3 failed to update %s", rpeer)
   103  	}
   104  	res.RemoteObservedAddress = c.RemoteMultiaddr()
   105  	return res, nil
   106  }