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  }