3 let usage prefix progname =
5 (List.map (fun x -> (Printf.sprintf "%s: %s %s" prefix progname x))
6 [ "send <port> <filename>";
7 "receive <host> <port> <size> <filename>";
9 "chat connect <host> <port>" ])
11 let buff = String.create 1024
15 Unix_error (err, fun_name, arg) ->
17 prerr_string fun_name;
18 prerr_string "\" failed";
19 if String.length arg > 0 then
21 prerr_string " on \""; prerr_string arg; prerr_string "\""; ()
24 prerr_endline (error_message err);
25 flush Pervasives.stderr; ()
27 try Printexc.print raise exc with
30 let accept_connection f s =
31 let (t, addr) = accept s in
34 let write_file filename size t =
36 try openfile filename [ O_RDONLY ] 0 with
37 _ -> Printf.eprintf "Open failed.\n"; flush Pervasives.stderr; exit 1
39 let (len, rlen) = ref 0, ref 0 in
40 while len := read fd buff 0 (String.length buff); !len <> 0
43 let j = i + write t buff i (!len - i) in
44 if j == !len then () else loop j
47 flush (out_channel_of_descr t);
49 Printf.printf "DCC %s %d%% (%d/%d bytes) sent.\n"
50 filename (100 * !rlen / size) !rlen size;
51 flush Pervasives.stdout
55 let send_file port filename =
57 let host = gethostbyname (gethostname ()) in
58 let haddr = string_of_inet_addr host.h_addr_list.(0) in
59 let s = socket PF_INET SOCK_STREAM 0 in
60 setsockopt s SO_REUSEADDR true;
61 bind s (ADDR_INET (inet_addr_any, port));
63 match (getsockname s) with
64 ADDR_INET (addr, port) -> port
69 try openfile filename [ O_RDONLY ] 0 with
70 _ -> Printf.eprintf "Open failed.\n"; flush Pervasives.stderr; exit 1
72 let size = (fstat fd).st_size in
73 let hl = (Hostlong.of_address_string haddr) in
75 Printf.printf "DCC send %s %d %s %d\n"
76 (Filename.basename filename) port (Hostlong.to_string hl) size;
77 flush Pervasives.stdout;
78 accept_connection (fun t -> write_file filename size t) s;
82 let read_file filename size t =
84 try openfile filename [ O_WRONLY; O_CREAT ] 0o600 with
85 _ -> Printf.eprintf "Open failed.\n"; flush Pervasives.stderr; exit 1
87 let (len, rlen) = ref 0, ref 0 in
88 while len := read t buff 0 (String.length buff); !len <> 0
90 let _ = write fd buff 0 !len in
91 flush (out_channel_of_descr fd);
93 Printf.printf "DCC %s %d%% (%d/%d bytes) received.\n"
94 filename (100 * !rlen / size) !rlen size;
95 flush Pervasives.stdout
99 let receive_file host port size filename =
100 let s = socket PF_INET SOCK_STREAM 0 in
101 let hl = Hostlong.of_string host in
103 inet_addr_of_string (Hostlong.to_address_string hl)
105 connect s (ADDR_INET (inet_addr, port));
106 read_file filename size s; ()
109 let sel = ref [s; stdin] in
113 select !sel [] [] (-1.0)
122 else if x == stdin then
129 len := read rfd buff 0 (String.length buff);
131 begin try shutdown wfd SHUTDOWN_SEND; () with
137 let j = i + write wfd buff i (!len - i) in
138 if j == !len then () else loop j
141 flush (out_channel_of_descr wfd)
147 let chat_listen port =
148 let host = gethostbyname (gethostname ()) in
149 let haddr = string_of_inet_addr host.h_addr_list.(0) in
150 let s = socket PF_INET SOCK_STREAM 0 in
151 setsockopt s SO_REUSEADDR true;
152 bind s (ADDR_INET (inet_addr_any, port));
154 match (getsockname s) with
155 ADDR_INET (addr, port) -> port
158 let hl = Hostlong.of_address_string haddr in
160 Printf.printf "DCC chat %s %d\n" (Hostlong.to_string hl) port;
161 flush Pervasives.stdout;
164 Printf.printf "DCC chat established\n";
165 flush Pervasives.stdout;
168 let chat_connect host port =
169 let s = socket PF_INET SOCK_STREAM 0 in
170 let hl = Hostlong.of_string host in
172 inet_addr_of_string (Hostlong.to_address_string hl)
174 connect s (ADDR_INET (inet_addr, port));
175 Printf.printf "DCC chat established\n";
176 flush Pervasives.stdout;
179 let getaddr_ext server =
181 try (gethostbyname server).h_addr_list.(0) with
182 _ -> inet_addr_of_string "198.41.0.4"
184 let s = socket PF_INET SOCK_DGRAM 0 in
185 connect s (ADDR_INET (addr, port));
186 match (getsockname s) with
187 ADDR_INET (addr, port) -> addr
188 | _ -> raise Not_found
192 let usage = usage "Usage" (Filename.basename Sys.argv.(0)) in
194 Arg.parse speclist (fun x -> a := !a @ [x]) usage;
196 "send" :: [ port; filename ] ->
198 try int_of_string port with
199 _ -> Arg.usage speclist usage; exit 1
201 send_file port filename;
203 | "receive" :: [ host; port; size; filename ] ->
209 _ -> Arg.usage speclist usage; exit 1
211 receive_file host port size filename;
213 | "chat" :: [ "listen"; port ] ->
218 _ -> Arg.usage speclist usage; exit 1
222 | "chat" :: [ "connect"; host; port ] ->
227 _ -> Arg.usage speclist usage; exit 1
229 chat_connect host port;
231 | _ -> Arg.usage speclist usage; exit 1
234 let _ = Printexc.catch main ()