open Unix let bufsize = 4096 module TMap = Map.Make (struct type t = Thread.t let compare t1 t2 = compare (Thread.id t1) (Thread.id t2) end) type server = { mutable threads: Unix.file_descr TMap.t; sock: Unix.file_descr; log: LogFile.log; mutex: Mutex.t } let stop server = Printf.printf "STOP received: shutting down\n%!"; shutdown server.sock SHUTDOWN_ALL; Mutex.lock server.mutex; let ts = server.threads in Mutex.unlock server.mutex; TMap.iter (fun t s -> shutdown s SHUTDOWN_ALL) ts; sleep 2; LogFile.close server.log let threaded_server log session_fun sock_addr = let announce_death() = Printf.kprintf (LogFile.add log) "t%d terminated" (Thread.id (Thread.self())) in let domain = match sock_addr with | ADDR_UNIX _ -> PF_UNIX | ADDR_INET _ -> PF_INET in let sock = socket domain SOCK_STREAM 0 in let server: server = { threads = TMap.empty; sock = sock; log = log; mutex = Mutex.create() } in let cleanup o = Mutex.lock server.mutex; server.threads <- TMap.remove (Thread.self()) server.threads; Mutex.unlock server.mutex; close_out_noerr o; LogFile.thread log false in let session (fd,a) = LogFile.thread log true; Mutex.lock server.mutex; server.threads <- TMap.add (Thread.self()) fd server.threads; Mutex.unlock server.mutex; let i = in_channel_of_descr fd in let o = out_channel_of_descr fd in try session_fun(a,i,o); raise Exit with Exit -> cleanup o | other -> cleanup o; raise other in let master() = setsockopt sock SO_REUSEADDR true; bind sock sock_addr; listen sock 8; try while true do let cn = try accept sock with Unix_error _ -> raise Exit in ignore(Thread.create session cn) done with Exit -> LogFile.thread log false | Sys.Break -> stop server in master(); server let error_handler req out status = let title = Printf.sprintf "%d: %s" (Status.code status) (Status.text status) in let buf = Buffer.create 1024 in let puts = Buffer.add_string buf in Printf.kprintf puts (* construct html page *) "