(* Compilieren mit: ocamlc unix.cma echoserver.ml oder ocamlopt unix.cmxa echoserver.ml *) open Unix open Printf let err_mlecho_syntax = "ERROR bad syntax for MLECHO\n" let err_unknown_cmd = "ERROR unknown command\n" (* Diese Exception werden nur ausgelöst, wenn weniger geschrieben wurde, als beabsichtigt. *) exception WriteFailure let readline sd = let c = " " in let rec loop res = if (read sd c 0 1) = 1 then if c = "\n" then res^c else loop (res^c) else raise End_of_file in loop "" let write_safe sd s = let len = String.length s in if (write sd s 0 len) < len then raise WriteFailure let strncmp s1 s2 n = let s1' = String.sub s1 0 (min n (String.length s1)) and s2' = String.sub s2 0 (min n (String.length s2)) in s1' = s2' let isdigit c = let i = int_of_char c in (48 <= i) && (i <= 57) let atoi c = (int_of_char c) - 48 let get_ip sock_addr = match sock_addr with ADDR_INET (inet_addr, port) -> string_of_inet_addr inet_addr | _ -> failwith "get_ip" let main () = let sd = socket PF_INET SOCK_STREAM 0 in bind sd (ADDR_INET(inet_addr_any, 9000)); listen sd 5; let rec server_loop () = let (csd, client_addr) = accept sd in let rec client_loop () = let cmd = readline csd in if strncmp "ECHO " cmd 5 then begin write_safe csd ("REPLY "^(String.sub cmd 5 ((String.length cmd)-5))); client_loop () end else if strncmp "INFO" cmd 4 then begin write_safe csd ("YOURIP "^(get_ip client_addr)^"\n"); client_loop () end else if strncmp "MLECHO " cmd 7 then begin if ((String.length cmd) = 10) && isdigit(cmd.[7]) then begin let nlines = atoi cmd.[7] in let rec loop n = if n = 0 then [] else (readline csd)::(loop (n - 1)) in let lines = loop nlines in write_safe csd (sprintf "MLREPLY %d\n" nlines); List.iter (write_safe csd) lines end else write_safe csd err_mlecho_syntax; client_loop () end else if strncmp "QUIT" cmd 4 then begin close csd; server_loop () end else begin write_safe csd err_unknown_cmd; client_loop () end in client_loop () in handle_unix_error server_loop ()