patch #8113
[mldonkey.git] / src / daemon / common / commonGlobals.ml
blob5153daad727661f2c926cebc8dbe21d915f6bbb5
1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
2 (*
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 open Printf2
21 open Options
22 open CommonOptions
23 open BasicSocket
24 open CommonTypes
25 open UdpSocket
26 open TcpBufferedSocket
29 (*************************************************************************)
30 (* *)
31 (* short_lazy *)
32 (* *)
33 (*************************************************************************)
35 (* Store the result of a computation for a very short time to avoid
36 recomputing it too often. Each value is associated with a uniq
37 '(string, int1, int2)' that should be provided by the caller.
40 module ShortLazy : sig
41 val compute : string * int * int -> ('a -> 'b) -> 'a -> 'b
42 end = struct
44 type t
46 let short_lazy_values = Hashtbl.create 111
47 let compute name f x =
48 let f = (Obj.magic f : t -> t) in
49 let x = (Obj.magic x : t) in
50 try
51 let (f',x',v) = Hashtbl.find short_lazy_values name in
53 if f' != f || x <> x' then
54 (Hashtbl.remove short_lazy_values name; raise Not_found);
55 Obj.magic (v : t)
56 with _ ->
57 let v = f x in
58 Hashtbl.add short_lazy_values name (f,x,v);
59 Obj.magic (v : t)
61 let _ =
62 add_infinite_timer 5. (fun _ -> Hashtbl.clear short_lazy_values)
63 end
65 (*************************************************************************)
66 (* *)
67 (* ............ *)
68 (* *)
69 (*************************************************************************)
71 (* ripped from gui_misc *)
73 let ko = 1024.0
74 let mo = ko *. ko
75 let go = mo *. ko
76 let tob = go *. ko
78 let size_of_int64 size =
79 if !!html_mods_human_readable then
80 let f = Int64.to_float size in
81 if f > tob then
82 Printf.sprintf "%.2fT" (f /. tob)
83 else
84 if f > go then
85 Printf.sprintf "%.2fG" (f /. go)
86 else
87 if f > mo then
88 Printf.sprintf "%.1fM" (f /. mo)
89 else
90 if f > ko then
91 Printf.sprintf "%.1fk" (f /. ko)
92 else
93 Int64.to_string size
94 else
95 Int64.to_string size
97 let networks_string = ref ""
99 let patches_string = ref ""
101 let is_startup_phase = ref true
103 let version () =
104 Printf.sprintf "MLNet %s: Multi-Network p2p client (%s)"
105 Autoconf.current_version !networks_string
107 (* Should we try to find another port when we cannot bind to the one set
108 in an option, and then change the option accordingly. ?> *)
109 let find_other_port = ref false
111 let upnp_port_forwarding () = !!upnp_port_forwarding && Autoconf.upnp_natpmp
113 let shorten str limit =
114 (* TODO: we should change all strings to utf8 when
115 they come into the core instead. *)
116 let name = Charset.Locale.to_utf8 (* String.escaped *) str in
117 let slen = String.length str in
118 let len =
120 Charset.utf8_length str
121 with e -> slen
123 let diff_len_utf8_ascii = slen - len in
124 let max_len = max limit 10 in
125 if len > max_len then
126 let prefix = String.sub name 0 (max_len - 7 + diff_len_utf8_ascii) in
127 let suffix = String.sub name (len - 4 + diff_len_utf8_ascii) 4 in
128 Printf.sprintf "%s...%s" prefix suffix
129 else name
131 let client_short_name c =
132 shorten c !!max_client_name_len
134 let find_port server_name bind_addr port_option handler =
135 if !!port_option <> 0 then
136 let rec iter port =
138 let sock = TcpServerSocket.create server_name
139 (Ip.to_inet_addr bind_addr)
140 port handler in
141 port_option =:= port;
142 Some sock
143 with e ->
144 if !find_other_port then iter (port+1)
145 else begin
146 lprintf_nl "Exception %s while starting %s" server_name
147 (Printexc2.to_string e);
148 None
151 iter !!port_option
152 else None
154 let new_connection_control () = {
155 control_last_ok = 0;
156 control_state = 0;
157 control_last_try = 0;
158 control_min_reask = !!min_reask_delay;
161 let new_connection_control_recent_ok () = {
162 control_last_ok = last_time () - (Date.minute_in_secs * 25);
163 control_state = 0;
164 control_last_try = 0;
165 control_min_reask = !!min_reask_delay;
168 let connection_ok cc =
169 cc.control_last_ok <- last_time ();
170 cc.control_state <- 0
172 let connection_try cc =
173 cc.control_last_try <- last_time ()
175 let connection_failed cc =
176 cc.control_state <- cc.control_state + 1
178 let connection_next_try cc =
179 cc.control_last_try + min (cc.control_min_reask * cc.control_state)
180 cc.control_min_reask
182 let connection_can_try cc =
183 connection_next_try cc < last_time ()
185 let connection_was_tried cc =
186 cc.control_last_try > 0
188 let print_control c =
189 lprintf_nl "Connection Control: ok = %d seconds ago, state = %d, last tried = %d seconds ago, delay = %d, next in %d seconds"
190 (last_time () - c.control_last_ok) c.control_state (last_time () - c.control_last_try) c.control_min_reask (connection_next_try c - last_time ())
192 let connection_must_try cc =
193 cc.control_state <- 0
195 let connection_set_last_conn cc lc =
196 cc.control_last_ok <- lc
198 let connection_last_conn cc =
199 cc.control_last_ok
201 let connection_delay cc =
202 cc.control_last_try <- last_time ();
203 cc.control_state <- 0
205 let upload_control = TcpBufferedSocket.create_write_bandwidth_controler
206 "Upload"
207 (!!max_hard_upload_rate * 1024)
209 let download_control = TcpBufferedSocket.create_read_bandwidth_controler
210 "Download"
211 (!!max_hard_download_rate * 1024)
213 let payload_bandwidth = ref 0.
215 let check_ul_dl_ratio () =
216 if !!max_hard_upload_rate < 0 then max_hard_upload_rate =:= 0;
217 if !!max_hard_download_rate < 0 then max_hard_download_rate =:= 0;
218 let max_max_hard_download_rate =
219 match !!max_hard_upload_rate with
220 | 0 -> None
221 | x when x < 4 -> Some (x * 3)
222 | x when x < 10 -> Some (x * 4)
223 | x -> None in
224 match max_max_hard_download_rate with
225 | None -> ()
226 | Some limit ->
227 if !!max_hard_download_rate = 0 ||
228 !!max_hard_download_rate > limit then
229 max_hard_download_rate =:= limit
231 let _ =
232 option_hook max_hard_upload_rate (fun _ ->
233 check_ul_dl_ratio ();
234 TcpBufferedSocket.change_rate upload_control
235 (!!max_hard_upload_rate * 1024);
236 payload_bandwidth :=
237 float_of_int (if !!max_hard_upload_rate = 0 then
238 10000 * 1024
239 else
240 max (!!max_hard_upload_rate * 1024) 1024) *. 0.90;
242 option_hook max_hard_download_rate (fun _ ->
243 check_ul_dl_ratio ();
244 TcpBufferedSocket.change_rate download_control
245 (!!max_hard_download_rate * 1024))
247 let udp_write_controler = UdpSocket.new_bandwidth_controler upload_control
249 let udp_read_controler = UdpSocket.new_bandwidth_controler download_control
251 let pid = Unix.getpid ()
253 let do_at_exit f =
254 Pervasives.at_exit (fun _ ->
255 if Unix.getpid () = pid then
256 try f () with e -> ())
258 let exit_properly n = Pervasives.exit n
260 let user_socks = ref ([] : TcpBufferedSocket.t list)
261 let dialog_history = ref ([] : (int * string * string) list )
263 exception Incoming_full
265 let want_and_not andnot f none value =
266 (* lprintf "want_and_not [%s]\n" value; *)
267 let ws = String2.split_simplify value ' ' in
268 if ws = [] then raise Not_found;
269 let wanted = ref "" in
270 let not_wanted = ref "" in
271 List.iter (fun w ->
272 let len = String.length w in
273 if len>1 && w.[0] = '-' then
274 let w = String.sub w 1 (len-1) in
275 if !not_wanted = "" then not_wanted := w
276 else not_wanted := !not_wanted ^ " " ^ w
277 else
278 if !wanted = "" then wanted := w
279 else wanted := !wanted ^ " " ^ w
280 ) ws;
281 let wanted = if !wanted <> "" then f !wanted else none in
282 if !not_wanted = "" then wanted else
283 andnot wanted (f !not_wanted)
285 let want_comb_not andnot comb f none value =
286 (* lprintf "want_comb_not [%s]\n" value; *)
287 let ws = String2.split_simplify value ' ' in
288 let wanted = ref [] in
289 let not_wanted = ref [] in
290 List.iter (fun w ->
291 let len = String.length w in
292 if len>1 && w.[0] = '-' then
293 let w = String.sub w 1 (len-1) in
294 not_wanted := w :: !not_wanted
295 else wanted := w :: !wanted
296 ) ws;
297 let wanted = match !wanted with
298 [] -> none
299 | w :: tail ->
300 List.fold_left (fun q w ->
301 comb q (f w)
302 ) (f w) tail
304 match !not_wanted with
305 [] -> wanted
306 | w :: tail ->
307 andnot wanted
308 (List.fold_left (fun q w ->
309 comb q (f w)
310 ) (f w) tail)
313 let string_of_tags tags =
314 let buf = Buffer.create 100 in
315 List.iter (fun t ->
316 Buffer.add_string buf (Printf.sprintf "%-3s "
317 (match t.tag_value with
318 String s -> s
319 | Uint64 i -> Int64.to_string i
320 | Fint64 i -> Int64.to_string i
321 | _ -> "???"
323 ) tags;
324 Buffer.contents buf
326 let rec find_tag name tags =
327 match tags with
328 [] -> raise Not_found
329 | { tag_name = tag_name; tag_value = v } :: _ when tag_name = name -> v
330 | _ :: tail -> find_tag name tail
335 (* first GUI have gui_num = 2, since newly created objects have _update = 1 *)
336 let gui_counter = ref 2
338 let upload_counter = ref Int64.zero
339 let download_counter = ref Int64.zero
340 let nshared_files = ref 0
341 let nshared_bytes = ref Int64.zero
342 let shared_counter = ref Int64.zero
343 let has_upload = ref 0
344 let upload_credit = ref 0
346 let string_of_field t =
347 match t with
348 | Field_Artist -> "artist"
349 | Field_Title -> "title"
350 | Field_Album -> "album"
351 | Field_Format -> "format"
352 | Field_Type -> "type"
353 | Field_Length -> "length"
354 | Field_Availability -> "availability"
355 | Field_Completesources -> "completesources"
356 | Field_Filename -> "filename"
357 | Field_Size -> "size"
358 | Field_Size_Hi -> "size_hi"
359 | Field_Uid -> "uid"
360 | Field_Bitrate -> "bitrate"
361 | Field_Codec -> "codec"
362 | Field_Filerating -> "rating"
363 | Field_Lastseencomplete -> "lastcompl"
364 | Field_Medialength -> "mlen"
365 | Field_Mediacodec -> "mediacodec"
366 | Field_KNOWN s -> s
367 | Field_UNKNOWN s -> s
369 let field_of_string t =
370 match String.lowercase t with
371 | "artist" -> Field_Artist
372 | "title" -> Field_Title
373 | "album" -> Field_Album
374 | "format" -> Field_Format
375 | "type" -> Field_Type
376 | "length" -> Field_Length
377 | "availability" -> Field_Availability
378 | "completesources" -> Field_Completesources
379 | "filename" -> Field_Filename
380 | "size" -> Field_Size
381 | "size_hi" -> Field_Size_Hi
382 | "uid" -> Field_Uid
383 | "bitrate" -> Field_Bitrate
384 | "codec" -> Field_Codec
385 | "rating" -> Field_Filerating
386 | "lastcompl" -> Field_Lastseencomplete
387 | "mlen" -> Field_Medialength
388 | "mediacodec" -> Field_Mediacodec
389 | _ -> Field_KNOWN t
391 let escaped_string_of_field tag =
392 match tag.tag_name with
393 | Field_KNOWN s -> String.escaped s
394 | Field_UNKNOWN s -> String.escaped s
395 | t -> string_of_field t
398 let string_of_tag tag =
399 Printf.sprintf " \"%s\" = %s" (escaped_string_of_field tag)
400 (string_of_tag_value tag.tag_value)
402 let hexstring_of_tag tag =
403 Printf.sprintf " \"%s\" = %s" (String2.hex_string_of_string (escaped_string_of_field tag))
404 (string_of_tag_value tag.tag_value)
406 let rec print_tags tags =
407 match tags with
408 [] -> ()
409 | tag :: tags ->
410 lprintf " \"%s\" = %s" (escaped_string_of_field tag)
411 (string_of_tag_value tag.tag_value);
412 print_tags tags
414 let rec fprint_tags oc tags =
415 match tags with
416 [] -> Printf.fprintf oc "\n"
417 | tag :: tags ->
418 Printf.fprintf oc "%s = %s" (escaped_string_of_field tag)
419 (string_of_tag_value tag.tag_value);
420 fprint_tags oc tags
422 let rec bprint_tags buf tags =
423 match tags with
424 [] -> Printf.bprintf buf "\n"
425 | tag :: tags ->
426 Printf.bprintf buf "%s = %s" (escaped_string_of_field tag)
427 (string_of_tag_value tag.tag_value);
428 bprint_tags buf tags
430 (* let searches = ref ([] : search list) *)
432 let core_included = ref false
433 let gui_included = ref false
435 let gui_reconnected = ref false
437 let core_gui_fifo = (Fifo.create () : GuiProto.to_gui Fifo.t)
438 let gui_core_fifo = (Fifo.create () : GuiProto.from_gui Fifo.t)
440 let init_hooks = ref ([] : (unit -> unit) list)
442 let add_init_hook f =
443 init_hooks := f :: !init_hooks
445 let chat_message_fifo = (Fifo.create () : (int * string * int * string * string) Fifo.t)
447 let log_chat_message i num n s =
448 Fifo.put chat_message_fifo (last_time(),i,num,n,s);
449 (try
450 Unix2.tryopen_write_gen messages_log [Open_creat; Open_wronly; Open_append]
451 0o600 (fun oc ->
452 Printf.fprintf oc "%s: %s (%s): %s\n" (Date.simple (BasicSocket.date_of_int (last_time ()))) n i s)
453 with e ->
454 lprintf_nl "[ERROR] Exception %s while trying to log message to %s"
455 (Printexc2.to_string e) messages_log);
457 while (Fifo.length chat_message_fifo) > !!html_mods_max_messages do
458 ignore(Fifo.take chat_message_fifo)
459 done
461 let last_message_log = ref 0
463 let debug_clients = ref Intset.empty
465 (* control_: means that it is the limited bandwidth, not the unlimited one
466 used by the interfaces. tcp_: the full bandwidth (limited+unlimited) *)
468 let udp_upload_rate = ref 0
469 (* let tcp_upload_rate = ref 0 *)
470 let control_upload_rate = ref 0
471 let udp_download_rate = ref 0
472 (* let tcp_download_rate = ref 0 *)
473 let control_download_rate = ref 0
475 let sd_udp_upload_rate = ref 0
476 let sd_tcp_upload_rate = ref 0
477 let sd_control_upload_rate = ref 0
479 let bandwidth_samples = Fifo.create ()
480 let short_delay_bandwidth_samples = Fifo.create ()
482 let nmeasures = 6
483 let dummy_sample = Array.make nmeasures 0.
485 let trimto n samples =
486 let len = ref (Fifo.length samples) in
487 while !len > n do
488 ignore (Fifo.take samples);
489 decr len
490 done
492 let last samples =
494 Fifo.head samples
495 with _ ->
496 (last_time (), dummy_sample)
498 let derive (t1, sample1) (t2, sample2) =
499 let dt = t2 - t1 in
500 if dt <> 0 then
501 let fdt = float_of_int dt in
502 (dt, Array.init nmeasures
503 (fun i -> int_of_float ((sample2.(i) -. sample1.(i)) /. fdt)))
504 else
505 (0, Array.make nmeasures 0)
507 let update_link_stats () =
509 let put time sample samples =
510 assert (Array.length sample = nmeasures);
511 Fifo.put samples (time, sample) in
513 let last_count_time, last_sample =
514 last bandwidth_samples in
515 let time = last_time () in
516 let sample = [|
517 Int64.to_float !tcp_uploaded_bytes;
518 Int64.to_float !tcp_downloaded_bytes;
519 Int64.to_float (moved_bytes upload_control);
520 Int64.to_float (moved_bytes download_control);
521 Int64.to_float !udp_uploaded_bytes;
522 Int64.to_float !udp_downloaded_bytes;|] in
524 (match derive (last_count_time, last_sample) (time, sample) with
525 _, [|tur; tdr; cur; cdr; uur; udr|] ->
528 tcp_upload_rate := tur;
529 tcp_download_rate := tdr;
531 control_upload_rate := cur;
532 control_download_rate := cdr;
533 udp_upload_rate := uur;
534 udp_download_rate := udr
535 | _ -> failwith "wrong number of measures");
538 lprintf "BANDWIDTH %d/%d %d/%d\n" !control_upload_rate !tcp_upload_rate
539 !control_download_rate !tcp_download_rate ;
541 put time sample bandwidth_samples;
542 trimto 20 bandwidth_samples;
544 let sd_last_count_time, sd_last_sample =
545 last short_delay_bandwidth_samples in
546 (match derive (sd_last_count_time, sd_last_sample) (time, sample) with
547 _, [|tur; _; cur; _; uur; _|] ->
548 sd_tcp_upload_rate := tur;
549 sd_control_upload_rate := cur;
550 sd_udp_upload_rate := uur
551 | _ -> failwith "wrong number of measures");
553 put time sample short_delay_bandwidth_samples;
554 trimto 5 short_delay_bandwidth_samples
556 let history_step = 5
557 let history_size = 720
558 let history_size_for_h_graph = ref 0 (* history_size * !!html_mods_vd_gfx_h_intervall / 60 *)
559 let history_h_step = ref 0 (* 60 * !!html_mods_vd_gfx_h_intervall <= history_size * history_step *)
560 let history_h_size = 1440
561 let history_timeflag = ref 0.
562 let history_h_timeflag = ref 0.
564 let upload_history = Fifo.create ()
565 let download_history = Fifo.create ()
566 let upload_h_history = Fifo.create ()
567 let download_h_history = Fifo.create ()
569 let upload_usage () =
570 !udp_upload_rate + !control_upload_rate
572 let short_delay_upload_usage () =
573 !sd_udp_upload_rate + !sd_control_upload_rate
575 let download_usage () =
576 !udp_download_rate + !control_download_rate
578 let update_download_history () =
579 Fifo.put download_history (download_usage ());
580 let len = ref (Fifo.length download_history) in
581 while !len > history_size+1 do
582 ignore (Fifo.take download_history);
583 decr len
584 done
586 let update_upload_history () =
587 Fifo.put upload_history (upload_usage ());
588 let len = ref (Fifo.length upload_history) in
589 while !len > history_size+1 do
590 ignore (Fifo.take upload_history);
591 decr len
592 done
594 let update_h_download_history () =
595 if (!history_h_step = history_size * history_step) or ( (Fifo.length download_history) <= (!history_size_for_h_graph+1)) then
596 Fifo.put download_h_history ((List.fold_left (+) 0 (Fifo.to_list download_history)) / ((Fifo.length download_history)))
597 else
598 Fifo.put download_h_history ((List.fold_left (+) 0
599 (snd (List2.cut ((Fifo.length download_history) - !history_size_for_h_graph - 1) (Fifo.to_list download_history))))
600 / (!history_size_for_h_graph + 1) );
601 let len = ref (Fifo.length download_h_history) in
602 while !len > history_h_size+1 do
603 ignore (Fifo.take download_h_history);
604 decr len
605 done
607 let update_h_upload_history () =
608 (* Fifo.put upload_h_history ((Fifo.length upload_history) / 720); *)
609 if (!history_h_step = history_size * history_step) or ((Fifo.length upload_history) <= (!history_size_for_h_graph+1)) then
610 Fifo.put upload_h_history ((List.fold_left (+) 0 (Fifo.to_list upload_history)) / ((Fifo.length upload_history)))
611 else
612 Fifo.put upload_h_history ((List.fold_left (+) 0
613 (snd (List2.cut ((Fifo.length upload_history) - !history_size_for_h_graph - 1) (Fifo.to_list upload_history))))
614 / (!history_size_for_h_graph+1) );
615 let len = ref (Fifo.length upload_h_history) in
616 while !len > history_h_size+1 do
617 ignore (Fifo.take upload_h_history);
618 decr len
619 done
621 let detected_link_capacity link =
622 List.fold_left max 0 (Fifo.to_list link)
624 let detected_uplink_capacity () =
625 List.fold_left max 0 (Fifo.to_list upload_history)
627 let detected_downlink_capacity () =
628 List.fold_left max 0 (Fifo.to_list download_history)
631 let new_tag name v =
632 { tag_name = name; tag_value = v }
634 let int_tag s i =
635 { tag_name = s; tag_value = Uint64 (Int64.of_int i) }
637 let int64_tag s i =
638 { tag_name = s; tag_value = Uint64 i }
640 let string_tag s i =
641 { tag_name = s; tag_value = String i }
643 let for_int_tag tag f =
644 match tag.tag_value with
645 Uint64 i | Fint64 i -> f (Int64.to_int i)
646 | String _ -> ()
647 | Addr _ -> ()
648 | Pair _ -> ()
649 | Uint16 n | Uint8 n -> f n
651 let for_int64_tag tag f =
652 match tag.tag_value with
653 Uint64 i | Fint64 i -> f i
654 | String _ -> ()
655 | Addr _ -> ()
656 | Pair _ -> ()
657 | Uint8 n | Uint16 n -> f (Int64.of_int n)
659 let for_two_int16_tag tag f =
660 match tag.tag_value with
661 Uint64 i | Fint64 i ->
662 let i1 = Int64.to_int (Int64ops.right64 i 16) in
663 let i0 = Int64.to_int i in
664 let i0 = i0 land 0xffff in
665 let i1 = i1 land 0xffff in
666 f i0 i1
667 | String _ -> ()
668 | Addr _ -> ()
669 | Pair _ -> ()
670 | Uint8 n | Uint16 n -> f n 0
672 let for_string_tag tag f =
673 match tag.tag_value with
674 Uint64 _ | Fint64 _ -> ()
675 | String s -> f s
676 | Addr _ -> ()
677 | Pair _ -> ()
678 | Uint16 _ | Uint8 _ -> ()
680 let partial_chunk c =
681 match c with
682 | VerificationBitmap.State_missing | VerificationBitmap.State_partial ->
683 true
684 | VerificationBitmap.State_complete | VerificationBitmap.State_verified ->
685 false
688 module CanBeCompressed = struct
690 let to_deflate = ref []
691 let to_deflate_len = ref 0
693 let compression_buffer_len = 20000
694 let compression_buffer = String.create compression_buffer_len
696 let deflate_connection sock =
697 lprintf "Creating deflate connection\n";
698 let comp = Deflate (Zlib.inflate_init true, Zlib.deflate_init 6 true) in
699 CompressedConnection (comp,
700 buf_create !max_buffer_size, buf_create !max_buffer_size, sock)
702 let rec iter_deflate sock zs wbuf =
703 if wbuf.len > 0 then begin
704 lprintf "iter_deflate\n";
705 let (_, used_in, used_out) = Zlib.deflate zs
706 wbuf.buf wbuf.pos wbuf.len
707 compression_buffer 0 compression_buffer_len
708 Zlib.Z_SYNC_FLUSH in
709 lprintf "deflated %d/%d -> %d\n" used_in wbuf.len used_out;
710 lprintf "[%s]\n" (String.escaped (String.sub compression_buffer 0 used_out));
711 write sock compression_buffer 0 used_out;
712 buf_used wbuf used_in;
713 if used_in > 0 || used_out > 0 then
714 iter_deflate sock zs wbuf
717 let deflate_timer _ =
718 List.iter (fun conn ->
720 match conn with
721 CompressedConnection (comp, _, wbuf, sock) ->
722 if closed sock then raise Exit;
723 let Deflate (_, zs) = comp in
724 iter_deflate sock zs wbuf
725 | _ -> ()
726 with e ->
727 lprintf "[ERROR] Exception %s in CanBeCompressed.deflate_timer\n"
728 (Printexc2.to_string e)
729 ) !to_deflate;
730 to_deflate := [];
731 to_deflate_len := 0
733 let to_deflate conn =
734 if not (List.memq conn !to_deflate) then
735 to_deflate := conn :: !to_deflate;
736 if !to_deflate_len > 1000000 then
737 deflate_timer ()
739 let write_string conn s =
740 lprintf "write_string\n";
741 let len = String.length s in
742 match conn with
743 Connection sock -> write_string sock s
744 | CompressedConnection (_,_,wbuf,sock) ->
745 lprintf "CanBeCompressed.write_string %d\n" len;
746 to_deflate_len := !to_deflate_len + len;
747 to_deflate conn;
748 buf_add sock wbuf s 0 len
749 | _ -> assert false
751 let rec iter_inflate zs sock b rbuf =
752 if b.len > 0 then begin
753 lprintf "iter_inflate %d\n" b.len;
754 lprintf "[%s]\n" (String.escaped (String.sub b.buf b.pos b.len));
755 let (_, used_in, used_out) = Zlib.inflate zs b.buf b.pos b.len
756 compression_buffer 0 compression_buffer_len
757 Zlib.Z_SYNC_FLUSH in
758 lprintf "inflated %d/%d -> %d\n" used_in b.len used_out;
759 lprintf "[%s]\n" (String.escaped (String.sub compression_buffer 0 used_out));
760 buf_add sock rbuf compression_buffer 0 used_out;
761 buf_used b used_in;
762 if used_in > 0 || used_out > 0 then
763 iter_inflate zs sock b rbuf
766 let buf conn =
767 lprintf "CanBeCompressed.buf\n";
769 match conn with
770 Connection sock -> buf sock
771 | CompressedConnection (comp,rbuf,_,sock) ->
773 let b = buf sock in
774 let Deflate (zs, _) = comp in
775 if b.len > 0 then iter_inflate zs sock b rbuf;
776 rbuf
777 | _ -> assert false
778 with e ->
779 lprintf "[ERROR] Exception %s in CanBeCompressed.buf\n"
780 (Printexc2.to_string e);
781 raise e
785 let do_if_connected tcp_connection f =
786 match tcp_connection with
787 Connection sock -> f sock
788 | _ -> ()
790 let new_activity () = {
791 activity_begin = BasicSocket.last_time ();
792 activity_client_overnet_connections = 0;
793 activity_client_overnet_indirect_connections = 0;
794 activity_client_overnet_successful_connections = 0;
795 activity_client_edonkey_connections = 0;
796 activity_client_edonkey_indirect_connections = 0;
797 activity_client_edonkey_successful_connections = 0;
798 activity_server_edonkey_connections = 0;
799 activity_server_edonkey_successful_connections = 0;
802 let nactivities = ref 0
803 let activities = Fifo.create ()
804 let activity = ref (new_activity ())
806 let _ =
807 add_infinite_timer 60. (fun _ ->
808 Fifo.put activities !activity;
809 incr nactivities;
810 if !nactivities > 2000 then begin
811 ignore (Fifo.take activities);
812 decr nactivities
813 end;
814 activity := new_activity ()
817 module StringIntern = Weak.Make(struct
818 type t = string
819 let hash s = Hashtbl.hash s
820 let equal x y = x = y
821 end)
823 let intern_table = StringIntern.create 1000
824 let intern s = StringIntern.merge intern_table s
826 let print_command_result o result =
827 if use_html_mods o then
828 html_mods_table_one_row o.conn_buf "serversTable" "servers" [
829 ("", "srh", result); ]
830 else
831 Printf.bprintf o.conn_buf "%s" result
833 let discover_ip force =
834 if !!discover_ip || force then
835 begin
836 if !verbose then lprintf_nl "started IP discovery";
837 let module H = Http_client in
838 let r = { H.basic_request with
839 H.req_url = Url.of_string "http://dynupdate.no-ip.com/ip.php";
840 H.req_proxy = !CommonOptions.http_proxy;
841 H.req_max_retry = 10;
842 H.req_user_agent = get_user_agent () }
844 H.wget r (fun file ->
845 if !verbose then lprintf_nl "downloaded IP discovery page, parsing...";
846 Unix2.tryopen_read file (fun cin ->
848 while true do
849 let line = input_line cin in
851 let ip = Ip.of_string line in
852 begin
853 set_client_ip =:= ip;
854 last_high_id := !!set_client_ip;
855 if !verbose then lprintf_nl "discovered IP %s" (Ip.to_string !!set_client_ip)
857 with e -> lprintf_nl "IP discovery parse error: %s" (Printexc2.to_string e)
858 done
859 with End_of_file -> ())
863 let _ =
864 Heap.add_memstat "CommonGlobals" (fun level buf ->
865 let counter = ref 0 in
866 StringIntern.iter (fun f -> incr counter;) intern_table;
867 Printf.bprintf buf " intern_table: %d\n" !counter;
868 Printf.bprintf buf " core_gui_fifo: %d\n" (Fifo.length core_gui_fifo);
869 Printf.bprintf buf " gui_core_fifo: %d\n" (Fifo.length gui_core_fifo);
870 Printf.bprintf buf " chat_message_fifo: %d\n" (Fifo.length chat_message_fifo);
871 Printf.bprintf buf " upload_history: %d\n" (Fifo.length upload_history);
872 Printf.bprintf buf " download_history: %d\n" (Fifo.length download_history);
873 Printf.bprintf buf " upload_h_history: %d\n" (Fifo.length upload_h_history);
874 Printf.bprintf buf " download_h_history: %d\n" (Fifo.length download_h_history);
875 Printf.bprintf buf " bandwidth_samples: %d\n" (Fifo.length bandwidth_samples);
876 Printf.bprintf buf " short_delay_bandwidth_samples: %d\n" (Fifo.length short_delay_bandwidth_samples);
877 Printf.bprintf buf " dummy_sample: %d\n" (Array.length dummy_sample);
878 Printf.bprintf buf " activities: %d\n" (Fifo.length activities);