diff --git a/dht/dht.go b/dht/dht.go index 162f60c..d5aca0d 100644 --- a/dht/dht.go +++ b/dht/dht.go @@ -517,11 +517,14 @@ func (dht *IpfsDHT) peerFromInfo(pbp *pb.Message_Peer) (peer.Peer, error) { return nil, err } - maddr, err := pbp.Address() + // add addresses we've just discovered + maddrs, err := pbp.Addresses() if err != nil { return nil, err } - p.AddAddress(maddr) + for _, maddr := range maddrs { + p.AddAddress(maddr) + } return p, nil } diff --git a/dht/handlers.go b/dht/handlers.go index 07f21f1..41013a6 100644 --- a/dht/handlers.go +++ b/dht/handlers.go @@ -210,14 +210,16 @@ func (dht *IpfsDHT) handleAddProvider(ctx context.Context, p peer.Peer, pmes *pb pid := peer.ID(pb.GetId()) if pid.Equal(p.ID()) { - addr, err := pb.Address() + maddrs, err := pb.Addresses() if err != nil { - log.Errorf("provider %s error with address %s", p, *pb.Addr) + log.Errorf("provider %s error with addresses %s", p, pb.Addrs) continue } - log.Infof("received provider %s %s for %s", p, addr, key) - p.AddAddress(addr) + log.Infof("received provider %s %s for %s", p, maddrs, key) + for _, maddr := range maddrs { + p.AddAddress(maddr) + } dht.providers.AddProvider(key, p) } else { diff --git a/dht/pb/dht.pb.go b/dht/pb/dht.pb.go index 3e52a94..e102ef7 100644 --- a/dht/pb/dht.pb.go +++ b/dht/pb/dht.pb.go @@ -15,10 +15,12 @@ It has these top-level messages: package dht_pb import proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto" +import json "encoding/json" import math "math" -// Reference imports to suppress errors if they are not otherwise used. +// Reference proto, json, and math imports to suppress error if they are not otherwise used. var _ = proto.Marshal +var _ = &json.SyntaxError{} var _ = math.Inf type Message_MessageType int32 @@ -66,6 +68,50 @@ func (x *Message_MessageType) UnmarshalJSON(data []byte) error { return nil } +type Message_ConnectionType int32 + +const ( + // sender does not have a connection to peer, and no extra information (default) + Message_NOT_CONNECTED Message_ConnectionType = 0 + // sender has a live connection to peer + Message_CONNECTED Message_ConnectionType = 1 + // sender recently connected to peer + Message_CAN_CONNECT Message_ConnectionType = 2 + // sender recently tried to connect to peer repeatedly but failed to connect + // ("try" here is loose, but this should signal "made strong effort, failed") + Message_CANNOT_CONNECT Message_ConnectionType = 3 +) + +var Message_ConnectionType_name = map[int32]string{ + 0: "NOT_CONNECTED", + 1: "CONNECTED", + 2: "CAN_CONNECT", + 3: "CANNOT_CONNECT", +} +var Message_ConnectionType_value = map[string]int32{ + "NOT_CONNECTED": 0, + "CONNECTED": 1, + "CAN_CONNECT": 2, + "CANNOT_CONNECT": 3, +} + +func (x Message_ConnectionType) Enum() *Message_ConnectionType { + p := new(Message_ConnectionType) + *p = x + return p +} +func (x Message_ConnectionType) String() string { + return proto.EnumName(Message_ConnectionType_name, int32(x)) +} +func (x *Message_ConnectionType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Message_ConnectionType_value, data, "Message_ConnectionType") + if err != nil { + return err + } + *x = Message_ConnectionType(value) + return nil +} + type Message struct { // defines what type of message it is. Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=dht.pb.Message_MessageType" json:"type,omitempty"` @@ -133,9 +179,13 @@ func (m *Message) GetProviderPeers() []*Message_Peer { } type Message_Peer struct { - Id *string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Addr *string `protobuf:"bytes,2,opt,name=addr" json:"addr,omitempty"` - XXX_unrecognized []byte `json:"-"` + // ID of a given peer. + Id *string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + // multiaddrs for a given peer + Addrs []string `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` + // used to signal the sender's connection capabilities to the peer + Connection *Message_ConnectionType `protobuf:"varint,3,opt,name=connection,enum=dht.pb.Message_ConnectionType" json:"connection,omitempty"` + XXX_unrecognized []byte `json:"-"` } func (m *Message_Peer) Reset() { *m = Message_Peer{} } @@ -149,11 +199,18 @@ func (m *Message_Peer) GetId() string { return "" } -func (m *Message_Peer) GetAddr() string { - if m != nil && m.Addr != nil { - return *m.Addr +func (m *Message_Peer) GetAddrs() []string { + if m != nil { + return m.Addrs } - return "" + return nil +} + +func (m *Message_Peer) GetConnection() Message_ConnectionType { + if m != nil && m.Connection != nil { + return *m.Connection + } + return Message_NOT_CONNECTED } // Record represents a dht record that contains a value @@ -204,4 +261,5 @@ func (m *Record) GetSignature() []byte { func init() { proto.RegisterEnum("dht.pb.Message_MessageType", Message_MessageType_name, Message_MessageType_value) + proto.RegisterEnum("dht.pb.Message_ConnectionType", Message_ConnectionType_name, Message_ConnectionType_value) } diff --git a/dht/pb/dht.proto b/dht/pb/dht.proto index 1b49a15..6f31dd5 100644 --- a/dht/pb/dht.proto +++ b/dht/pb/dht.proto @@ -12,9 +12,30 @@ message Message { PING = 5; } + enum ConnectionType { + // sender does not have a connection to peer, and no extra information (default) + NOT_CONNECTED = 0; + + // sender has a live connection to peer + CONNECTED = 1; + + // sender recently connected to peer + CAN_CONNECT = 2; + + // sender recently tried to connect to peer repeatedly but failed to connect + // ("try" here is loose, but this should signal "made strong effort, failed") + CANNOT_CONNECT = 3; + } + message Peer { + // ID of a given peer. optional string id = 1; - optional string addr = 2; + + // multiaddrs for a given peer + repeated string addrs = 2; + + // used to signal the sender's connection capabilities to the peer + optional ConnectionType connection = 3; } // defines what type of message it is. diff --git a/dht/pb/message.go b/dht/pb/message.go index f8001c5..a7cc28b 100644 --- a/dht/pb/message.go +++ b/dht/pb/message.go @@ -3,7 +3,6 @@ package dht_pb import ( "errors" - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" peer "github.com/jbenet/go-ipfs/peer" ) @@ -19,12 +18,11 @@ func NewMessage(typ Message_MessageType, key string, level int) *Message { func peerToPBPeer(p peer.Peer) *Message_Peer { pbp := new(Message_Peer) - addrs := p.Addresses() - if len(addrs) == 0 || addrs[0] == nil { - pbp.Addr = proto.String("") - } else { - addr := addrs[0].String() - pbp.Addr = &addr + + maddrs := p.Addresses() + pbp.Addrs = make([]string, len(maddrs)) + for i, maddr := range maddrs { + pbp.Addrs[i] = maddr.String() } pid := string(p.ID()) pbp.Id = &pid @@ -41,12 +39,21 @@ func PeersToPBPeers(peers []peer.Peer) []*Message_Peer { return pbpeers } -// Address returns a multiaddr associated with the Message_Peer entry -func (m *Message_Peer) Address() (ma.Multiaddr, error) { +// Addresses returns a multiaddr associated with the Message_Peer entry +func (m *Message_Peer) Addresses() ([]ma.Multiaddr, error) { if m == nil { return nil, errors.New("MessagePeer is nil") } - return ma.NewMultiaddr(*m.Addr) + + var err error + maddrs := make([]ma.Multiaddr, len(m.Addrs)) + for i, addr := range m.Addrs { + maddrs[i], err = ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + } + return maddrs, nil } // GetClusterLevel gets and adjusts the cluster level on the message. diff --git a/dht/routing.go b/dht/routing.go index 4e2dc37..1074b23 100644 --- a/dht/routing.go +++ b/dht/routing.go @@ -241,12 +241,17 @@ func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.Peer, error) log.Warningf("Received invalid peer from query: %v", err) continue } - ma, err := pbp.Address() + + // add addresses + maddrs, err := pbp.Addresses() if err != nil { - log.Warning("Received peer with bad or missing address.") + log.Warning("Received peer with bad or missing addresses: %s", pbp.Addrs) continue } - np.AddAddress(ma) + for _, maddr := range maddrs { + np.AddAddress(maddr) + } + if pbp.GetId() == string(id) { return &dhtQueryResult{ peer: np,