/** connection is closing but a write has to be finished first */ private Receive ClosingWithPendingWrite(ConnectionInfo info, IActorRef closeCommandor, Tcp.ConnectionClosed closedEvent) { return(message => { if (message is Tcp.SuspendReading) { SuspendReading(info); return true; } if (message is Tcp.ResumeReading) { ResumeReading(info); return true; } if (message is SelectionHandler.ChannelReadable) { DoRead(info, closeCommandor); return true; } if (message is SelectionHandler.ChannelWritable) { DoWrite(info); if (!WritePending()) // writing is now finished { HandleClose(info, closeCommandor, closedEvent); } return true; } var updatePendingWrite = message as UpdatePendingWriteAndThen; if (updatePendingWrite != null) { _pendingWrite = updatePendingWrite.RemainingWrite; updatePendingWrite.Work(); if (WritePending()) { info.Registration.EnableInterest(SocketAsyncOperation.Send); } else { HandleClose(info, closeCommandor, closedEvent); } return true; } var writeFailed = message as WriteFileFailed; if (writeFailed != null) { HandleError(info.Handler, writeFailed.E); // rethrow exception from dispatcher task return true; } if (message is Tcp.Abort) { HandleClose(info, Sender, IO.Tcp.Aborted.Instance); return true; } return false; }); }
private void HandleClose(ConnectionInfo info, IActorRef closeCommander, Tcp.ConnectionClosed closedEvent) { if (closedEvent is Tcp.Aborted) { if (_tcp.Settings.TraceLogging) { _log.Debug("Got Abort command. RESETing connection."); } DoCloseConnection(info.Handler, closeCommander, closedEvent); return; } if (closedEvent is Tcp.PeerClosed && info.KeepOpenOnPeerClosed) { // report that peer closed the connection info.Handler.Tell(IO.Tcp.PeerClosed.Instance); // used to check if peer already closed its side later _peerClosed = true; Context.Become(PeerSentEOF(info)); return; } if (WritePending()) // finish writing first { if (_tcp.Settings.TraceLogging) { _log.Debug("Got Close command but write is still pending."); } Context.Become(ClosingWithPendingWrite(info, closeCommander, closedEvent)); return; } if (closedEvent is Tcp.ConfirmedClosed) // shutdown output and wait for confirmation { if (_tcp.Settings.TraceLogging) { _log.Debug("Got ConfirmedClose command, sending FIN."); } // If peer closed first, the socket is now fully closed. // Also, if shutdownOutput threw an exception we expect this to be an indication // that the peer closed first or concurrently with this code running. if (_peerClosed || !SafeShutdownOutput()) { DoCloseConnection(info.Handler, closeCommander, closedEvent); } else { Context.Become(Closing(info, closeCommander)); } return; } // close now if (_tcp.Settings.TraceLogging) { _log.Debug("Got Close command, closing connection."); } DoCloseConnection(info.Handler, closeCommander, closedEvent); }
private void DoCloseConnection(IActorRef handler, IActorRef closeCommander, Tcp.ConnectionClosed closedEvent) { if (closedEvent is Tcp.Aborted) { Abort(); } else { _channel.Close(); } StopWith(new CloseInformation(new HashSet <IActorRef>(new[] { handler, closeCommander }.Where(x => x != null)), closedEvent)); }