(* $Id: nethttp_client_conncache.ml 2195 2015-01-01 12:23:39Z gerd $ *)
type transport_layer_id = int
type inactive_data =
{ conn_trans : transport_layer_id;
tls_stashed_endpoint : exn option;
}
type conn_state = [ `Inactive of inactive_data | `Active of < > ]
type peer =
[ `Direct of string * int
| `Direct_name of string * int
| `Http_proxy of string * int
| `Http_proxy_connect of (string * int) * (string * int)
| `Socks5 of (string * int) * (string * int)
]
class type connection_cache =
object
method get_connection_state : Unix.file_descr -> conn_state
method set_connection_state : Unix.file_descr -> peer -> conn_state -> unit
method find_inactive_connection : peer -> transport_layer_id -> Unix.file_descr * inactive_data
method find_my_connections : < > -> Unix.file_descr list
method close_connection : Unix.file_descr -> unit
method close_all : unit -> unit
end
class restrictive_cache() : connection_cache =
object(self)
val mutable active_conns = Hashtbl.create 10
val mutable rev_active_conns = Hashtbl.create 10
method get_connection_state fd =
`Active(Hashtbl.find active_conns fd)
method set_connection_state fd peer state =
match state with
| `Active owner ->
Hashtbl.replace active_conns fd owner;
let fd_list =
try Hashtbl.find rev_active_conns owner with Not_found -> [] in
if not (List.mem fd fd_list) then
Hashtbl.replace rev_active_conns owner (fd :: fd_list);
| `Inactive _ ->
self # remove_connection fd;
raise Not_found
method find_inactive_connection _ _ = raise Not_found
method find_my_connections owner =
try
Hashtbl.find rev_active_conns owner
with
Not_found -> []
method private remove_connection fd =
( try
let owner = Hashtbl.find active_conns fd in
let fd_list =
try Hashtbl.find rev_active_conns owner with Not_found -> [] in
let fd_list' =
List.filter (fun fd' -> fd' <> fd) fd_list in
Hashtbl.replace rev_active_conns owner fd_list'
with
Not_found -> ()
);
Hashtbl.remove active_conns fd;
method close_connection fd =
self # remove_connection fd;
Netlog.Debug.release_fd fd;
Unix.close fd
method close_all () =
Hashtbl.iter
(fun fd _ ->
Netlog.Debug.release_fd fd;
Unix.close fd)
active_conns;
Hashtbl.clear active_conns;
Hashtbl.clear rev_active_conns
end
class aggressive_cache () : connection_cache =
object(self)
val mutable active_conns = Hashtbl.create 10
(* maps file_descr to owner *)
val mutable rev_active_conns = Hashtbl.create 10
(* maps owner to file_descr list *)
val mutable inactive_conns = Hashtbl.create 10
(* maps file_descr to (inactive_data,sockaddr) *)
val mutable rev_inactive_conns = Hashtbl.create 10
(* maps (trans,sockaddr) to (file_descr * inactive_data) list *)
method get_connection_state fd =
try
`Active(Hashtbl.find active_conns fd)
with
Not_found ->
let (idata,_) = Hashtbl.find inactive_conns fd in
`Inactive idata
method set_connection_state fd peer state =
match state with
| `Active owner ->
self # forget_inactive_connection fd;
Hashtbl.replace active_conns fd owner;
let fd_list =
try Hashtbl.find rev_active_conns owner with Not_found -> [] in
if not (List.mem fd fd_list) then
Hashtbl.replace rev_active_conns owner (fd :: fd_list);
| `Inactive idata ->
let trans = idata.conn_trans in
( try
self # forget_active_connection fd;
Hashtbl.replace inactive_conns fd (idata,peer);
let fd_list =
try Hashtbl.find rev_inactive_conns (trans,peer)
with Not_found -> [] in
if not (List.mem_assoc fd fd_list) then
Hashtbl.replace
rev_inactive_conns (trans,peer) ((fd,idata) :: fd_list)
with
| Unix.Unix_error(Unix.ENOTCONN,_,_) ->
self # close_connection fd
)
method find_inactive_connection peer trans =
match Hashtbl.find rev_inactive_conns (trans,peer) with
| [] -> raise Not_found
| (fd,idata) :: _ -> (fd,idata)
method find_my_connections owner =
try
Hashtbl.find rev_active_conns owner
with
Not_found -> []
method private forget_active_connection fd =
( try
let owner = Hashtbl.find active_conns fd in
let fd_list =
try Hashtbl.find rev_active_conns owner with Not_found -> [] in
let fd_list' =
List.filter (fun fd' -> fd' <> fd) fd_list in
if fd_list' <> [] then
Hashtbl.replace rev_active_conns owner fd_list'
else
Hashtbl.remove rev_active_conns owner
with
Not_found -> ()
);
Hashtbl.remove active_conns fd;
method private forget_inactive_connection fd =
try
let idata, peer = Hashtbl.find inactive_conns fd in
(* Do not use getpeername! fd might be disconnected in the meantime! *)
let trans = idata.conn_trans in
let fd_list =
try Hashtbl.find rev_inactive_conns (trans,peer) with Not_found -> [] in
let fd_list' =
List.filter (fun (fd',_) -> fd' <> fd) fd_list in
if fd_list' <> [] then
Hashtbl.replace rev_inactive_conns (trans,peer) fd_list'
else
Hashtbl.remove rev_inactive_conns (trans,peer);
Hashtbl.remove inactive_conns fd;
with
| Not_found ->
()
method close_connection fd =
self # forget_active_connection fd;
self # forget_inactive_connection fd;
Netlog.Debug.release_fd fd;
Unix.close fd
method close_all () =
Hashtbl.iter
(fun fd _ ->
Netlog.Debug.release_fd fd;
Unix.close fd)
active_conns;
Hashtbl.clear active_conns;
Hashtbl.clear rev_active_conns;
Hashtbl.iter
(fun fd _ ->
Netlog.Debug.release_fd fd;
Unix.close fd)
inactive_conns;
Hashtbl.clear inactive_conns;
Hashtbl.clear rev_inactive_conns
end