github.com/koko1123/flow-go-1@v0.29.6/network/internal/p2putils/utils.go (about) 1 package p2putils 2 3 import ( 4 "fmt" 5 "net" 6 7 "github.com/libp2p/go-libp2p/core" 8 "github.com/libp2p/go-libp2p/core/crypto" 9 "github.com/libp2p/go-libp2p/core/host" 10 "github.com/libp2p/go-libp2p/core/network" 11 "github.com/libp2p/go-libp2p/core/peer" 12 "github.com/multiformats/go-multiaddr" 13 "github.com/rs/zerolog" 14 15 "github.com/koko1123/flow-go-1/model/flow" 16 "github.com/koko1123/flow-go-1/network/p2p/keyutils" 17 "github.com/koko1123/flow-go-1/network/p2p/unicast" 18 ) 19 20 // FlowStream returns the Flow protocol Stream in the connection if one exist, else it returns nil 21 func FlowStream(conn network.Conn) network.Stream { 22 for _, s := range conn.GetStreams() { 23 if unicast.IsFlowProtocolStream(s) { 24 return s 25 } 26 } 27 return nil 28 } 29 30 // StreamLogger creates a logger for libp2p stream which logs the remote and local peer IDs and addresses 31 func StreamLogger(log zerolog.Logger, stream network.Stream) zerolog.Logger { 32 logger := log.With(). 33 Str("protocol", string(stream.Protocol())). 34 Str("remote_peer", stream.Conn().RemotePeer().String()). 35 Str("remote_address", stream.Conn().RemoteMultiaddr().String()). 36 Str("local_peer", stream.Conn().LocalPeer().String()). 37 Str("local_address", stream.Conn().LocalMultiaddr().String()).Logger() 38 return logger 39 } 40 41 var directionLookUp = map[network.Direction]string{ 42 network.DirInbound: "InBound", 43 network.DirOutbound: "OutBound", 44 network.DirUnknown: "Unknown", 45 } 46 47 var connectednessLookup = map[network.Connectedness]string{ 48 network.CannotConnect: "CannotConnect", 49 network.CanConnect: "CanConnect", 50 network.Connected: "Connected", 51 network.NotConnected: "NotConnected", 52 } 53 54 // DirectionToString reverse translates libp2p network direction to string 55 func DirectionToString(direction network.Direction) (string, bool) { 56 if dirStr, found := directionLookUp[direction]; found { 57 return dirStr, true 58 } 59 return "", false 60 } 61 62 // ConnectednessToString reverse translates libp2p network connectedness to string 63 func ConnectednessToString(connectedness network.Connectedness) (string, bool) { 64 if connStr, found := connectednessLookup[connectedness]; found { 65 return connStr, true 66 } 67 return "", false 68 69 } 70 71 // FindOutboundStream finds an existing outbound stream to the target id if it exists by querying libp2p 72 func FindOutboundStream(host host.Host, targetID peer.ID, protocol core.ProtocolID) (network.Stream, bool) { 73 streams := FilterStream(host, targetID, protocol, network.DirOutbound, false) 74 if len(streams) > 0 { 75 return streams[0], true 76 } 77 return nil, false 78 } 79 80 // CountStream finds total number of outbound stream to the target id 81 func CountStream(host host.Host, targetID peer.ID, protocol core.ProtocolID, dir network.Direction) int { 82 streams := FilterStream(host, targetID, protocol, dir, true) 83 return len(streams) 84 } 85 86 // FilterStream finds one or all existing outbound streams to the target id if it exists. 87 // if parameter all is true - all streams are found else the first stream found is returned 88 func FilterStream(host host.Host, targetID peer.ID, protocol core.ProtocolID, dir network.Direction, all bool) []network.Stream { 89 90 var filteredStreams []network.Stream 91 92 // choose the connection only if it is connected 93 if host.Network().Connectedness(targetID) != network.Connected { 94 return filteredStreams 95 } 96 97 // get all connections 98 conns := host.Network().ConnsToPeer(targetID) 99 100 // find a connection which is in the connected state 101 for _, conn := range conns { 102 103 // get all streams 104 streams := conn.GetStreams() 105 for _, stream := range streams { 106 107 // choose a stream which is marked as outbound and is for the flow protocol 108 if stream.Stat().Direction == dir && stream.Protocol() == protocol { 109 filteredStreams = append(filteredStreams, stream) 110 if !all { 111 return filteredStreams 112 } 113 } 114 } 115 } 116 return filteredStreams 117 } 118 119 // NetworkingInfo returns ip, port, libp2p public key of the identity. 120 func NetworkingInfo(identity flow.Identity) (string, string, crypto.PubKey, error) { 121 // split the node address into ip and port 122 ip, port, err := net.SplitHostPort(identity.Address) 123 if err != nil { 124 return "", "", nil, fmt.Errorf("could not parse address %s: %w", identity.Address, err) 125 } 126 127 // convert the Flow key to a LibP2P key 128 lkey, err := keyutils.LibP2PPublicKeyFromFlow(identity.NetworkPubKey) 129 if err != nil { 130 return "", "", nil, fmt.Errorf("could not convert flow key to libp2p key: %w", err) 131 } 132 133 return ip, port, lkey, nil 134 } 135 136 // IPPortFromMultiAddress returns the IP/hostname and the port for the given multi-addresses 137 // associated with a libp2p host 138 func IPPortFromMultiAddress(addrs ...multiaddr.Multiaddr) (string, string, error) { 139 140 var ipOrHostname, port string 141 var err error 142 143 for _, a := range addrs { 144 // try and get the dns4 hostname 145 ipOrHostname, err = a.ValueForProtocol(multiaddr.P_DNS4) 146 if err != nil { 147 // if dns4 hostname is not found, try and get the IP address 148 ipOrHostname, err = a.ValueForProtocol(multiaddr.P_IP4) 149 if err != nil { 150 continue // this may not be a TCP IP multiaddress 151 } 152 } 153 154 // if either IP address or hostname is found, look for the port number 155 port, err = a.ValueForProtocol(multiaddr.P_TCP) 156 if err != nil { 157 // an IPv4 or DNS4 based multiaddress should have a port number 158 return "", "", err 159 } 160 161 //there should only be one valid IPv4 address 162 return ipOrHostname, port, nil 163 } 164 return "", "", fmt.Errorf("ip address or hostname not found") 165 }