12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091(*
* Copyright (c) 2017 Docker Inc
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)typeaction=[|`SendProbe|`WaitofDuration.t|`Close]typestate={probes_sent:int}letalive={probes_sent=0;}letnext~configuration~nsstate=letopenTcpip.Tcp.Keepaliveinletafter_ns=configuration.afterin(* Wait until [time] has gone past *)ifafter_ns>nsthen`Wait(Int64.subafter_nsns),aliveelsebeginletsending_probes_for_ns=Int64.subnsafter_nsinletinterval_ns=configuration.intervalinletshould_have_sent=Int64.(to_int(divsending_probes_for_nsinterval_ns))inifshould_have_sent>configuration.probesthen`Close,stateelseifshould_have_sent>state.probes_sentthen`SendProbe,{probes_sent=should_have_sent}(* we don't want to send back-to-back probes *)elsebeginletsince_last_probe_ns=Int64.remsending_probes_for_nsinterval_nsin`Wait(Int64.subinterval_nssince_last_probe_ns),stateendendmoduleMake(T:Mirage_time.S)(Clock:Mirage_clock.MCLOCK)=structtypet={configuration:Tcpip.Tcp.Keepalive.t;callback:([`SendProbe|`Close]->unitLwt.t);mutablestate:state;mutabletimer:unitLwt.t;mutablestart:int64;}(** A keep-alive timer *)letrecrestartt=letopenLwt.Infixinletns=Int64.sub(Clock.elapsed_ns())t.startinmatchnext~configuration:t.configuration~nst.statewith|`Waitns,state->T.sleep_nsns>>=fun()->t.state<-state;restartt|`SendProbe,state->t.callback`SendProbe>>=fun()->t.state<-state;restartt|`Close,_->t.callback`Close>>=fun()->Lwt.return_unitletcreateconfigurationcallback=letstate=aliveinlettimer=Lwt.return_unitinletstart=Clock.elapsed_ns()inlett={configuration;callback;state;timer;start}int.timer<-restartt;tletrefresht=t.start<-Clock.elapsed_ns();t.state<-alive;Lwt.cancelt.timer;t.timer<-restarttend