anchor.diff:      | UnknownSessionId
       | Unknown
   
  -type InternalEngineIoSocket(id: SocketId) as this =
  +type InternalEngineIoSocket(id: SocketId, pingTimeout: TimeSpan, onClose: InternalEngineIoSocket -> unit) as this =
  +    let logError s = ll.error (eventX (sprintf "[%s] %s" (id.ToString()) s))
       let logDebug s = ll.debug (eventX (sprintf "[%s] %s" (id.ToString()) s))
       let logWarn s = ll.warn (eventX (sprintf "[%s] %s" (id.ToString()) s))
  +
  +    let closeLock = new obj()
  +    let mutable closed = false
  +
  +    let timeoutInMs = int pingTimeout.TotalMilliseconds
  +
  +    let pingTimeoutTimer =
  +        let timer = new System.Timers.Timer()
  +        timer.AutoReset <- false
  +        timer.Interval <- pingTimeout.TotalMilliseconds
  +        timer.Elapsed.Add(fun _ ->
  +            logDebug "Ping timeout, closing socket"
  +            this.Close())
  +        timer
  +
  +    let setPingTimeout () =
  +        pingTimeoutTimer.Stop()
  +        pingTimeoutTimer.Start()
   
       let incomming = MailboxProcessor<IncomingCommunication>.Start(fun inbox ->
           let rec loop (messages: Queue<PacketMessage>) (currentReplyChan: AsyncReplyChannel<PacketMessage> option) = async {
  
positive.code: 
              match msg with
              | NewIncomming msg ->
                  logDebug (sprintf "[NewIncomming] %A" msg)
  
                  match msg with
  
negative.code: let inline private simpleResponse (code: HttpCode) (message: string) =
      bytesResponse code (UTF8.bytes message)
  
  /// Use CompareExchange to apply a mutation to a field.
  /// Mutation must be pure & writes to the field should be rare compared to reads.
  let mutateField<'t when 't: not struct> (targetField: 't byref) (mutation: 't -> 't) =
      let mutable retry = true
      while retry do
          let before = targetField
          let newValue = mutation before
          let afterExchange = System.Threading.Interlocked.CompareExchange(&targetField, newValue, before)
          retry <- not (obj.ReferenceEquals(before, afterExchange))
  
  type EngineIo(config, app: EngineApp) =
      let mutable sessions: Map<SocketId, InternalEngineIoSocket> = Map.empty
      let idGenerator = Base64Id.create config.RandomNumberGenerator
      
      let socketTimeout = config.PingTimeout + config.PingInterval
      
      let socketClosed (socket: InternalEngineIoSocket) =
          ll.info (eventX (sprintf "Removing session with ID %s" (socket.Id.ToString())))
          mutateField &sessions (fun s -> s |> Map.remove socket.Id)
  
      let payloadToResponse sid payload engineCtx =
          if engineCtx.SupportsBinary then
              bytesResponse HttpCode.HTTP_200 (payload |> Payload.encodeToBinary |> Segment.toArray)
  