+open Inotify
+open Unix
+open Globals
+open Dirwatcher
+open Printf
+
+type channel_pipe = Process of out_channel | Fifo of out_channel
+type signed_fd = Infd of Unix.file_descr | Outfd of Unix.file_descr
+
+(* (1) fdmap maps fifo fds -> service names, for initial read events
+ * (2) pidmap maps pids of currently executing services into fds for sigchlds to
+ * prevent the appearence of zombies and to define the end of a session.
+ * (3) open_fds maps read events into active services
+ *)
+let fdmap: (Unix.file_descr,string*string) Hashtbl.t = Hashtbl.create 1024
+let pidmap: (int,signed_fd*signed_fd*Unix.file_descr) Hashtbl.t = Hashtbl.create 1024
+let backend_prefix = ref ""
+let open_fds: (Unix.file_descr,channel_pipe) Hashtbl.t = Hashtbl.create 1024
+
+
+
+let receive_process_event (idesc:fd_and_fname) (_:fd_and_fname) =
+ printf "Process event\n";flush Pervasives.stdout;
+ let (_,ifd) = idesc in
+ let cp = try Hashtbl.find open_fds ifd with
+ Not_found->
+ printf "Fifo fd disappeared\n";raise Bug
+ in
+ match (cp) with
+ | Fifo(fifo_outchan) ->
+ let process_inchan = in_channel_of_descr ifd in
+ let cont = ref true in
+ let count = ref 0 in
+ count:=!count + 1;
+ while (!cont) do
+ try
+ let curline = input_line process_inchan in
+ printf "Here: %d %s\n" !count curline;flush Pervasives.stdout;
+ fprintf fifo_outchan "%s\n" curline;flush fifo_outchan
+ with
+ | End_of_file|Sys_blocked_io|Unix_error(EPIPE,_,_) ->
+ begin
+ cont:=false
+ end
+ | Unix_error(_,s1,s2) -> printf "Unix error %s - %s\n" s1 s2;flush Pervasives.stdout;cont:=false
+ | e -> printf "Error!!!\n";raise e
+ done
+ | _ -> printf "Bug! Process fd received in the channel handler\n";raise Bug
+
+
+let rec openentry_int fifoin fifoout (abspath:string*string) =
+ let fdin =
+ try openfile fifoin [O_RDONLY;O_NONBLOCK] 0o777 with
+ e->printf "Error opening and connecting FIFO: %s,%o\n" fifoin 0o777;flush Pervasives.stdout;raise e
+ in
+ Hashtbl.replace fdmap fdin abspath;
+ Fdwatcher.add_fd (Some(fifoin),fdin) (Some(fifoout),stdout) receive_fifo_event
+and reopenentry_int fdin fifoin fifoout =
+ close fdin;
+ Fdwatcher.del_fd fdin;
+ let abspath = try
+ Hashtbl.find fdmap fdin with _ -> printf "Bug: Phantom pipe\n";flush Pervasives.stdout;raise Bug
+ in
+ openentry_int fifoin fifoout abspath
+and receive_fifo_event eventdescriptor outdescriptor =
+ let evfname,evfd = eventdescriptor in
+ let (fname_other,fd_other) = outdescriptor in
+ let outfd =
+ match (fname_other) with
+ | Some(str)->
+ (
+ try openfile str [O_WRONLY;O_NONBLOCK] 0o777 with
+ _->printf "Problemo:%s\n" str;flush Pervasives.stdout;stdout
+ )
+ | None-> printf "Bug, nameless pipe\n";raise Bug
+ in
+ let pipe = try Hashtbl.find open_fds evfd with
+ | Not_found ->
+ (* This is a fifo fd for sure *)
+ let execpath,slice_name = Hashtbl.find fdmap evfd in
+ (* Spawn server. We assume that the fd is one fifo opened RW *)
+ let (myinfd,pout) = Unix.pipe () in
+ let (pin,myoutfd) = Unix.pipe () in
+ set_nonblock myinfd;
+ let pid = try create_process execpath [|execpath;slice_name|] pin pout pout with e -> printf "Error executing service: %s\n" execpath;flush Pervasives.stdout;raise e
+ in
+ Hashtbl.add pidmap pid (Infd(myinfd),Outfd(myoutfd),evfd);
+ Hashtbl.add open_fds evfd (Process(out_channel_of_descr myoutfd));
+ Hashtbl.add open_fds myinfd (Fifo(out_channel_of_descr outfd));
+ Fdwatcher.add_fd (None,myinfd) (None,myinfd) receive_process_event;
+ (Process(out_channel_of_descr myoutfd))
+ in
+ let inchan_fd = in_channel_of_descr evfd in
+ match (pipe) with
+ | Process(out_channel) ->
+ let cont = ref true in
+ while (!cont) do
+ try
+ printf "Reading...\n";flush Pervasives.stdout;
+ 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)->
+ reopenentry_int evfd str1 str2
+ | Some(str1),None ->
+ printf "Bug, nameless pipe\n";flush Pervasives.stdout;raise Bug
+ | None,_ ->
+ printf "Race condition -> user deleted file before closing it. Clever ploy, but won't work.\n";
+ flush Pervasives.stdout
+ );
+ cont:=false
+ |Sys_blocked_io ->printf "Sysblockedio\n";flush Pervasives.stdout;
+ cont:=false
+ | _ ->printf "Bug: unhandled exception\n";flush Pervasives.stdout;raise Bug
+ done
+ | _ -> printf "BUG! received process event from fifo\n";raise Bug
+
+
+let mkentry fqp abspath perm =
+ printf "Making entry %s->%s\n" fqp abspath;flush Pervasives.stdout;
+ let fifoin=sprintf "%s.in" fqp in
+ let fifoout=sprintf "%s.out" fqp in
+ (try Unix.unlink fifoin with _ -> ());
+ (try Unix.unlink fifoout with _ -> ());
+ (try
+ Unix.mkfifo (sprintf "%s.in" fqp) 0o666
+ with
+ e->printf "Error creating FIFO: %s->%s,%o\n" fqp fifoin perm;flush Pervasives.stdout;raise e);
+ (try
+ Unix.mkfifo (sprintf "%s.out" fqp) 0o666
+ with
+ e->printf "Error creating FIFO: %s->%s,%o\n" fqp fifoout perm;flush Pervasives.stdout;raise e)
+
+
+let openentry fqp abspath perm =
+ let fifoin = String.concat "." [fqp;"in"] in
+ let fifoout = String.concat "." [fqp;"out"] in
+ openentry_int fifoin fifoout abspath
+
+let sigchld_handle s =
+ let pid,_=Unix.waitpid [Unix.WNOHANG] 0 in
+ try
+ let value = Hashtbl.find pidmap pid in
+ match value with
+ | (Infd(ifd),Outfd(ofd),fd) ->
+ close(ifd);close(ofd);
+ Hashtbl.remove open_fds fd;
+ Fdwatcher.del_fd ifd;
+ Hashtbl.remove pidmap pid
+ | _ -> printf "BUG! Got fds in the wrong order\n";
+ flush Pervasives.stdout;
+ raise Bug
+ with
+ Not_found-> (* Do nothing, probably a grandchild *)
+ ()
+
+
+
+let initialize () =
+ Sys.set_signal Sys.sigchld (Sys.Signal_handle sigchld_handle)