(*****************************************************************************) (* *) (* Open Source License *) (* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) (* Copyright (c) 2019 Nomadic Labs, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) (* to deal in the Software without restriction, including without limitation *) (* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) (* and/or sell copies of the Software, and to permit persons to whom the *) (* Software is furnished to do so, subject to the following conditions: *) (* *) (* The above copyright notice and this permission notice shall be included *) (* in all copies or substantial portions of the Software. *) (* *) (* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) (* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) (* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) (* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) (* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) (* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) module Id = struct (* A net point (address x port). *) type t = P2p_addr.t * P2p_addr.port option let compare (a1, p1) (a2, p2) = match Ipaddr.V6.compare a1 a2 with 0 -> Stdlib.compare p1 p2 | x -> x let equal p1 p2 = compare p1 p2 = 0 let hash = Hashtbl.hash let pp ppf (addr, port) = match port with | None -> Format.fprintf ppf "[%a]:??" Ipaddr.V6.pp addr | Some port -> Format.fprintf ppf "[%a]:%d" Ipaddr.V6.pp addr port let pp_opt ppf = function | None -> Format.pp_print_string ppf "none" | Some point -> pp ppf point let to_string t = Format.asprintf "%a" pp t let is_local (addr, _) = Ipaddr.V6.is_private addr let is_global (addr, _) = not @@ Ipaddr.V6.is_private addr let of_point (addr, port) = (addr, Some port) let to_point = function | (_, None) -> None | (addr, Some port) -> Some (addr, port) let to_point_exn = function | (_, None) -> invalid_arg "to_point_exn" | (addr, Some port) -> (addr, port) let encoding = let open Data_encoding in def "p2p_connection.id" ~description: "The identifier for a p2p connection. It includes an address and a \ port number." @@ obj2 (req "addr" P2p_addr.encoding) (opt "port" uint16) end module Map = Map.Make (Id) module Set = Set.Make (Id) module Table = Hashtbl.Make (Id) module Info = struct type 'meta t = { incoming : bool; peer_id : P2p_peer_id.t; id_point : Id.t; remote_socket_port : P2p_addr.port; announced_version : Network_version.t; private_node : bool; local_metadata : 'meta; remote_metadata : 'meta; } let encoding metadata_encoding = let open Data_encoding in conv (fun { incoming; peer_id; id_point; remote_socket_port; announced_version; private_node; local_metadata; remote_metadata; } -> ( incoming, peer_id, id_point, remote_socket_port, announced_version, private_node, local_metadata, remote_metadata )) (fun ( incoming, peer_id, id_point, remote_socket_port, announced_version, private_node, local_metadata, remote_metadata ) -> { incoming; peer_id; id_point; remote_socket_port; announced_version; private_node; local_metadata; remote_metadata; }) (obj8 (req "incoming" bool) (req "peer_id" P2p_peer_id.encoding) (req "id_point" Id.encoding) (req "remote_socket_port" uint16) (req "announced_version" Network_version.encoding) (req "private" bool) (req "local_metadata" metadata_encoding) (req "remote_metadata" metadata_encoding)) let pp pp_meta ppf { incoming; id_point = (remote_addr, remote_port); remote_socket_port; peer_id; announced_version; private_node; local_metadata = _; remote_metadata; } = let point = match remote_port with | None -> (remote_addr, remote_socket_port) | Some port -> (remote_addr, port) in Format.fprintf ppf "%s %a %a (%a) %s%a" (if incoming then "↘" else "↗") P2p_peer_id.pp peer_id P2p_point.Id.pp point Network_version.pp announced_version (if private_node then " private" else "") pp_meta remote_metadata end module P2p_event = struct (** Pool-level events *) type t = | Too_few_connections | Too_many_connections | New_point of P2p_point.Id.t | New_peer of P2p_peer_id.t | Gc_points | Gc_peer_ids | Incoming_connection of P2p_point.Id.t | Outgoing_connection of P2p_point.Id.t | Authentication_failed of P2p_point.Id.t | Accepting_request of P2p_point.Id.t * Id.t * P2p_peer_id.t | Rejecting_request of P2p_point.Id.t * Id.t * P2p_peer_id.t | Request_rejected of P2p_point.Id.t * (Id.t * P2p_peer_id.t) option | Connection_established of Id.t * P2p_peer_id.t | Bootstrap_received of {source : P2p_peer_id.t} | Bootstrap_sent of {source : P2p_peer_id.t} | Advertise_received of {source : P2p_peer_id.t} | Advertise_sent of {source : P2p_peer_id.t} | Swap_request_received of {source : P2p_peer_id.t} | Swap_ack_received of {source : P2p_peer_id.t} | Swap_request_sent of {source : P2p_peer_id.t} | Swap_ack_sent of {source : P2p_peer_id.t} | Swap_request_ignored of {source : P2p_peer_id.t} | Swap_success of {source : P2p_peer_id.t} | Swap_failure of {source : P2p_peer_id.t} | Disconnection of P2p_peer_id.t | External_disconnection of P2p_peer_id.t let pp ppf (event : t) = match event with | Too_few_connections -> Format.pp_print_string ppf "Too_few_connections" | Too_many_connections -> Format.pp_print_string ppf "Too_many_connections" | New_point p -> Format.pp_print_string ppf "New_point " ; P2p_point.Id.pp ppf p | New_peer p -> Format.pp_print_string ppf "New_peer " ; P2p_peer_id.pp ppf p | Gc_points -> Format.pp_print_string ppf "Gc_points" | Gc_peer_ids -> Format.pp_print_string ppf "Gc_peer_ids" | Incoming_connection p -> Format.pp_print_string ppf "Incoming_connection " ; P2p_point.Id.pp ppf p | Outgoing_connection p -> Format.pp_print_string ppf "Outgoing_connection " ; P2p_point.Id.pp ppf p | Authentication_failed p -> Format.pp_print_string ppf "Authentication_failed " ; P2p_point.Id.pp ppf p | Accepting_request (pi, _, _) -> Format.pp_print_string ppf "Accepting_request " ; P2p_point.Id.pp ppf pi | Rejecting_request (pi, _, _) -> Format.pp_print_string ppf "Rejecting_request " ; P2p_point.Id.pp ppf pi | Request_rejected (pi, _) -> Format.pp_print_string ppf "Request_rejected " ; P2p_point.Id.pp ppf pi | Connection_established (_, pi) -> Format.pp_print_string ppf "Connection_established " ; P2p_peer_id.pp ppf pi | Bootstrap_received {source} -> Format.pp_print_string ppf "Bootstrap_received " ; P2p_peer_id.pp ppf source | Bootstrap_sent {source} -> Format.pp_print_string ppf "Bootstrap_sent " ; P2p_peer_id.pp ppf source | Advertise_received {source} -> Format.pp_print_string ppf "Advertise_received " ; P2p_peer_id.pp ppf source | Advertise_sent {source} -> Format.pp_print_string ppf "Advertise_sent " ; P2p_peer_id.pp ppf source | Swap_request_received {source} -> Format.pp_print_string ppf "Swap_request_received " ; P2p_peer_id.pp ppf source | Swap_ack_received {source} -> Format.pp_print_string ppf "Swap_ack_received " ; P2p_peer_id.pp ppf source | Swap_request_sent {source} -> Format.pp_print_string ppf "Swap_request_sent " ; P2p_peer_id.pp ppf source | Swap_ack_sent {source} -> Format.pp_print_string ppf "Swap_ack_sent " ; P2p_peer_id.pp ppf source | Swap_request_ignored {source} -> Format.pp_print_string ppf "Swap_request_ignored " ; P2p_peer_id.pp ppf source | Swap_success {source} -> Format.pp_print_string ppf "Swap_success " ; P2p_peer_id.pp ppf source | Swap_failure {source} -> Format.pp_print_string ppf "Swap_failure " ; P2p_peer_id.pp ppf source | Disconnection source -> Format.pp_print_string ppf "Disconnection " ; P2p_peer_id.pp ppf source | External_disconnection source -> Format.pp_print_string ppf "External_disconnection " ; P2p_peer_id.pp ppf source let encoding = let open Data_encoding in let branch_encoding name obj = conv (fun x -> ((), x)) (fun ((), x) -> x) (merge_objs (obj1 (req "event" (constant name))) obj) in def "p2p_connection.pool_event" ~description: "An event that may happen during maintenance of and other operations \ on the p2p connection pool. Typically, it includes connection errors, \ peer swaps, etc." @@ union ~tag_size:`Uint8 [ case (Tag 0) ~title:"Too_few_connections" (branch_encoding "too_few_connections" empty) (function Too_few_connections -> Some () | _ -> None) (fun () -> Too_few_connections); case (Tag 1) ~title:"Too_many_connections" (branch_encoding "too_many_connections" empty) (function Too_many_connections -> Some () | _ -> None) (fun () -> Too_many_connections); case (Tag 2) ~title:"New_point" (branch_encoding "new_point" (obj1 (req "point" P2p_point.Id.encoding))) (function New_point p -> Some p | _ -> None) (fun p -> New_point p); case (Tag 3) ~title:"New_peer" (branch_encoding "new_peer" (obj1 (req "peer_id" P2p_peer_id.encoding))) (function New_peer p -> Some p | _ -> None) (fun p -> New_peer p); case (Tag 4) ~title:"Incoming_connection" (branch_encoding "incoming_connection" (obj1 (req "point" P2p_point.Id.encoding))) (function Incoming_connection p -> Some p | _ -> None) (fun p -> Incoming_connection p); case (Tag 5) ~title:"Outgoing_connection" (branch_encoding "outgoing_connection" (obj1 (req "point" P2p_point.Id.encoding))) (function Outgoing_connection p -> Some p | _ -> None) (fun p -> Outgoing_connection p); case (Tag 6) ~title:"Authentication_failed" (branch_encoding "authentication_failed" (obj1 (req "point" P2p_point.Id.encoding))) (function Authentication_failed p -> Some p | _ -> None) (fun p -> Authentication_failed p); case (Tag 7) ~title:"Accepting_request" (branch_encoding "accepting_request" (obj3 (req "point" P2p_point.Id.encoding) (req "id_point" Id.encoding) (req "peer_id" P2p_peer_id.encoding))) (function | Accepting_request (p, id_p, g) -> Some (p, id_p, g) | _ -> None) (fun (p, id_p, g) -> Accepting_request (p, id_p, g)); case (Tag 8) ~title:"Rejecting_request" (branch_encoding "rejecting_request" (obj3 (req "point" P2p_point.Id.encoding) (req "id_point" Id.encoding) (req "peer_id" P2p_peer_id.encoding))) (function | Rejecting_request (p, id_p, g) -> Some (p, id_p, g) | _ -> None) (fun (p, id_p, g) -> Rejecting_request (p, id_p, g)); case (Tag 9) ~title:"Request_rejected" (branch_encoding "request_rejected" (obj2 (req "point" P2p_point.Id.encoding) (opt "identity" (tup2 Id.encoding P2p_peer_id.encoding)))) (function Request_rejected (p, id) -> Some (p, id) | _ -> None) (fun (p, id) -> Request_rejected (p, id)); case (Tag 10) ~title:"Connection_established" (branch_encoding "connection_established" (obj2 (req "id_point" Id.encoding) (req "peer_id" P2p_peer_id.encoding))) (function | Connection_established (id_p, g) -> Some (id_p, g) | _ -> None) (fun (id_p, g) -> Connection_established (id_p, g)); case (Tag 11) ~title:"Disconnection" (branch_encoding "disconnection" (obj1 (req "peer_id" P2p_peer_id.encoding))) (function Disconnection g -> Some g | _ -> None) (fun g -> Disconnection g); case (Tag 12) ~title:"External_disconnection" (branch_encoding "external_disconnection" (obj1 (req "peer_id" P2p_peer_id.encoding))) (function External_disconnection g -> Some g | _ -> None) (fun g -> External_disconnection g); case (Tag 13) ~title:"Gc_points" (branch_encoding "gc_points" empty) (function Gc_points -> Some () | _ -> None) (fun () -> Gc_points); case (Tag 14) ~title:"Gc_peer_ids" (branch_encoding "gc_peer_ids" empty) (function Gc_peer_ids -> Some () | _ -> None) (fun () -> Gc_peer_ids); case (Tag 15) ~title:"Swap_request_received" (branch_encoding "swap_request_received" (obj1 (req "source" P2p_peer_id.encoding))) (function | Swap_request_received {source} -> Some source | _ -> None) (fun source -> Swap_request_received {source}); case (Tag 16) ~title:"Swap_ack_received" (branch_encoding "swap_ack_received" (obj1 (req "source" P2p_peer_id.encoding))) (function Swap_ack_received {source} -> Some source | _ -> None) (fun source -> Swap_ack_received {source}); case (Tag 17) ~title:"Swap_request_sent" (branch_encoding "swap_request_sent" (obj1 (req "source" P2p_peer_id.encoding))) (function Swap_request_sent {source} -> Some source | _ -> None) (fun source -> Swap_request_sent {source}); case (Tag 18) ~title:"Swap_ack_sent" (branch_encoding "swap_ack_sent" (obj1 (req "source" P2p_peer_id.encoding))) (function Swap_ack_sent {source} -> Some source | _ -> None) (fun source -> Swap_ack_sent {source}); case (Tag 19) ~title:"Swap_request_ignored" (branch_encoding "swap_request_ignored" (obj1 (req "source" P2p_peer_id.encoding))) (function | Swap_request_ignored {source} -> Some source | _ -> None) (fun source -> Swap_request_ignored {source}); case (Tag 20) ~title:"Swap_success" (branch_encoding "swap_success" (obj1 (req "source" P2p_peer_id.encoding))) (function Swap_success {source} -> Some source | _ -> None) (fun source -> Swap_success {source}); case (Tag 21) ~title:"Swap_failure" (branch_encoding "swap_failure" (obj1 (req "source" P2p_peer_id.encoding))) (function Swap_failure {source} -> Some source | _ -> None) (fun source -> Swap_failure {source}); case (Tag 22) ~title:"Bootstrap_sent" (branch_encoding "bootstrap_sent" (obj1 (req "source" P2p_peer_id.encoding))) (function Bootstrap_sent {source} -> Some source | _ -> None) (fun source -> Bootstrap_sent {source}); case (Tag 23) ~title:"Bootstrap_received" (branch_encoding "bootstrap_received" (obj1 (req "source" P2p_peer_id.encoding))) (function Bootstrap_received {source} -> Some source | _ -> None) (fun source -> Bootstrap_received {source}); case (Tag 24) ~title:"Advertise_sent" (branch_encoding "advertise_sent" (obj1 (req "source" P2p_peer_id.encoding))) (function Advertise_sent {source} -> Some source | _ -> None) (fun source -> Advertise_sent {source}); case (Tag 25) ~title:"Advertise_received" (branch_encoding "advertise_received" (obj1 (req "source" P2p_peer_id.encoding))) (function Advertise_received {source} -> Some source | _ -> None) (fun source -> Advertise_received {source}); ] end let () = Data_encoding.Registration.register ~pp:Id.pp Id.encoding ; Data_encoding.Registration.register ~pp:P2p_event.pp P2p_event.encoding module Internal_for_tests = struct module Info = struct let mock default_metadata = Info. { incoming = false; peer_id = P2p_peer_id.zero; id_point = Id.of_point (P2p_point.Id.of_string_exn "0.0.0.0:0"); remote_socket_port = 0; announced_version = Network_version.Internal_for_tests.mock (); private_node = true; local_metadata = default_metadata; remote_metadata = default_metadata; } end end