open Unix;;
open Printf;;

exception Recoverable_exception of string;;

let open_udp_server port =
  let socket = socket PF_INET SOCK_DGRAM 0 in
  bind socket (ADDR_INET (inet_addr_anyport));
  socket;;

let string_of_sockaddr s =
  match s with
    ADDR_UNIX s -> s
  | ADDR_INET (inet,p) -> (string_of_inet_addr inet)^":"^(string_of_int p);;

let establish_udp_server (f:file_descr -> sockaddr -> string -> unitport =
  let buffer_size = 1024 in
  let buffer = String.create buffer_size in
  let server = open_udp_server port in
  while true do
    let n,client = recvfrom server buffer 0 buffer_size [] in
    let request = String.sub buffer 0 n in
    eprintf "J'ai lu \"%s\" envoyés par %s.\n" request (string_of_sockaddr client);
    Pervasives.flush Pervasives.stderr;
    try
      f server client request
    with Recoverable_exception s ->
      eprintf "Erreur du serveur: %s\n" s;
      Pervasives.flush Pervasives.stderr
  done;;

let uppercase serveur client s =
  ignore (sendto serveur (String.uppercase s) 0 (String.length s) [] client);;

let port_of_string port =
  try
    try
      (getservbyname port "tcp").s_port
    with Not_found -> int_of_string port
  with _ -> raise (Failure "port_of_string");;

let main () =
  if Array.length Sys.argv <> 2 then
    begin
      prerr_endline ("Usage: "^Sys.argv.(0)^" port");
      exit 1
    end
  else
    try
      let port = port_of_string Sys.argv.(1) in
      establish_udp_server uppercase port
    with
      Failure "port_of_string" ->
        prerr_endline ("Unknown port: "^Sys.argv.(1));
        exit 3;;

handle_unix_error main ();;