/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*
* 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;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
-(* XXX preconditions: >= 0 *)
-typedef int off_t
+typedef uint64 off_t
* 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
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
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 \
wrappi_enums.cmo \
wrappi_structs.cmo \
wrappi_c_impl.cmo \
+ wrappi_c_xdr.cmo \
wrappi_c.cmo \
wrappi_main.cmo
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
| _ -> 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
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 <stdlib.h>
+
+#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
)
);
- 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) ()
--- /dev/null
+(* 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 <stdlib.h>
+#include <rpc/xdr.h>
+
+#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
--- /dev/null
+(* 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
(* 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"
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)
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");
+ }
}
#include <string.h>
#include <errno.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
#define STREQ(a,b) (strcmp((a),(b)) == 0)
#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
* 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. */
#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_<name>_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_ */
--- /dev/null
+/* 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#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;
+ }
+}
--- /dev/null
+/* 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rpc/xdr.h>
+
+#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);
+}
--- /dev/null
+/* 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 <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#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_ */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include "wrappi.h"
#include "internal.h"
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);
}