Raw File
point_parser.mll
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2020 Nomadic Labs, <contact@nomadic-labs.com>               *)
(*                                                                           *)
(* 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.                                                 *)
(*                                                                           *)
(*****************************************************************************)

(* This file parses a string encoding a point with an expected peer
   id.  Because the address part of the point may be given with a
   domain we keep this field as a string. The string will be
   eventually given to `getaddrinfo` and therefore we remove brackets
   around ipv6 address. The expected peer id is given using the b58
   format. We also ensure that the port is between the range
   [0-65535]. *)

{

  type addr_port_id = {
    addr : string;
    port : int option;
    peer_id : P2p_peer_id.t option;
  }

  type parsing_error =
    | Port_not_in_range of int
    | Bad_id_format of string
    | Bad_format

  let string_of_parsing_error = function
    | Port_not_in_range p ->
      Format.asprintf "port '%d' not in range [0-65535]" p
    | Bad_id_format s ->
      Format.asprintf "peer id '%s' is not valid (b58 format expected)" s
    | Bad_format ->
      Format.asprintf "expected <addr>[:<port>][#<peer_id>]"

  let parse_port p k =
      match p with
      | None -> k None
      | Some p ->
            let p = int_of_string p in
      	    if 0 <= p && p <= 65535 then
	          k (Some p)
	   else
                  Error (Port_not_in_range p)


  let parse_peer_id peer_id k =
      match peer_id with
      | None -> k None
      | Some peer_id ->
            match P2p_peer_id.of_b58check_opt peer_id with
      	    | None -> Error (Bad_id_format peer_id)
	    | Some id -> k (Some id)

  (* Remove square brackets for ipv6 addresses *)
  let parse_addr addr k =
      let len = String.length addr in
      if len > 0 && String.get addr 0 = '[' && String.get addr (len - 1) = ']' then
           k (String.sub addr 1 (len - 2))
      else
           k addr

  let make_full_addr addr port peer_id =
    parse_port port (fun port ->
    parse_peer_id peer_id (fun peer_id ->
    parse_addr addr (fun addr ->
    Ok {addr;port;peer_id})))

}

let peer_id = ['a'-'z' 'A'-'Z' '0'-'9']+

let empty = ['_']?

let domain = ['a'-'z' 'A'-'Z' '0' - '9' '.' '-']+

let ipv4seg = ['0' - '9'] ['0' - '9']? ['0' - '9']?

let ipv4 = ipv4seg '.' ipv4seg '.' ipv4seg '.' ipv4seg

let ipv6_char = ['a'-'f' 'A'-'F' '0'-'9' ':' '.']

let ipv6 = '[' ipv6_char+ ']'

let port = ['0'-'9']+

let addr = ipv4 | ipv6 | domain | empty

rule parse_full_addr = parse
    | (addr as addr) (':' (port as port))? ('#' (peer_id as peer_id))? eof
    {make_full_addr addr port peer_id}
    | _ + eof
    {Error Bad_format}
back to top