Skip to content

Commit

Permalink
Merge pull request mirage#89 from avsm/docs
Browse files Browse the repository at this point in the history
Rename bytes functions to octets instead
  • Loading branch information
avsm authored Jul 10, 2019
2 parents 0d8a5a3 + decf2bd commit e614dc9
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 142 deletions.
23 changes: 23 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
## v4.0.0

* Rename the `to/from_bytes` functions to refer to `octets`
instead. This distinguishes the meaning of human-readable
addresses (`string`s in this library) and byte-packed
representations(`octet`s in this library) from the OCaml
`bytes` type that represents mutable strings.

Porting code should just be a matter of renaming functions
such as:
- `Ipaddr.of_bytes` becomes `Ipaddr.of_octets`
- `Macaddr.to_bytes` becomes `Macaddr.to_octets`

* Introduce new `write_octets` functions that can write
octet representations of IPv4/v6 into an existing bytestring.

* Use the `domain-name` library to produce domain names
from IP addresses.

* Remove the `ipaddr.sexp` and `macaddr.sexp` ocamlfind
subpackages and instead have `ipaddr-sexp` and `macaddr-sexp`
to match the opam package names.

## v3.1.0 (2019-03-02)

* Do not leak a `Not_found` exception when parsing `[:`
Expand Down
114 changes: 51 additions & 63 deletions lib/ipaddr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ let (>!) x y = (x >|> y) &&& 0xFF_l
let (<!) x y = (x &&& 0xFF_l) <|< y

let need_more x = Parse_error ("not enough data", x)
let too_much x = Parse_error ("too much data", x)

let char_0 = int_of_char '0'
let char_a = int_of_char 'a'
Expand Down Expand Up @@ -184,35 +183,38 @@ module V4 = struct
let pp ppf i =
Format.fprintf ppf "%s" (to_string i)

(* Byte conversion *)

let of_bytes_raw bs o =
make
(Char.code bs.[0 + o])
(Char.code bs.[1 + o])
(Char.code bs.[2 + o])
(Char.code bs.[3 + o])

let of_bytes_exn bs =
let len = String.length bs in
if len > 4 then raise (too_much bs);
if len < 4 then raise (need_more bs);
of_bytes_raw bs 0

let of_bytes bs = try_with_result of_bytes_exn bs

let to_bytes_raw i b o =
Bytes.set b (0 + o) (Char.chr ((|~) (i >! 24)));
Bytes.set b (1 + o) (Char.chr ((|~) (i >! 16)));
Bytes.set b (2 + o) (Char.chr ((|~) (i >! 8)));
Bytes.set b (3 + o) (Char.chr ((|~) (i >! 0)))

let to_bytes i =
let b = Bytes.create 4 in
to_bytes_raw i b 0;
Bytes.to_string b

(* Int32*)
(* Octets conversion *)

let of_octets_exn ?(off=0) bs =
try
make
(Char.code bs.[0 + off])
(Char.code bs.[1 + off])
(Char.code bs.[2 + off])
(Char.code bs.[3 + off])
with _ -> raise (need_more bs)

let of_octets ?off bs = try_with_result (of_octets_exn ?off) bs

let write_octets_exn ?(off=0) i b =
try
Bytes.set b (0 + off) (Char.chr ((|~) (i >! 24)));
Bytes.set b (1 + off) (Char.chr ((|~) (i >! 16)));
Bytes.set b (2 + off) (Char.chr ((|~) (i >! 8)));
Bytes.set b (3 + off) (Char.chr ((|~) (i >! 0)))
with _ -> raise (need_more (Bytes.to_string b))

let write_octets ?off i bs = try_with_result (write_octets_exn ?off i) bs

let to_octets i =
String.init 4 (function
| 0 -> Char.chr ((|~) (i >! 24))
| 1 -> Char.chr ((|~) (i >! 16))
| 2 -> Char.chr ((|~) (i >! 8))
| 3 -> Char.chr ((|~) (i >! 0))
| _ -> assert false)

(* Int32 *)
let of_int32 i = i
let to_int32 i = i

Expand All @@ -230,7 +232,7 @@ module V4 = struct
Bytes.set macb 3 (Char.chr ((|~) (i >|> 16 &&& 0x7F_l)));
Bytes.set macb 4 (Char.chr ((|~) (i >! 8)));
Bytes.set macb 5 (Char.chr ((|~) (i >! 0)));
Macaddr.of_bytes_exn (Bytes.to_string macb)
Macaddr.of_octets_exn (Bytes.to_string macb)

(* Host *)
let to_domain_name i =
Expand Down Expand Up @@ -433,21 +435,11 @@ module B128 = struct
in
(a,b,c,d,e,f,g,h)

let to_bytes_raw (a,b,c,d) byte o =
V4.to_bytes_raw a byte (o+0);
V4.to_bytes_raw b byte (o+4);
V4.to_bytes_raw c byte (o+8);
V4.to_bytes_raw d byte (o+12)

let _of_bytes_exn bs = (* TODO : from cstruct *)
let len = String.length bs in
if len > 16 then raise (too_much bs);
if len < 16 then raise (need_more bs);
let hihi = V4.of_bytes_raw bs 0 in
let hilo = V4.of_bytes_raw bs 4 in
let lohi = V4.of_bytes_raw bs 8 in
let lolo = V4.of_bytes_raw bs 12 in
of_int32 (hihi, hilo, lohi, lolo)
let write_octets_exn ?(off=0) (a,b,c,d) byte =
V4.write_octets_exn ~off a byte;
V4.write_octets_exn ~off:(off+4) b byte;
V4.write_octets_exn ~off:(off+8) c byte;
V4.write_octets_exn ~off:(off+12) d byte

let compare (a1,b1,c1,d1) (a2,b2,c2,d2) =
match V4.compare a1 a2 with
Expand Down Expand Up @@ -639,25 +631,21 @@ module V6 = struct

(* byte conversion *)

let of_bytes_raw bs o = (* TODO : from cstruct *)
let hihi = V4.of_bytes_raw bs (o + 0) in
let hilo = V4.of_bytes_raw bs (o + 4) in
let lohi = V4.of_bytes_raw bs (o + 8) in
let lolo = V4.of_bytes_raw bs (o + 12) in
let of_octets_exn ?(off=0) bs = (* TODO : from cstruct *)
let hihi = V4.of_octets_exn ~off bs in
let hilo = V4.of_octets_exn ~off:(off+4) bs in
let lohi = V4.of_octets_exn ~off:(off+8) bs in
let lolo = V4.of_octets_exn ~off:(off+12) bs in
of_int32 (hihi, hilo, lohi, lolo)

let of_bytes_exn bs = (* TODO : from cstruct *)
let len = String.length bs in
if len > 16 then raise (too_much bs);
if len < 16 then raise (need_more bs);
of_bytes_raw bs 0
let of_octets ?off bs = try_with_result (of_octets_exn ?off) bs

let of_bytes bs = try_with_result of_bytes_exn bs
let write_octets ?off i bs = try_with_result (write_octets_exn ?off i) bs

let to_bytes i =
let bs = Bytes.create 16 in
to_bytes_raw i bs 0;
Bytes.to_string bs
let to_octets i =
let b = Bytes.create 16 in
write_octets_exn i b;
Bytes.to_string b

(* MAC *)
(* {{:https://tools.ietf.org/html/rfc2464#section-7}RFC 2464}. *)
Expand All @@ -670,7 +658,7 @@ module V6 = struct
Bytes.set macb 3 (Char.chr ((|~) (i >! 16)));
Bytes.set macb 4 (Char.chr ((|~) (i >! 8)));
Bytes.set macb 5 (Char.chr ((|~) (i >! 0)));
Macaddr.of_bytes_exn (Bytes.to_string macb)
Macaddr.of_octets_exn (Bytes.to_string macb)

(* Host *)
let to_domain_name (a,b,c,d) =
Expand Down Expand Up @@ -886,7 +874,7 @@ module V6 = struct
let link_address_of_mac =
let c b i = Char.code (String.get b i) in
fun mac ->
let bmac = Macaddr.to_bytes mac in
let bmac = Macaddr.to_octets mac in
let c_0 = c bmac 0 lxor 2 in
let addr = make 0 0 0 0
(c_0 lsl 8 + c bmac 1)
Expand Down
115 changes: 64 additions & 51 deletions lib/ipaddr.mli
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
(*
* Copyright (c) 2019 Anil Madhavapeddy <[email protected]>
* Copyright (c) 2013-2015 David Sheets <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
Expand Down Expand Up @@ -54,20 +55,21 @@ module V4 : sig
(** Converts the low bytes of four int values into an abstract {! V4.t }. *)
val make : int -> int -> int -> int -> t

(** {3 Text string conversion} *)
(** {3 Text string conversion}
These manipulate human-readable IPv4 addresses (for example [192.168.1.2]). *)

(** [of_string s] is the address {!t} represented by the IPv4 address [s].
Returns a human-readable error string if parsing failed. *)
(** [of_string s] is the address {!t} represented by the human-readable IPv4
address [s]. Returns a human-readable error string if parsing failed. *)
val of_string : string -> (t, [> `Msg of string ]) result

(** [of_string_exn s] is the address {!t} represented
by [s]. Raises {!Parse_error} if [s] is not a
valid representation of an IPv4 address. *)
(** [of_string_exn s] is the address {!t} represented as a human-readable IPv4
address [s]. Raises {!Parse_error} if [s] is not exactly 4 bytes long. *)
val of_string_exn : string -> t

(** [of_string_raw s off] acts as {!of_string_exn} but takes as an extra
argument the offset into the string for reading. [off] will be
mutated to an unspecified value during the function call. *)
mutated to an unspecified value during the function call. [s] will
a {!Parse_error} exception if it is an invalid or truncated IP address. *)
val of_string_raw : string -> int ref -> t

(** [to_string ipv4] is the dotted decimal string representation
Expand All @@ -82,28 +84,36 @@ module V4 : sig
the formatter [f]. *)
val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]

(** {3 Bytestring conversion} *)

(** [of_bytes s] is the address {!t} represented by the IPv4 octets
represented by [s]. [s] should be exactly 4 bytes long.
Returns a human-readable error string if parsing fails. *)
val of_bytes : string -> (t, [> `Msg of string ]) result

(** [of_bytes_exn ipv4_octets] is the address represented
by [ipv4_octets]. Raises [Parse_error] if [ipv4_octets] is not a
valid representation of an IPv4 address. *)
val of_bytes_exn : string -> t

(** [of_bytes_raw s off] is the same as {!of_bytes_exn} but takes
an extra paramenter [off] the offset into the bytes for reading. *)
val of_bytes_raw : string -> int -> t

(** [to_bytes ipv4] is a string of length 4 encoding [ipv4]. *)
val to_bytes : t -> string

(** [to_bytes_raw ipv4 bytes offset] writes the 4 byte encoding of [ipv4]
into [bytes] at offset [offset]. *)
val to_bytes_raw : t -> Bytes.t -> int -> unit
(** {3 Octets conversion}
These manipulate IPv4 addresses represented as a sequence of
four bytes. (e.g for example [0xc0a80102] will be the representation
of the human-readable [192.168.1.2] address. *)

(** [of_octets ?off s] is the address {!t} represented by the IPv4 octets
represented by [s] starting from offset [off] within the string.
[s] must be at least [off+4] bytes long.
Returns a human-readable error string if parsing fails.
[off] defaults to 0. *)
val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result

(** [of_octets_exn ipv4_octets] is the IPv4 address represented
by [ipv4_octets] starting from offset [off] within the string.
Raises {!Parse_error} if [ipv4_octets] is not at least [off+4] bytes long.
[off] defaults to 0. *)
val of_octets_exn : ?off:int -> string -> t

(** [write_octets ?off ipv4 b] writes the [ipv4] as octets to [b] starting
from offset [off]. [b] must be at least [off+4] long or an error is
returned. *)
val write_octets : ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result

(** [write_octets_exn ?off ipv4 b] writes the [ipv4] as octets to [b] starting
from offset [off]. [b] must be at least [off+4] long or a
{!Parse_error} is raised. *)
val write_octets_exn : ?off:int -> t -> bytes -> unit

(** [to_octets ipv4] returns the 4 bytes representing the [ipv4] octets. *)
val to_octets : t -> string

(** {3 Int conversion} *)

Expand Down Expand Up @@ -200,7 +210,7 @@ module V4 : sig
val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]

(** [of_address_string_exn cidr_addr] is the address and prefix
represented by [cidr_addr]. Raises [Parse_error] if [cidr_addr] is not
represented by [cidr_addr]. Raises {!Parse_error} if [cidr_addr] is not
a valid representation of a CIDR-scoped address. *)
val of_address_string_exn : string -> t * addr

Expand Down Expand Up @@ -310,7 +320,7 @@ module V6 : sig
(** {3 Text string conversion} *)

(** [of_string_exn ipv6_string] is the address represented
by [ipv6_string]. Raises [Parse_error] if [ipv6_string] is not a
by [ipv6_string]. Raises {!Parse_error} if [ipv6_string] is not a
valid representation of an IPv6 address. *)
val of_string_exn : string -> t

Expand All @@ -323,7 +333,7 @@ module V6 : sig
val of_string_raw : string -> int ref -> t

(** [to_string ipv6] is the string representation of [ipv6],
i.e. XXX:XX:X::XXX:XX. *)
i.e. [XXX:XX:X::XXX:XX]. *)
val to_string : t -> string

(** [to_buffer buf ipv6] writes the string representation of [ipv6] into the
Expand All @@ -334,27 +344,30 @@ module V6 : sig
the formatter [f]. *)
val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]

(** {3 Bytestring conversion} *)
(** {3 Octets conversion} *)

(** [of_bytes_exn ipv6_octets] is the address represented
by [ipv6_octets]. Raises [Parse_error] if [ipv6_octets] is not a
valid representation of an IPv6 address. *)
val of_bytes_exn : string -> t
(** [of_octets_exn ?off ipv6_octets] is the address represented
by [ipv6_octets], starting from offset [off].
Raises {!Parse_error} if [ipv6_octets] is not a valid representation of
an IPv6 address. *)
val of_octets_exn : ?off:int -> string -> t

(** Same as {!of_bytes_exn} but returns an result type instead of raising
(** Same as {!of_octets_exn} but returns an result type instead of raising
an exception. *)
val of_bytes : string -> (t, [> `Msg of string ]) result
val of_octets : ?off:int -> string -> (t, [> `Msg of string ]) result

(** Same as {!of_bytes_exn} but takes an extra paramenter, the offset into
the bytes for reading. *)
val of_bytes_raw : string -> int -> t
(** [write_octets_exn ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b] starting
from offset [off] within [b]. [b] must be at least [off+16] bytes long or
a {!Parse_error} exception will be raised. *)
val write_octets_exn : ?off:int -> t -> bytes -> unit

(** [to_bytes ipv6] is a string of length 16 encoding [ipv6]. *)
val to_bytes : t -> string

(** [to_bytes_raw ipv6 bytes offset] writes the 16 bytes encoding of [ipv6]
into [bytes] at offset [offset]. *)
val to_bytes_raw : t -> Bytes.t -> int -> unit
(** [write_octets ?off ipv6 b] writes 16 bytes that encode [ipv6] into [b] starting
from offset [off] within [b]. [b] must be at least [off+16] bytes long or
an error is returned. *)
val write_octets : ?off:int -> t -> bytes -> (unit, [> `Msg of string ]) result

(** [to_octets ipv6] returns the 16 bytes representing the [ipv6] octets. *)
val to_octets : t -> string

(** {3 Int conversion} *)

Expand Down Expand Up @@ -436,7 +449,7 @@ module V6 : sig
val network_address : t -> addr -> addr

(** [of_string_exn cidr] is the subnet prefix represented by the CIDR
string, [cidr]. Raises [Parse_error] if [cidr] is not a valid
string, [cidr]. Raises {!Parse_error} if [cidr] is not a valid
representation of a CIDR notation routing prefix. *)
val of_string_exn : string -> t

Expand All @@ -457,7 +470,7 @@ module V6 : sig
val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]

(** [of_address_string_exn cidr_addr] is the address and prefix
represented by [cidr_addr]. Raises [Parse_error] if [cidr_addr] is not
represented by [cidr_addr]. Raises {!Parse_error} if [cidr_addr] is not
a valid representation of a CIDR-scoped address. *)
val of_address_string_exn : string -> t * addr

Expand Down Expand Up @@ -642,7 +655,7 @@ module Prefix : sig
val pp : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]

(** [of_string_exn cidr] is the subnet prefix represented by the CIDR
string, [cidr]. Raises [Parse_error] if [cidr] is not a valid
string, [cidr]. Raises {!Parse_error} if [cidr] is not a valid
representation of a CIDR notation routing prefix. *)
val of_string_exn : string -> t

Expand Down
Loading

0 comments on commit e614dc9

Please sign in to comment.