Remote and RPC.
authorRichard W.M. Jones <rjones@redhat.com>
Mon, 2 Jan 2012 14:20:04 +0000 (14:20 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Mon, 2 Jan 2012 19:05:24 +0000 (19:05 +0000)
17 files changed:
.gitignore
APIs/filesize.api
APIs/off_t.api
APIs/pathname.api
generator/.depend
generator/Makefile.am
generator/wrappi_c_impl.ml
generator/wrappi_c_xdr.ml [new file with mode: 0644]
generator/wrappi_c_xdr.mli [new file with mode: 0644]
generator/wrappi_main.ml
lib/Makefile.am
lib/connect.c
lib/internal.h
lib/proto-ssh.c [new file with mode: 0644]
lib/proto-xdr.c [new file with mode: 0644]
lib/proto-xdr.h [new file with mode: 0644]
lib/wrappi.c

index 3d8285c..df7650b 100644 (file)
@@ -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*
index 218a1da..c7d3bbc 100644 (file)
  * 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;
 
index 22dde87..e82a6b1 100644 (file)
@@ -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
index 5672b2d..e11182d 100644 (file)
@@ -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
index 7d2e46e..335882d 100644 (file)
@@ -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
index 19c04e6..cc34af3 100644 (file)
@@ -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
 
index 74f4d39..2b08eb4 100644 (file)
@@ -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 <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
@@ -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 (file)
index 0000000..2eb4b52
--- /dev/null
@@ -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 <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
diff --git a/generator/wrappi_c_xdr.mli b/generator/wrappi_c_xdr.mli
new file mode 100644 (file)
index 0000000..b974521
--- /dev/null
@@ -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
index 322fd8e..2b40ec2 100644 (file)
@@ -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"
index a9f74d7..edcb328 100644 (file)
@@ -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)
index 2062e08..e75ba53 100644 (file)
 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");
+  }
 }
index b9cc57c..69128e9 100644 (file)
@@ -21,6 +21,8 @@
 
 #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)
@@ -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_<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_ */
diff --git a/lib/proto-ssh.c b/lib/proto-ssh.c
new file mode 100644 (file)
index 0000000..117f772
--- /dev/null
@@ -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 <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;
+  }
+}
diff --git a/lib/proto-xdr.c b/lib/proto-xdr.c
new file mode 100644 (file)
index 0000000..aa7a782
--- /dev/null
@@ -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 <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);
+}
diff --git a/lib/proto-xdr.h b/lib/proto-xdr.h
new file mode 100644 (file)
index 0000000..a73fffb
--- /dev/null
@@ -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 <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_ */
index 0e45890..c0350f5 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #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);
 }