Use splice/tee to connect vsys clients and servers.
authorSapan Bhatia <sapanb@cs.princeton.edu>
Sun, 2 Mar 2008 19:49:55 +0000 (19:49 +0000)
committerSapan Bhatia <sapanb@cs.princeton.edu>
Sun, 2 Mar 2008 19:49:55 +0000 (19:49 +0000)
Makefile
fifowatcher.ml
splice.ml [new file with mode: 0644]
splice_stub.c [new file with mode: 0644]

index 45d0312..55e146c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -30,8 +30,8 @@ docs: *.ml
 ocaml_inotify-0.4/inotify.cmxa:
        $(MAKE) -C ocaml_inotify-0.4 && cp -f ocaml_inotify-0.4/inotify_stubs.o ./
 
-vsys: ocaml_inotify-0.4/inotify.cmxa globals.cmx fdwatcher.cmx conffile.cmx dirwatcher.cmx fifowatcher.cmx frontend.cmx backend.cmx main.cmx docs
-       ocamlopt -I ocaml_inotify-0.4 str.cmxa unix.cmxa inotify.cmxa globals.cmx fdwatcher.cmx dirwatcher.cmx fifowatcher.cmx frontend.cmx backend.cmx str.cmxa conffile.cmx main.cmx -o vsys
+vsys: ocaml_inotify-0.4/inotify.cmxa globals.cmx fdwatcher.cmx conffile.cmx splice_stub.o splice.cmx dirwatcher.cmx fifowatcher.cmx frontend.cmx backend.cmx main.cmx docs 
+       ocamlopt -I ocaml_inotify-0.4 str.cmxa unix.cmxa inotify.cmxa globals.cmx fdwatcher.cmx dirwatcher.cmx splice.cmx splice_stub.o fifowatcher.cmx frontend.cmx backend.cmx str.cmxa conffile.cmx main.cmx -o vsys
 
 vsys.b: ocaml_inotify-0.4/inotify.cma inotify.cmi globals.ml fdwatcher.ml dirwatcher.ml fifowatcher.ml frontend.ml backend.ml main.ml
        ocamlc -g str.cma unix.cma ocaml_inotify-0.4/inotify.cma globals.cmo fdwatcher.cmo dirwatcher.cmo fifowatcher.cmo frontend.cmo backend.cmo str.cma conffile.cmo main.cmo -o vsys.b
index c26295f..061d86b 100644 (file)
@@ -5,14 +5,17 @@ open Unix
 open Globals
 open Dirwatcher
 open Printf
+open Splice
 
 (** A connected process, FIFO *)
-type channel_pipe = Process of out_channel | Fifo of out_channel | BrokenPipe
-(** Signed file descriptors. Usually, we'll make sure that they're not
-  mistreated *)
+type channel_pipe = Process of Unix.file_descr | Fifo of Unix.file_descr | BrokenPipe
+
+(** Signed file descriptors. *)
 type signed_fd = Infd of Unix.file_descr | Outfd of Unix.file_descr | Eventfd of Unix.file_descr
 
+(** XXX This will get deprecated when we switch to inotify *)                                                                                  
 let fdmap: (Unix.file_descr,string*string) Hashtbl.t = Hashtbl.create 1024
+
 (** Maps pids to slice connections. Needed to clean up fds when a script dies
   with EPIPE *)
 let pidmap: (int,signed_fd list) Hashtbl.t = Hashtbl.create 1024
@@ -32,22 +35,16 @@ let receive_process_event (idesc: fname_and_fd) (_: fname_and_fd) =
         fprintf logfd "Fifo fd disappeared\n";flush logfd;raise Bug
   in
     match (cp) with 
-      | Fifo(fifo_outchan) ->
-          let process_inchan = in_channel_of_descr ifd in
-          let cont = ref true in
-            while (!cont) do
-              try 
-                let curline = input_line process_inchan in
-                  fprintf fifo_outchan "%s\n" curline;flush fifo_outchan
-              with 
-                | End_of_file|Sys_blocked_io|Unix_error(EPIPE,_,_)|Unix_error(EBADF,_,_) ->
-                    begin
-                      cont:=false
-                    end
-                | Unix_error(_,s1,s2) -> fprintf logfd "Unix error %s - %s\n" s1 s2;flush logfd;cont:=false
-                | Sys_error(s) -> (* We get this error if the EPIPE comes before the EOF marker*) cont:=false
-                | e -> fprintf logfd "Error - received unexpected event from file system !!!\n";raise e
-            done
+      | Fifo(fifo_outfd) ->
+          begin
+          try
+            printf "Received process event\n";flush Pervasives.stdout;
+            let tr0,tr1 = Unix.pipe () in
+                ignore(splice ifd tr1 4096);
+                ignore(splice tr0 fifo_outfd 4096)
+          with 
+              Failure(s)->fprintf logfd "Transfer failure: %s\n" s;flush logfd
+          end
       | _ -> fprintf logfd "Bug! Process fd received in the channel handler\n";flush logfd;raise Bug
 
 let rec openentry_int fifoin fifoout (abspath:string*string) =
@@ -64,6 +61,7 @@ and reopenentry_int fdin fifoin fifoout =
       Hashtbl.find fdmap fdin with _ -> fprintf logfd "Bug: Phantom pipe\n";flush logfd;raise Bug
     in
       openentry_int fifoin fifoout abspath
+
 (** receive an event from a fifo and connect to the corresponding service, or to
   create it if it doesn't exit 
   @param eventdescriptor Name of input pipe,in descriptor
@@ -102,48 +100,33 @@ and receive_fifo_event eventdescriptor outdescriptor =
                   Hashtbl.add pidmap pid [Infd(script_infd);Outfd(script_outfd);Eventfd(evfd)];
 
                   (* Connect pipe to running script *)
-                  Hashtbl.add open_fds evfd (Process(out_channel_of_descr script_outfd));
+                  Hashtbl.add open_fds evfd (Process(script_outfd));
 
                   (* Connect the running script to the pipe *)
-                  Hashtbl.add open_fds script_infd (Fifo(out_channel_of_descr outfd));
+                  Hashtbl.add open_fds script_infd (Fifo(outfd));
 
                   (* Activate running script *)
                   Fdwatcher.add_fd (None,script_infd) (None,script_infd) receive_process_event;
 
-                  (Process(out_channel_of_descr script_outfd))
+                  (Process(script_outfd))
   in
   (* We have the connection to the process - because it was open, or because it
    just got established *)
-  let inchan_fd = in_channel_of_descr evfd in
     match (pipe) with
-      | Process(out_channel) -> 
-          let cont = ref true in
-            while (!cont) do
-              try 
-                fprintf logfd "Reading...\n";flush logfd;
-                let curline = input_line inchan_fd in
-                  fprintf out_channel "%s\n" curline;flush out_channel 
-              with 
-                |End_of_file->
-                    (
-                      match (evfname,fname_other) with
-                        | Some(str1),Some(str2)->
-                            fprintf logfd "Reopening entry\n";flush logfd;
-                            reopenentry_int evfd str1 str2
-                        | Some(str1),None ->
-                            fprintf logfd "Bug, nameless pipe\n";flush logfd;raise Bug
-                        | None,_ ->
-                            fprintf logfd "Race condition -> user deleted file before closing it. Clever ploy, but won't work.\n";
-                            flush logfd
-                    );
-                    cont:=false
-                |Sys_blocked_io ->fprintf logfd "Sysblockedio\n";flush logfd;
-                                  cont:=false
-                | Unix_error(_,s1,s2) -> fprintf logfd "Unix error %s - %s\n" s1 s2;flush logfd;cont:=false
-                (*| _ ->fprintf logfd "Bug: unhandled exception\n";flush
-                 * logfd;raise Bug*)
-            done;
+      | Process(fifo_outfd) -> 
+          begin
+          try
+            printf "Received fifo event\n";flush Pervasives.stdout;
+            let tr0,tr1 = Unix.pipe() in
+          ignore(splice evfd tr1 4096);
+          ignore(splice tr0 fifo_outfd 4096)
+          with Failure(str) ->
+            begin
+            fprintf logfd "Error connecting user to service: %s\n" str;
+            flush logfd
+            end;
             ignore(sigprocmask SIG_UNBLOCK [Sys.sigchld])
+          end
       | BrokenPipe -> ()
       | Fifo(_) -> fprintf logfd "BUG! received process event from fifo\n";raise Bug
 
diff --git a/splice.ml b/splice.ml
new file mode 100644 (file)
index 0000000..a25d981
--- /dev/null
+++ b/splice.ml
@@ -0,0 +1,7 @@
+open Unix
+
+external splice : Unix.file_descr -> Unix.file_descr -> int -> int
+                   = "stub_splice"
+
+external sendfile : Unix.file_descr -> Unix.file_descr -> int -> int
+                   = "stub_sendfile"
diff --git a/splice_stub.c b/splice_stub.c
new file mode 100644 (file)
index 0000000..a8da686
--- /dev/null
@@ -0,0 +1,42 @@
+/* This module allows data between vsys clients and servers to be copied in kernel -
+ * and some of these copies to be eliminated through page rewrites */
+
+#define SPLICE_SYSCALL 313
+#define TEE_SYSCALL    315
+#define SPLICE_F_NONBLOCK 0x02
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+#include <caml/custom.h>
+#include <caml/fail.h>
+#include <caml/signals.h>
+
+CAMLprim value stub_splice(value fd_in, value fd_out, value len)
+{
+        CAMLparam3(fd_in, fd_out, len);
+       long ret;
+        ret = syscall(SPLICE_SYSCALL, Int_val(fd_in), NULL, Int_val(fd_out),NULL, Int_val(len), SPLICE_F_NONBLOCK);
+        if (ret == -1) {
+               printf ("Splice error: %s\n", strerror(errno));
+                caml_failwith("Splice system call returned -1");
+       }
+        CAMLreturn(Val_int(ret));
+}
+
+CAMLprim value stub_tee(value fd_in, value fd_out, value len)
+{
+        CAMLparam3(fd_in, fd_out, len);
+       long ret;
+        ret = syscall(TEE_SYSCALL,Int_val(fd_in), Int_val(fd_out), Int_val(len), SPLICE_F_NONBLOCK);
+        if (ret == -1) {
+               printf ("Sendfile error: %s\n", strerror(errno));
+                caml_failwith("Splice system call returned -1");
+       }
+        CAMLreturn(Val_int(ret));
+}