Previously nbd_set_tls had an integer argument which was 0 for disable, 1 for allow and 2 for require. This commit adds a proper enumerated type to describe this, defining LIBNBD_TLS_DISABLE = 0, LIBNBD_TLS_ALLOW = 1 and LIBNBD_TLS_REQUIRE = 2. (Note the C API doesn't change). In C the enumerated type is still defined and passed as an int (not as an enum). While we could define an enum type for this, there are ABI stability problems inherent in enums in C. In OCaml this is implemented as a variant type. There is no equivalent for returning an enum (eg. for nbd_get_tls). We should add that later. It won't affect the C API but would change the OCaml API. --- TODO | 2 - generator/generator | 108 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index 65c95ee..8e067c0 100644 --- a/TODO +++ b/TODO @@ -35,8 +35,6 @@ Suggested API improvements: - nbd_connect_command: allow passing char **env TLS: - - nbd_set_tls: either remove optiona (1/2) interface, or - define symbols for it - should be individual APIs for setting each TLS file (set_tls_certificates can continue to exist) - TLS should have a way to pass in PIN or password to diff --git a/generator/generator b/generator/generator index 5823686..73b8b79 100755 --- a/generator/generator +++ b/generator/generator @@ -855,6 +855,7 @@ and arg = | BytesPersistIn of string * string (* same as above, but buffer persists *) | BytesPersistOut of string * string | Closure of closure (* function pointer + void *opaque *) +| Enum of string * enum (* enum/union type, int in C *) | Int of string (* small int *) | Int64 of string (* 64 bit signed int *) | Path of string (* filename or path *) @@ -890,6 +891,10 @@ and cbarg = | CBString of string (* like String *) | CBUInt of string (* like UInt *) | CBUInt64 of string (* like UInt64 *) +and enum = { + enum_prefix : string; (* prefix of each enum variant *) + enums : (string * int) list (* enum names and their values in C *) +} and flags = { flag_prefix : string; (* prefix of each flag name *) flags : (string * int) list (* flag names and their values in C *) @@ -910,6 +915,17 @@ let non_blocking_test_call_description = "\n This call does not block, because it returns data that is saved in the handle from the NBD protocol handshake." +(* Enums. *) +let tls_enum = { + enum_prefix = "TLS"; + enums = [ + "DISABLE", 0; + "ALLOW", 1; + "REQUIRE", 2; + ] +} +let all_enums = [ tls_enum ] + (* Flags. *) let cmd_flags = { flag_prefix = "CMD_FLAG"; @@ -1020,7 +1036,7 @@ Get the export name associated with the handle."; "set_tls", { default_call with - args = [Int "tls"]; ret = RErr; + args = [Enum ("tls", tls_enum)]; ret = RErr; permitted_states = [ Created ]; shortdesc = "enable or require TLS (authentication and encryption)"; longdesc = "\ @@ -1029,12 +1045,12 @@ NBD server. The possible settings are: =over 4 -=item C<tls=0> +=item C<LIBNBD_TLS_DISABLE> Disable TLS. (The default setting, unless using C<nbd_connect_uri> with a URI that requires TLS) -=item C<tls=1> +=item C<LIBNBD_TLS_ALLOW> Enable TLS if possible. In some cases this will fall back to an unencrypted and/or unauthenticated connection if @@ -1042,7 +1058,7 @@ TLS could not be established. However some servers will drop the connection if TLS fails so fallback may not be possible. -=item C<tls=2> +=item C<LIBNBD_TLS_REQUIRE> Require an encrypted and authenticated TLS connection. Always fail to connect if the connection is not encrypted @@ -3307,6 +3323,7 @@ let rec name_of_arg = function | BytesPersistOut (n, len) -> [n; len] | Closure { cbname } -> [ sprintf "%s_callback" cbname; sprintf "%s_user_data" cbname ] +| Enum (n, _) -> [n] | Int n -> [n] | Int64 n -> [n] | Path n -> [n] @@ -3351,6 +3368,9 @@ let rec print_arg_list ?(handle = false) ?(types = true) args optargs = pr ", "; if types then pr "void *"; pr "%s_user_data" cbname + | Enum (n, _) -> + if types then pr "int "; + pr "%s" n | Int n -> if types then pr "int "; pr "%s" n @@ -3512,6 +3532,15 @@ let generate_include_libnbd_h () = pr "\n"; pr "struct nbd_handle;\n"; pr "\n"; + List.iter ( + fun { enum_prefix; enums } -> + List.iter ( + fun (enum, i) -> + let enum = sprintf "LIBNBD_%s_%s" enum_prefix enum in + pr "#define %-40s %d\n" enum i + ) enums; + pr "\n" + ) all_enums; List.iter ( fun { flag_prefix; flags } -> List.iter ( @@ -3701,6 +3730,7 @@ let generate_lib_api_c () = | BytesOut (n, count) | BytesPersistOut (n, count) -> pr " %s=<buf> %s=%%zu" n count | Closure { cbname } -> pr " %s=<fun>" cbname + | Enum (n, _) -> pr " %s=%%d" n | Int n -> pr " %s=%%d" n | Int64 n -> pr " %s=%%\" PRIi64 \"" n | SockAddrAndLen (n, len) -> pr " %s=<sockaddr> %s=%%d" n len @@ -3724,6 +3754,7 @@ let generate_lib_api_c () = | BytesOut (_, count) | BytesPersistOut (_, count) -> pr ", %s" count | Closure { cbname } -> () + | Enum (n, _) -> pr ", %s" n | Int n -> pr ", %s" n | Int64 n -> pr ", %s" n | SockAddrAndLen (_, len) -> pr ", (int) %s" len @@ -4206,6 +4237,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = pr " struct py_aio_buffer *%s_buf;\n" n | Closure { cbname } -> pr " PyObject *%s_user_data;\n" cbname + | Enum (n, _) -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n | Int64 n -> pr " int64_t %s_i64;\n" n; @@ -4248,6 +4280,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = | BytesOut (_, count) -> pr " \"n\"" | BytesPersistOut (_, count) -> pr " \"O\"" | Closure _ -> pr " \"O\"" + | Enum _ -> pr " \"i\"" | Int n -> pr " \"i\"" | Int64 n -> pr " \"L\"" | Path n -> pr " \"O&\"" @@ -4272,6 +4305,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = | BytesPersistOut (n, _) -> pr ", &%s" n | BytesOut (_, count) -> pr ", &%s" count | Closure { cbname } -> pr ", &%s_user_data" cbname + | Enum (n, _) -> pr ", &%s" n | Int n -> pr ", &%s" n | Int64 n -> pr ", &%s" n | Path n -> pr ", PyUnicode_FSConverter, &py_%s" n @@ -4306,6 +4340,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = pr " \"callback parameter %s is not callable\");\n" cbname; pr " return NULL;\n"; pr " }\n" + | Enum _ -> () | Int _ -> () | Int64 n -> pr " %s_i64 = %s;\n" n n | Path n -> @@ -4338,6 +4373,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = | Closure { cbname } -> pr ", %s_%s_wrapper" name cbname; pr ", %s_user_data" cbname + | Enum (n, _) -> pr ", %s" n | Int n -> pr ", %s" n | Int64 n -> pr ", %s_i64" n | Path n -> pr ", %s" n @@ -4373,6 +4409,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = | BytesIn _ | BytesPersistIn _ | BytesPersistOut _ | Closure _ + | Enum _ | Int _ | Int64 _ | Path _ @@ -4413,6 +4450,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = | BytesIn (n, _) -> pr " PyBuffer_Release (&%s);\n" n | BytesPersistIn _ | BytesOut _ | BytesPersistOut _ -> () | Closure _ -> () + | Enum _ -> () | Int _ -> () | Int64 _ -> () | Path n -> @@ -4505,6 +4543,15 @@ Error.__str__ = _str "; + List.iter ( + fun { enum_prefix; enums } -> + List.iter ( + fun (enum, i) -> + let enum = sprintf "%s_%s" enum_prefix enum in + pr "%-30s = %d\n" enum i + ) enums; + pr "\n" + ) all_enums; List.iter ( fun { flag_prefix; flags } -> List.iter ( @@ -4565,6 +4612,7 @@ class NBD (object): | BytesPersistOut (n, _) -> n | BytesOut (_, count) -> count | Closure { cbname } -> cbname + | Enum (n, _) -> n | Int n -> n | Int64 n -> n | Path n -> n @@ -4640,6 +4688,7 @@ and ocaml_arg_to_string = function | BytesPersistOut _ -> "Buffer.t" | Closure { cbargs } -> sprintf "(%s)" (ocaml_closuredecl_to_string cbargs) + | Enum (_, { enum_prefix }) -> sprintf "%s.t" enum_prefix | Int _ -> "int" | Int64 _ -> "int64" | Path _ -> "string" @@ -4686,6 +4735,7 @@ let ocaml_name_of_arg = function | BytesPersistIn (n, len) -> n | BytesPersistOut (n, len) -> n | Closure { cbname } -> cbname + | Enum (n, _) -> n | Int n -> n | Int64 n -> n | Path n -> n @@ -4727,6 +4777,17 @@ exception Closed of string "; + List.iter ( + fun { enum_prefix; enums } -> + pr "module %s : sig\n" enum_prefix; + pr " type t =\n"; + List.iter ( + fun (enum, _) -> + pr " | %s\n" enum + ) enums; + pr "end\n"; + pr "\n" + ) all_enums; List.iter ( fun { flag_prefix; flags } -> pr "module %s : sig\n" flag_prefix; @@ -4819,6 +4880,17 @@ let () = "; + List.iter ( + fun { enum_prefix; enums } -> + pr "module %s = struct\n" enum_prefix; + pr " type t =\n"; + List.iter ( + fun (enum, _) -> + pr " | %s\n" enum + ) enums; + pr "end\n"; + pr "\n" + ) all_enums; List.iter ( fun { flag_prefix; flags } -> pr "module %s = struct\n" flag_prefix; @@ -4874,6 +4946,30 @@ external close : t -> unit = \"nbd_internal_ocaml_nbd_close\" pr "\"nbd_internal_ocaml_nbd_%s\"\n" name ) handle_calls +let print_ocaml_enum_val { enum_prefix; enums } = + pr "/* Convert OCaml %s.t to int. */\n" enum_prefix; + pr "static int\n"; + pr "%s_val (value v)\n" enum_prefix; + pr "{\n"; + pr " CAMLparam1 (v);\n"; + pr " int i, r = 0;\n"; + pr "\n"; + pr " i = Int_val (Field (v, 0));\n"; + pr " /* i is the index of the enum in the type\n"; + pr " * (eg. i = 0 => enum = %s.%s).\n" enum_prefix (fst (List.hd enums)); + pr " * Convert it to the C representation.\n"; + pr " */\n"; + pr " switch (i) {\n"; + List.iteri ( + fun i (enum, _) -> + pr " case %d: r = LIBNBD_%s_%s; break;\n" i enum_prefix enum + ) enums; + pr " }\n"; + pr "\n"; + pr " CAMLreturnT (int, r);\n"; + pr "}\n"; + pr "\n" + let print_ocaml_flag_val { flag_prefix; flags } = pr "/* Convert OCaml %s.t list to uint32_t bitmask. */\n" flag_prefix; pr "static uint32_t\n"; @@ -5097,6 +5193,8 @@ let print_ocaml_binding (name, { args; optargs; ret }) = pr " *%s_user_data = %sv;\n" cbname cbname; pr " caml_register_generational_global_root (%s_user_data);\n" cbname; pr " const void *%s_callback = %s_%s_wrapper;\n" cbname name cbname + | Enum (n, { enum_prefix }) -> + pr " int %s = %s_val (%sv);\n" n enum_prefix n | Int n -> pr " int %s = Int_val (%sv);\n" n n | Int64 n -> @@ -5154,6 +5252,7 @@ let print_ocaml_binding (name, { args; optargs; ret }) = | BytesOut _ | BytesPersistOut _ | Closure _ + | Enum _ | Int _ | Int64 _ | Path _ @@ -5209,6 +5308,7 @@ let generate_ocaml_nbd_c () = pr "#pragma GCC diagnostic ignored \"-Wmissing-prototypes\"\n"; pr "\n"; + List.iter print_ocaml_enum_val all_enums; List.iter print_ocaml_flag_val all_flags; List.iter print_ocaml_binding handle_calls end -- 2.22.0