open Unix;; open Sys;; open Inet;; (** Installation d'un service. *) let install_service (port, service) = Printf.eprintf "Service \"%s\" on port %d\n" service.(0) port; Pervasives.flush Pervasives.stderr; let socket = open_server port in (socket, service);; (** Exécution d'un service. *) let exec_service command socket = try match fork () with 0 -> let exec () = dup2 socket stdin; dup2 socket stdout; dup2 socket stderr; close socket; execvp command.(0) command; in handle_unix_error exec (); assert false | _ -> close socket with Unix_error ((EAGAIN|ENOMEM),"fork",_) -> close socket; prerr_endline "No more process available";; (** Attente de tous les fils décédés. *) let rec wait_for_children signal = try let pid,_= waitpid [WNOHANG] (-1) in if pid <> 0 then wait_for_children signal with Unix_error(ECHILD,_,_) -> ();; (** Démarrage du démon *) let inetd services = (* Gestion du signal SICHLD pour récupérer les zombis *) ignore (signal sigchld (Signal_handle wait_for_children)); (* On ignore SIGPIPE et on recevra une erreur EPIPE lorsqu'on parle à un client qui à couper brutalement la connection. *) ignore (signal sigpipe Signal_ignore); (* installer les services *) let installed_services = List.map install_service services in (* construire la liste des sockets à écouter *) let sockets = List.map fst installed_services in (* acceptation d'une connexion et démarrage de la command associée *) let rec accept_connection server_socket = try let connection_socket,remote_addr = accept server_socket in Printf.eprintf "Connexion depuis %s\n" (string_of_sockaddr remote_addr); Pervasives.flush Pervasives.stderr; try (* chercher le service associé à la socket *) let command = List.assoc server_socket installed_services in (* exécuter le service avec la connexion fd *) exec_service command connection_socket with Not_found -> close connection_socket with Unix_error(EINTR,_,_) -> accept_connection server_socket in (* traitement du serveur *) let rec treatment () = begin try (* attente d'une connexion sur l'une des sockets *) let connections,_,_ = select sockets [] [] (-1.) in (* acceptation de toutes les connexions en attente sur socket_serveur *) List.iter accept_connection connections with Unix_error (EINTR,_,_) -> () end; treatment () in treatment();; (** Définition des services : liste de (port, command). *) let services = [ (7000, [| "cat" |]); (7001, [| "date"; "-I" |]); (7002, [| "ocaml" |]) ];; handle_unix_error inetd services;; |