123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990(*
* 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),stateendendtypet={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(Mirage_mtime.elapsed_ns())t.startinmatchnext~configuration:t.configuration~nst.statewith|`Waitns,state->Mirage_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=Mirage_mtime.elapsed_ns()inlett={configuration;callback;state;timer;start}int.timer<-restartt;tletrefresht=t.start<-Mirage_mtime.elapsed_ns();t.state<-alive;Lwt.cancelt.timer;t.timer<-restartt