Plasma GitLab Archive
Projects Blog Knowledge

open Rtypes
open Xdr
open Rpc
open Rpc_server
open Wdstated_aux
open Printf
open Unix
open Arg
open Wdstated_config

let server_port = ref 0
let sessions = Hashtbl.create 10000
let last_sweep = ref (gettimeofday ())
let config_location = ref "./wdstated.conf"
let fork_into_background = ref false

let _ = Arg.parse 
	  [("-f", Set_string config_location, "location of the config file");
	   ("-d", Set fork_into_background, "fork into the background as a daemon")]
	  (fun arg -> raise (Invalid_argument arg))
	  "Web State Daemon, a small daemon for maintaining the state of web applications"

let cfg = ref (getconfig !config_location)

let code_success = 0l
let code_authfail = 1l
let code_error = 2l
let code_timeout = 3l
let code_notfound = 4l
let code_exists = 5l

exception Authentication_failed
let authenticate user password =
  try
    if not ((Hashtbl.find !cfg.users user) = password) then
      raise Authentication_failed
  with Not_found -> raise Authentication_failed

let sweep_sessions () =
  let expired = 
    Hashtbl.fold
      (fun k (timestamp, timeout, _) l -> 
	 if (int_of_float ((gettimeofday ()) -. timestamp)) > timeout then
	   k :: l
	 else
	   l)
      sessions
      []
  in
    List.iter (fun k -> Hashtbl.remove sessions k) expired

let do_sweep time = 
  if (int_of_float (time -. !last_sweep)) > !cfg.sweep then
    (last_sweep := time;
     sweep_sessions ())

let put_session (user, password, timeout, key, session_data) =
  try
    authenticate user password;
    do_sweep (gettimeofday ());
    if not (Hashtbl.mem sessions key) then
      (Hashtbl.add sessions key (gettimeofday (), Int32.to_int timeout, session_data);
       code_success)
    else
      code_exists
  with 
      Authentication_failed -> code_authfail
    | _ -> code_error

let replace_session (user, password, timeout, key, session_data) =
  try
    Hashtbl.remove sessions key;
    put_session (user, password, timeout, key, session_data)
  with
      Authentication_failed -> code_authfail
    | _ -> code_error
  
let get_session (user, password, key) = 
  try
    let time = gettimeofday () in
      authenticate user password;
      do_sweep time;
      let (timestamp, timeout, session_data) = Hashtbl.find sessions key in
	if (int_of_float (time -. timestamp)) > timeout then
	  {result_code=code_timeout;serialized_data=""}
	else
	  (Hashtbl.replace sessions key (time, timeout, session_data);
	   {result_code=code_success;
	    serialized_data=session_data})
  with
      Not_found -> {result_code=code_notfound;serialized_data=""}
    | Authentication_failed -> {result_code=code_authfail;serialized_data=""}
    | _ -> {result_code=code_error;serialized_data=""}

let serv() =
  let esys = Unixqueue.create_unix_event_system() in
  let server =
    Wdstated_srv.Wdstated.V1.create_server
      ~proc_put_session: put_session
      ~proc_get_session: get_session
      ~proc_replace_session: replace_session
      Rpc_server.Portmapped
      Tcp
      Socket
      esys
  in

    List.iter
      (fun signal ->
	 Sys.set_signal 
         signal
	 (Sys.Signal_handle (fun _ -> Rpc_server.stop_server server;exit 0)))
      [ Sys.sigint; Sys.sigquit; Sys.sigterm ];

    Sys.set_signal
      Sys.sighup
      (Sys.Signal_handle (fun s -> cfg := getconfig !config_location));

    Sys.set_signal
      Sys.sigpipe
      Sys.Signal_ignore;

    (* ask the portmapper to allocate a port for us *)
    server_port := Rpc_portmapper.port_of_program 
      Wdstated_aux.program_Wdstated'V1 "localhost" Tcp;

    (* server loop *)
    try
      Unixqueue.run esys;
      Rpc_server.stop_server server
    with _ -> 
      try Rpc_server.stop_server server with _ -> ()          
;;

let main () = 
  while true
  do
    serv();
    sleep 1
  done

let _ = 
  if !fork_into_background then
    (close stdin;
     close stdout;
     close stderr;
     if fork () = 0 then
       main ()
     else
       exit 0)
  else
    main ()
;;

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml