From a6d8cf44fbc4fb4a09b3c3bb54701e35f201f997 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 2 Jan 2012 14:20:04 +0000 Subject: [PATCH] Remote and RPC. --- .gitignore | 3 + APIs/filesize.api | 4 +- APIs/off_t.api | 3 +- APIs/pathname.api | 2 +- generator/.depend | 7 +- generator/Makefile.am | 3 + generator/wrappi_c_impl.ml | 157 ++++++++++++++++++++++++++++++++++++++++++--- generator/wrappi_c_xdr.ml | 148 ++++++++++++++++++++++++++++++++++++++++++ generator/wrappi_c_xdr.mli | 21 ++++++ generator/wrappi_main.ml | 1 + lib/Makefile.am | 6 ++ lib/connect.c | 46 +++++++++++-- lib/internal.h | 34 ++++++++-- lib/proto-ssh.c | 112 ++++++++++++++++++++++++++++++++ lib/proto-xdr.c | 153 +++++++++++++++++++++++++++++++++++++++++++ lib/proto-xdr.h | 51 +++++++++++++++ lib/wrappi.c | 14 ++++ 17 files changed, 743 insertions(+), 22 deletions(-) create mode 100644 generator/wrappi_c_xdr.ml create mode 100644 generator/wrappi_c_xdr.mli create mode 100644 lib/proto-ssh.c create mode 100644 lib/proto-xdr.c create mode 100644 lib/proto-xdr.h diff --git a/.gitignore b/.gitignore index 3d8285c..df7650b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ Makefile.in /generator/stamp-generator /install-sh /lib/free_structs.c +/lib/internal-procs.h +/lib/internal-procs.c +/lib/proto-xdr-impl.c /lib/wrappi.h /libtool /local* diff --git a/APIs/filesize.api b/APIs/filesize.api index 218a1da..c7d3bbc 100644 --- a/APIs/filesize.api +++ b/APIs/filesize.api @@ -16,8 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) +typedef uint64 filesize_t + entry_point -off_t filesize (pathname path) +filesize_t filesize (pathname path) << struct stat buf; diff --git a/APIs/off_t.api b/APIs/off_t.api index 22dde87..e82a6b1 100644 --- a/APIs/off_t.api +++ b/APIs/off_t.api @@ -16,5 +16,4 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) -(* XXX preconditions: >= 0 *) -typedef int off_t +typedef uint64 off_t diff --git a/APIs/pathname.api b/APIs/pathname.api index 5672b2d..e11182d 100644 --- a/APIs/pathname.api +++ b/APIs/pathname.api @@ -16,5 +16,5 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) -(* XXX precondition that this is non-empty *) +(* XXX precondition that this is non-empty, starts with "/" character *) typedef string pathname diff --git a/generator/.depend b/generator/.depend index 7d2e46e..335882d 100644 --- a/generator/.depend +++ b/generator/.depend @@ -7,11 +7,14 @@ wrappi_c.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c.cmi wrappi_c_impl.cmi: wrappi_c_impl.cmo: wrappi_pr.cmi wrappi_boilerplate.cmi wrappi_c_impl.cmi wrappi_c_impl.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c_impl.cmi +wrappi_c_xdr.cmi: +wrappi_c_xdr.cmo: wrappi_pr.cmi wrappi_boilerplate.cmi wrappi_c_xdr.cmi +wrappi_c_xdr.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c_xdr.cmi wrappi_enums.cmi: wrappi_enums.cmo: wrappi_enums.cmi wrappi_enums.cmx: wrappi_enums.cmi -wrappi_main.cmo: wrappi_structs.cmi wrappi_pr.cmi wrappi_enums.cmi wrappi_c_impl.cmi wrappi_c.cmi -wrappi_main.cmx: wrappi_structs.cmx wrappi_pr.cmx wrappi_enums.cmx wrappi_c_impl.cmx wrappi_c.cmx +wrappi_main.cmo: wrappi_structs.cmi wrappi_pr.cmi wrappi_enums.cmi wrappi_c_xdr.cmi wrappi_c_impl.cmi wrappi_c.cmi +wrappi_main.cmx: wrappi_structs.cmx wrappi_pr.cmx wrappi_enums.cmx wrappi_c_xdr.cmx wrappi_c_impl.cmx wrappi_c.cmx wrappi_pr.cmi: wrappi_pr.cmo: wrappi_pr.cmi wrappi_pr.cmx: wrappi_pr.cmi diff --git a/generator/Makefile.am b/generator/Makefile.am index 19c04e6..cc34af3 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -28,6 +28,8 @@ SOURCES = \ wrappi_boilerplate.ml \ wrappi_c_impl.mli \ wrappi_c_impl.ml \ + wrappi_c_xdr.mli \ + wrappi_c_xdr.ml \ wrappi_c.mli \ wrappi_c.ml \ wrappi_enums.mli \ @@ -45,6 +47,7 @@ OBJECTS = \ wrappi_enums.cmo \ wrappi_structs.cmo \ wrappi_c_impl.cmo \ + wrappi_c_xdr.cmo \ wrappi_c.cmo \ wrappi_main.cmo diff --git a/generator/wrappi_c_impl.ml b/generator/wrappi_c_impl.ml index 74f4d39..2b08eb4 100644 --- a/generator/wrappi_c_impl.ml +++ b/generator/wrappi_c_impl.ml @@ -150,10 +150,13 @@ pr "\ pr_defn ep; pr "{\n"; - pr " if (w->scheme == NULL) {\n"; + pr " /* XXX Argument precondition checks here. */\n"; + pr "\n"; + pr " if (w->scheme == WRAP_SCHEME_LOCAL) {\n"; pr " /* Local connection. */\n"; pr " "; + let name = ep.ep_name in let ret, req, opt = ep.ep_ftype in (match ret with @@ -161,10 +164,10 @@ pr "\ | _ -> pr "return " ); - pr "impl_%s ((struct wrap_internal_h *)w" ep.ep_name; + pr "impl_%s ((struct wrap_internal_h *)w" name; (* Required parameters. *) - List.iter (fun (name, _, _) -> pr ", %s" name) req; + List.iter (fun (n, _, _) -> pr ", %s" n) req; (* Optional parameters. *) if opt <> [] then @@ -179,12 +182,144 @@ pr "\ pr " } else {\n"; pr " /* Remote connection. */\n"; - pr " abort (); /* XXX */\n"; + pr " struct wrap_int_%s_args args;\n" name; + pr " struct wrap_int_%s_ret ret;\n" name; + pr "\n"; + List.iter (fun (n, _, _) -> pr " args.%s = %s;\n" n n) req; + + if opt <> [] then assert false; (* XXX not implemented *) + pr "\n"; + + pr " memset (&ret, 0, sizeof ret);\n"; + pr "\n"; + + pr " wrap_int_make_request (w, wrap_int_%s_num,\n" name; + pr " &args, &ret);\n"; + + (match ret with + | RVoid -> () + | _ -> + pr "\n"; + pr " return ret.r;\n" + ); + pr " }\n"; pr "}\n" ) +let generate_lib_internal_procs_h api = + generate_header inputs CStyle LGPLv2plus; + + pr "\ +#ifndef WRAPPI_INTERNAL_PROCS_H_ +#define WRAPPI_INTERNAL_PROCS_H_ + +"; + + pr "\ +/* NOTE: These constants can change with each run of the generator. + * They are only for internal use within the library, eg. for indexing + * arrays. The constants must not 'escape' from the library into + * on-the-wire formats etc. + */ +enum { +"; + + iter_entry_points api ( + fun ep -> pr " wrap_int_%s_num,\n" ep.ep_name + ); + + pr "};\n"; + pr "\n"; + + pr "#define wrap_int_nr_procs %d\n" (StringMap.cardinal api.api_entry_points); + + pr "\n"; + + pr "\ +/* These structures are used as the first stage of marshalling + * arguments and return types of entry points. It is much more + * convenient to be able to pass around one of these structs, + * than to have to pass a variable list of arguments. They must + * not be exposed externally. + */ +"; + + iter_entry_points api ( + fun ep -> + let name = ep.ep_name in + let ret, req, opt = ep.ep_ftype in + + pr "struct wrap_int_%s_args {\n" name; + List.iter ( + fun (n, t, _) -> + let t = c_of_ptype ~param:true t in + let sep = (* "const char *" - omit space after asterisk *) + let len = String.length t in + if isalnum t.[len-1] then " " else "" in + pr " %s%s%s;\n" t sep n + ) req; + pr "};\n"; + pr "\n"; + + if opt <> [] then assert false; (* XXX not implemented *) + + pr "struct wrap_int_%s_ret {\n" name; + (match ret with + | RVoid -> () + | RStaticString -> pr " const char *r;\n"; + | Return t -> + let t = c_of_ptype ~param:false t in + let sep = (* "const char *" - omit space after asterisk *) + let len = String.length t in + if isalnum t.[len-1] then " " else "" in + pr " %s%sr;\n" t sep + ); + + pr "};\n"; + pr "\n"; + ); + + iter_entry_points api ( + fun ep -> + if not ep.ep_local then ( + let name = ep.ep_name in + pr "extern bool_t wrap_int_xdr_%s_args (XDR *, struct wrap_int_%s_args *);\n" name name; + pr "extern bool_t wrap_int_xdr_%s_ret (XDR *, struct wrap_int_%s_ret *);\n" name name + ) + ); + + pr "\n"; + pr "#endif /* WRAPPI_INTERNAL_PROCS_H_ */\n" + +let generate_lib_internal_procs_c api = + generate_header inputs CStyle LGPLv2plus; + + pr "\ +#include + +#include \"wrappi.h\" +#include \"internal.h\" + +"; + + pr "const struct proc_table wrap_int_proc_table[] = {\n"; + + iter_entry_points api ( + fun ep -> + let name = ep.ep_name in + pr " [wrap_int_%s_num] = {\n" name; + pr " .name = \"%s\",\n" name; + if not ep.ep_local then ( + pr " .xdr_args = (xdrproc_t) &wrap_int_xdr_%s_args,\n" name; + pr " .xdr_ret = (xdrproc_t) &wrap_int_xdr_%s_ret,\n" name; + ); + pr " },\n" + ); + + pr "};\n" + (* Make a unique, reproducible filename for each entry point. *) let filename_of_ep ep = let filename = Loc.file_name ep.ep_loc in @@ -236,9 +371,15 @@ let generate api = ) ); - let gitignores = List.rev !gitignores in - output_to "lib/.gitignore" - (fun () -> List.iter (pr "%s\n") gitignores) (); + output_to "lib/internal-procs.h" + generate_lib_internal_procs_h api; + + output_to "lib/internal-procs.c" + generate_lib_internal_procs_c api; output_to "lib/implementation_files.mk" - generate_lib_implementation_files_mk api + generate_lib_implementation_files_mk api; + + let gitignores = List.rev !gitignores in + output_to "lib/.gitignore" + (fun () -> List.iter (pr "%s\n") gitignores) () diff --git a/generator/wrappi_c_xdr.ml b/generator/wrappi_c_xdr.ml new file mode 100644 index 0000000..2eb4b52 --- /dev/null +++ b/generator/wrappi_c_xdr.ml @@ -0,0 +1,148 @@ +(* wrappi + * Copyright (C) 2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +open Camlp4.PreCast + +open Wrappi_utils +open Wrappi_types +open Wrappi_boilerplate +open Wrappi_pr + +open Printf + +let inputs = ["wrappi_c_xdr.ml"] + +(* Traditionally 'rpcgen' is used to generate this code. However the + * glibc maintainers have shown no interest (in fact, malign influence) + * in doing a proper job maintaining this, resulting in bitrot and poor + * code being generated. In any case the code that rpcgen makes is + * relatively simple. + *) + +let pr_xdr_of_ptype n = function + | TBool -> + pr " if (!xdr_bool (xdrs, &%s)) return FALSE;\n" n + | TBuffer -> assert false (* XXX not implemented *) + | TEnum _ -> + pr " if (!xdr_int (xdrs, &%s)) return FALSE;\n" n + | TFile -> assert false (* XXX not implemented *) + | THash t -> assert false (* XXX not implemented *) + | TInt -> (* XXX not int, correct type depends on preconditions *) + pr " if (!xdr_int (xdrs, &%s)) return FALSE;\n" n + | TInt32 -> + pr " if (!xdr_int32_t (xdrs, &%s)) return FALSE;\n" n + | TInt64 -> + pr " if (!xdr_int64_t (xdrs, &%s)) return FALSE;\n" n + | TList t -> assert false (* XXX not implemented *) + | TNullable TString -> + pr " if (!xdr_pointer (xdrs, &%s, sizeof (unlimited_string), (xdrproc_t) xdr_unlimited_string)) return FALSE;\n" n + | TNullable _ -> assert false (* XXX may be implemented in future *) + | TString -> + pr " if (!xdr_unlimited_string (xdrs, (void *) &%s)) return FALSE;\n" n + | TStruct sname -> + pr " if (!xdr_struct_%s (xdrs, %s)) return FALSE;\n" sname n + | TTypedef name -> assert false (* should never happen *) + | TUInt32 -> + pr " if (!xdr_uint32_t (xdrs, &%s)) return FALSE;\n" n + | TUInt64 -> + pr " if (!xdr_uint64_t (xdrs, &%s)) return FALSE;\n" n + | TUnion uname -> + pr " if (!xdr_union_%s (xdrs, %s)) return FALSE;\n" uname n + +let generate_lib_proto_xdr_impl_c api = + generate_header inputs CStyle LGPLv2plus; + + pr "\ +#include +#include + +#include \"wrappi.h\" +#include \"internal.h\" + +/* An unlimited length string. */ +typedef char *unlimited_string; + +static bool_t +xdr_unlimited_string (XDR *xdrs, unlimited_string *objp) +{ + if (!xdr_string (xdrs, objp, ~0)) return FALSE; + return TRUE; +} +"; + + iter_structs api ( + fun sd -> + let name = sd.sd_name in + + pr "\n"; + pr "static bool_t\n"; + pr "xdr_struct_%s (XDR *xdrs, struct wrap_%s *objp)\n" name name; + pr "{\n"; + + Array.iter ( + fun (n, t) -> + pr_xdr_of_ptype (sprintf "objp->%s" n) t + ) sd.sd_fields; + + pr " return TRUE;\n"; + pr "}\n"; + ); + + iter_entry_points api ( + fun ep -> + if not ep.ep_local then ( + let name = ep.ep_name in + let ret, req, opt = ep.ep_ftype in + + pr "\n"; + pr "bool_t\n"; + pr "wrap_int_xdr_%s_args (XDR *xdrs, struct wrap_int_%s_args *args)\n" + name name; + pr "{\n"; + + List.iter ( + fun (n, t, _) -> + pr_xdr_of_ptype (sprintf "args->%s" n) t + ) req; + + if opt <> [] then assert false; (* XXX not implemented *) + + pr " return TRUE;\n"; + pr "}\n"; + + pr "\n"; + pr "bool_t\n"; + pr "wrap_int_xdr_%s_ret (XDR *xdrs, struct wrap_int_%s_ret *ret)\n" + name name; + pr "{\n"; + + (match ret with + | RVoid -> () + | RStaticString -> + assert false (* RStaticString cannot be used for remote functions. *) + | Return t -> + pr_xdr_of_ptype "ret->r" t + ); + + pr " return TRUE;\n"; + pr "}\n" + ) + ) + +let generate api = + output_to "lib/proto-xdr-impl.c" generate_lib_proto_xdr_impl_c api diff --git a/generator/wrappi_c_xdr.mli b/generator/wrappi_c_xdr.mli new file mode 100644 index 0000000..b974521 --- /dev/null +++ b/generator/wrappi_c_xdr.mli @@ -0,0 +1,21 @@ +(* wrappi + * Copyright (C) 2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +(** Generate the XDR RPC code. *) + +val generate : Wrappi_types.api -> unit diff --git a/generator/wrappi_main.ml b/generator/wrappi_main.ml index 322fd8e..2b40ec2 100644 --- a/generator/wrappi_main.ml +++ b/generator/wrappi_main.ml @@ -120,6 +120,7 @@ Run it from the top source directory using the command (* Generate code. *) Wrappi_c_impl.generate api; + Wrappi_c_xdr.generate api; Wrappi_c.generate api; printf "generated %d lines of code in %d files\n" diff --git a/lib/Makefile.am b/lib/Makefile.am index a9f74d7..edcb328 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -31,6 +31,12 @@ libwrappi_la_SOURCES = \ wrappi.c \ connect.c \ free_structs.c \ + internal-procs.c \ + internal-procs.h \ + proto-ssh.c \ + proto-xdr.c \ + proto-xdr.h \ + proto-xdr-impl.c \ $(local_implementation_files) \ $(remote_implementation_files) libwrappi_la_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) diff --git a/lib/connect.c b/lib/connect.c index 2062e08..e75ba53 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -28,18 +28,56 @@ void wrap_connect (wrap_h *w) { - /* Remote not implemented yet. */ - assert (w->scheme == NULL); + switch (w->scheme) { + case WRAP_SCHEME_LOCAL: + /* nothing needed */ + return; + + case WRAP_SCHEME_SSH: + wrap_int_connect_ssh (w); + return; + + default: + set_error ("invalid scheme"); + return; + } } void wrap_set_scheme (wrap_h *w, wrap_scheme_enum scheme) { - /* XXX */ + if (scheme < 0 || scheme >= wrap_scheme_enum_nr(w)) { + set_error ("scheme out of range"); + return; + } + w->scheme = scheme; } void wrap_set_hostname (wrap_h *w, const char *hostname) { - /* XXX */ + if (hostname == NULL || strlen (hostname) == 0) { + set_error ("invalid hostname"); + return; + } + w->hostname = strdup (hostname); + if (!w->hostname) + set_error_errno ("strdup"); +} + +void +wrap_int_make_request (wrap_h *w, int proc_nr, const void *args, void *ret) +{ + switch (w->scheme) { + case WRAP_SCHEME_LOCAL: + abort (); /* shouldn't be reachable */ + + /* XDR-based methods. */ + case WRAP_SCHEME_SSH: + wrap_int_make_request_xdr (w, proc_nr, args, ret); + break; + + default: + set_error ("invalid scheme"); + } } diff --git a/lib/internal.h b/lib/internal.h index b9cc57c..69128e9 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -21,6 +21,8 @@ #include #include +#include +#include #define STREQ(a,b) (strcmp((a),(b)) == 0) #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0) @@ -51,11 +53,16 @@ struct wrap_h { * on the local side of a connection. */ - /* Connection URL. If scheme = NULL, it means we're using the local - * code. + uint32_t serial; /* Serial number used in protocol. */ + + FILE *rfp, *wfp; /* Connection to remote. */ + pid_t pid; /* Child process if using remote, eg ssh */ + + /* Connection URL. If scheme == LOCAL, it means we're using the + * local code. */ - const char *scheme; - const char *hostname; + wrap_scheme_enum scheme; + char *hostname; }; /* Declare an error, setting the error field in the handle. */ @@ -64,7 +71,26 @@ struct wrap_h { #define set_error_errno(fs...) \ wrap_int_set_error_errno ((struct wrap_internal_h *)w, (errno), __func__, fs) +extern void wrap_int_connect_ssh (wrap_h *w); +extern void wrap_int_make_request (wrap_h *w, int proc_nr, const void *args, void *ret); +extern void wrap_int_make_request_xdr (wrap_h *w, int proc_nr, const void *args, void *ret); extern void wrap_int_set_error (struct wrap_internal_h *w, const char *func, const char *fs, ...); extern void wrap_int_set_error_errno (struct wrap_internal_h *w, int errnum, const char *func, const char *fs, ...); +/* See lib/internal-procs.c for the static contents of this table. + * The table is indexed by wrap_int__num. These are defined in + * lib/internal-procs.h. + */ +struct proc_table { + const char *name; /* The name of this entry point. */ + + /* XDR encode/decode functions for serializing the args and ret. */ + xdrproc_t xdr_args; + xdrproc_t xdr_ret; +}; + +extern const struct proc_table wrap_int_proc_table[]; + +#include "internal-procs.h" + #endif /* WRAPPI_INTERNAL_H_ */ diff --git a/lib/proto-ssh.c b/lib/proto-ssh.c new file mode 100644 index 0000000..117f772 --- /dev/null +++ b/lib/proto-ssh.c @@ -0,0 +1,112 @@ +/* wrappi + * Copyright (C) 2011-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include +#include + +#include "wrappi.h" +#include "internal.h" + +void +wrap_int_connect_ssh (wrap_h *w) +{ + int rfd[2]; + int wfd[2]; + + if (pipe (rfd) == -1) { + set_error_errno ("pipe"); + return; + } + + if (pipe (wfd) == -1) { + set_error_errno ("pipe"); + close (rfd[0]); + close (rfd[1]); + return; + } + + w->pid = fork (); + if (w->pid == -1) { + set_error_errno ("fork"); + close (rfd[0]); + close (rfd[1]); + close (wfd[0]); + close (wfd[1]); + return; + } + + if (w->pid == 0) { + /* Child process. */ + close (wfd[1]); + close (rfd[0]); + + close (0); + close (1); + dup2 (rfd[1], 1); + dup2 (wfd[0], 0); + + execlp ("ssh", + "ssh", + "-T", "-o", "BatchMode=yes", "-e", "none", + w->hostname, + "sh", "-c", "cat", + NULL); + perror ("ssh"); + _exit (EXIT_FAILURE); + } + + /* Parent process. */ + close (wfd[0]); + close (rfd[1]); + + if (w->rfp) { + fclose (w->rfp); + w->rfp = NULL; + } + + if (w->wfp) { + fclose (w->wfp); + w->wfp = NULL; + } + + w->rfp = fdopen (rfd[0], "r"); + if (w->rfp == NULL) { + set_error_errno ("fdopen: rfp"); + close (rfd[0]); + close (wfd[1]); + waitpid (w->pid, NULL, 0); + w->pid = 0; + return; + } + + w->wfp = fdopen (wfd[1], "w"); + if (w->wfp == NULL) { + set_error_errno ("fdopen: wfp"); + fclose (w->rfp); + w->rfp = NULL; + close (wfd[1]); + waitpid (w->pid, NULL, 0); + w->pid = 0; + return; + } +} diff --git a/lib/proto-xdr.c b/lib/proto-xdr.c new file mode 100644 index 0000000..aa7a782 --- /dev/null +++ b/lib/proto-xdr.c @@ -0,0 +1,153 @@ +/* wrappi + * Copyright (C) 2011-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include + +#include "wrappi.h" +#include "internal.h" +#include "proto-xdr.h" + +bool_t +wrap_int_xdr_message_header (XDR *xdrs, struct wrap_int_message_header *hdr) +{ + if (!xdr_uint32_t (xdrs, &hdr->magic)) return FALSE; + if (!xdr_uint32_t (xdrs, &hdr->protocol)) return FALSE; + if (!xdr_uint32_t (xdrs, &hdr->serial)) return FALSE; + if (!xdr_string (xdrs, &hdr->proc, ~0)) return FALSE; + if (!xdr_uint32_t (xdrs, &hdr->type)) return FALSE; + + return TRUE; +} + +bool_t +wrap_int_xdr_message_error (XDR *xdrs, struct wrap_int_message_error *err) +{ + if (!xdr_string (xdrs, &err->error_message, ~0)) return FALSE; + if (!xdr_string (xdrs, &err->error_errno, 32)) return FALSE; + if (!xdr_string (xdrs, &err->error_func, 256)) return FALSE; + + return TRUE; +} + +void +wrap_int_make_request_xdr (wrap_h *w, int proc_nr, const void *args, void *ret) +{ + XDR xdr; + xdrproc_t xdrp_args; + xdrproc_t xdrp_ret; + struct wrap_int_message_header hdr; + struct wrap_int_message_error err; + + memset (&hdr, 0, sizeof hdr); + + hdr.proc = (char *) wrap_int_proc_table[proc_nr].name; + assert (hdr.proc); + xdrp_args = wrap_int_proc_table[proc_nr].xdr_args; + assert (xdrp_args); + xdrp_ret = wrap_int_proc_table[proc_nr].xdr_ret; + assert (xdrp_ret); + + /* Construct the header. */ + w->serial++; + + hdr.magic = WRAP_INT_PROTO_MAGIC; + hdr.protocol = WRAP_INT_PROTOCOL; + hdr.serial = w->serial; + hdr.type = WRAP_INT_PROTO_TYPE_REQUEST; + + /* Send the header. */ + xdrstdio_create (&xdr, w->wfp, XDR_ENCODE); + if (!wrap_int_xdr_message_header (&xdr, &hdr)) { + set_error ("error sending request header"); + xdr_destroy (&xdr); + return; + } + + /* Send the request arguments. */ + if (!xdrp_args (&xdr, (void *) args)) { + set_error ("error sending request arguments"); + xdr_destroy (&xdr); + return; + } + xdr_destroy (&xdr); + + /* Receive the reply header. */ + xdrstdio_create (&xdr, w->rfp, XDR_DECODE); + memset (&hdr, 0, sizeof hdr); + if (!wrap_int_xdr_message_header (&xdr, &hdr)) { + set_error ("error receiving reply header"); + xdr_destroy (&xdr); + return; + } + + /* Check the reply header. */ + if (hdr.magic != WRAP_INT_PROTO_MAGIC) { + set_error ("error in reply: unexpected magic (%x)", hdr.magic); + xdr_destroy (&xdr); + return; + } + if (hdr.protocol != WRAP_INT_PROTOCOL) { + set_error ("error in reply: unexpected protocol number (%d)", hdr.protocol); + xdr_destroy (&xdr); + return; + } + if (hdr.serial != w->serial) { + set_error ("error in reply: unexpected serial (%d)", hdr.serial); + xdr_destroy (&xdr); + return; + } + + switch (hdr.type) { + case WRAP_INT_PROTO_TYPE_REPLY: + /* Receive the return value. */ + if (!xdrp_ret (&xdr, (void *) ret)) { + set_error ("error receiving return value"); + xdr_destroy (&xdr); + return; + } + break; + + case WRAP_INT_PROTO_TYPE_ERROR: + /* Receive the error message etc. */ + memset (&err, 0, sizeof err); + if (!wrap_int_xdr_message_error (&xdr, &err)) { + set_error ("error receiving error message"); + xdr_destroy (&xdr); + return; + } + + /* XXX errno should be converted to an integer here */ + /* XXX func should be set, but it's not static! */ + set_error ("%s", err.error_message); + xdr_free ((xdrproc_t) wrap_int_xdr_message_error, (void *) &err); + + break; + + default: + set_error ("error in reply: unexpected type (%x)", hdr.type); + xdr_destroy (&xdr); + return; + } + + xdr_destroy (&xdr); +} diff --git a/lib/proto-xdr.h b/lib/proto-xdr.h new file mode 100644 index 0000000..a73fffb --- /dev/null +++ b/lib/proto-xdr.h @@ -0,0 +1,51 @@ +/* wrappi + * Copyright (C) 2011-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PROTO_XDR_H_ +#define PROTO_XDR_H_ + +#include +#include +#include +#include +#include + +#define WRAP_INT_PROTO_MAGIC 0x57524150 /* 'W' 'R' 'A' 'P' */ +#define WRAP_INT_PROTOCOL 1 +#define WRAP_INT_PROTO_TYPE_REQUEST 1 +#define WRAP_INT_PROTO_TYPE_REPLY 2 +#define WRAP_INT_PROTO_TYPE_ERROR 3 + +struct wrap_int_message_header { + uint32_t magic; /* WRAP_INT_PROTO_MAGIC */ + uint32_t protocol; /* protocol version */ + uint32_t serial; /* message serial number */ + char *proc; /* procedure name */ + uint32_t type; /* WRAP_INT_PROTO_TYPE_* */ +}; + +struct wrap_int_message_error { + char *error_message; /* error message */ + char *error_errno; /* errno as string, eg. "EINVAL", or empty */ + char *error_func; /* function where error occurred */ +}; + +extern bool_t wrap_int_xdr_message_header (XDR *, struct wrap_int_message_header *); +extern bool_t wrap_int_xdr_message_error (XDR *, struct wrap_int_message_error *); + +#endif /* WRAPPI_INTERNAL_H_ */ diff --git a/lib/wrappi.c b/lib/wrappi.c index 0e45890..c0350f5 100644 --- a/lib/wrappi.c +++ b/lib/wrappi.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "wrappi.h" #include "internal.h" @@ -32,12 +34,24 @@ wrap_create (void) if (w == NULL) return NULL; + w->serial = random (); + return w; } void wrap_close (wrap_h *w) { + if (w->pid) + waitpid (w->pid, NULL, 0); + + if (w->rfp != NULL) + fclose (w->rfp); + + if (w->wfp != NULL) + fclose (w->wfp); + + free (w->hostname); free (w); } -- 1.8.3.1