public ConnectionInfo(ChannelRegistration registration, IActorRef handler, bool keepOpenOnPeerClosed, bool useResumeWriting) { Registration = registration; Handler = handler; KeepOpenOnPeerClosed = keepOpenOnPeerClosed; UseResumeWriting = useResumeWriting; }
private void DoReceive(ChannelRegistration registration, IActorRef handler) { Action <int, ByteBuffer> innerReceive = null; innerReceive = (readsLeft, buffer) => { buffer.Clear(); buffer.Limit(_udp.Setting.DirectBufferSize); var sender = Channel.Receive(buffer); if (sender != null) { buffer.Flip(); handler.Tell(new Udp.Received(ByteString.Create(buffer), sender)); if (readsLeft > 0) { innerReceive(readsLeft - 1, buffer); } } }; var buffr = _udp.BufferPool.Acquire(); try { innerReceive(_udp.Setting.BatchReceiveLimit, buffr); } finally { _udp.BufferPool.Release(buffr); registration.EnableInterest(SocketAsyncOperation.Receive); } }
// AUXILIARIES and IMPLEMENTATION /** used in subclasses to start the common machinery above once a channel is connected */ protected void CompleteConnect(ChannelRegistration registration, IActorRef commander, IEnumerable <Inet.SocketOption> options) { // Turn off Nagle's algorithm by default try { Channel.Socket.NoDelay = true; } catch (SocketException e) { _log.Debug("Could not enable TcpNoDelay: {0}", e.Message); } options.ForEach(x => x.AfterConnect(Channel.Socket)); commander.Tell(new Tcp.Connected( Channel.Socket.RemoteEndPoint, Channel.Socket.LocalEndPoint)); Context.SetReceiveTimeout(_tcp.Settings.RegisterTimeout); // TODO: Not ported. The following need to be investigated before porting //if (WindowsConnectionAbortWorkaroundEnabled) // registration.EnableInterest(SocketAsyncOperation.Connect); Context.Become(WaitingForRegistration(registration, commander)); }
private void DoRead(ChannelRegistration registration, IActorRef handler) { Action <int, ByteBuffer> innerRead = null; innerRead = (readsLeft, buffer) => { buffer.Clear(); buffer.Limit(_udpConn.Settings.DirectBufferSize); if (_channel.Read(buffer) > 0) { buffer.Flip(); handler.Tell(new UdpConnected.Received(ByteString.Create(buffer))); innerRead(readsLeft - 1, buffer); } }; var buffr = _udpConn.BufferPool.Acquire(); try { innerRead(_udpConn.Settings.BatchReceiveLimit, buffr); } finally { registration.EnableInterest(SocketAsyncOperation.Receive); _udpConn.BufferPool.Release(buffr); } }
// STATES /** connection established, waiting for registration from user handler */ private Receive WaitingForRegistration(ChannelRegistration registration, IActorRef commander) { return(message => { var register = message as Tcp.Register; if (register != null) { // up to this point we've been watching the commander, // but since registration is now complete we only need to watch the handler from here on if (register.Handler != commander) { Context.Unwatch(commander); Context.Watch(register.Handler); } if (_tcp.Settings.TraceLogging) { _log.Debug("[{0}] registered as connection handler", register.Handler); } var info = new ConnectionInfo(registration, register.Handler, register.KeepOpenonPeerClosed, register.UseResumeWriting); // if we have resumed reading from pullMode while waiting for Register then register OP_READ interest if (_pullMode && !_readingSuspended) { ResumeReading(info); } DoRead(info, null); // immediately try reading, pullMode is handled by readingSuspended Context.SetReceiveTimeout(null); Context.Become(Connected(info)); return true; } if (message is Tcp.ResumeReading) { _readingSuspended = false; return true; } if (message is Tcp.SuspendReading) { _readingSuspended = true; return false; } var cmd = message as Tcp.CloseCommand; if (cmd != null) { var info = new ConnectionInfo(registration, commander, keepOpenOnPeerClosed: false, useResumeWriting: false); HandleClose(info, Sender, cmd.Event); return true; } if (message is ReceiveTimeout) { // after sending `Register` user should watch this actor to make sure // it didn't die because of the timeout _log.Debug("Configured registration timeout of [{0}] expired, stopping", _tcp.Settings.RegisterTimeout); Context.Stop(Self); return true; } return false; }); }
private Receive Resolving(DnsEndPoint remoteAddress, ChannelRegistration registration) { return(message => { var resolved = message as Dns.Resolved; if (resolved != null) { ReportConnectFailure(() => Register(new IPEndPoint(resolved.Addr, remoteAddress.Port), registration)); return true; } return false; }); }
private Receive Connecting(ChannelRegistration registration, int remainingFinishConnectRetries) { return(message => { if (message is SelectionHandler.ChannelConnectable) { ReportConnectFailure(() => { if (Channel.FinishConnect()) { if (_connect.Timeout.HasValue) { Context.SetReceiveTimeout(null); } Log.Debug("Connection established to [{0}]", _connect.RemoteAddress); CompleteConnect(registration, _commander, _connect.Options); } else { if (remainingFinishConnectRetries > 0) { var self = Self; Context.System.Scheduler.Advanced.ScheduleOnce(1, () => _channelRegistry.Register(Channel, SocketAsyncOperation.Connect, self)); Context.Become(Connecting(registration, remainingFinishConnectRetries - 1)); } else { Log.Debug("Could not establish connection because finishConnect " + "never returned true (consider increasing akka.io.tcp.finish-connect-retries)"); Stop(); } } }); return true; } if (message is ReceiveTimeout) { if (_connect.Timeout.HasValue) { Context.SetReceiveTimeout(null); // Clear the timeout } Log.Debug("Connect timeout expired, could not establish connection to [{0}]", _connect.RemoteAddress); Stop(); return true; } return false; }); }
private void Register(EndPoint address, ChannelRegistration registration) { ReportConnectFailure(() => { Log.Debug("Attempting connection to [{0}]", address); if (Channel.Connect(address)) { CompleteConnect(registration, _commander, _connect.Options); } else { registration.EnableInterest(SocketAsyncOperation.Connect); Become(Connecting(registration, Tcp.Settings.FinishConnectRetries)); } }); }
private void DoSend(ChannelRegistration registration) { var buffer = Udp.BufferPool.Acquire(); try { buffer.Clear(); _pendingSend.Payload.CopyToBuffer(buffer); buffer.Flip(); var writtenBytes = Channel.Send(buffer, _pendingSend.Target); if (Udp.Setting.TraceLogging) { _log.Debug("Wrote [{0}] bytes to channel", writtenBytes); } // Datagram channel either sends the whole message, or nothing if (writtenBytes == 0) { if (_retriedSend) { _pendingCommander.Tell(new Udp.CommandFailed(_pendingSend)); _retriedSend = false; _pendingSend = null; _pendingCommander = null; } else { registration.EnableInterest(SocketAsyncOperation.Send); _retriedSend = true; } } else { if (_pendingSend.WantsAck) { _pendingCommander.Tell(_pendingSend.Ack); } _retriedSend = false; _pendingSend = null; _pendingCommander = null; } } finally { Udp.BufferPool.Release(buffer); } }
private Receive ReadHandlers(ChannelRegistration registration) { return(message => { if (message is Udp.SuspendReading) { registration.DisableInterest(SocketAsyncOperation.Receive); return true; } if (message is Udp.ResumeReading) { registration.EnableInterest(SocketAsyncOperation.Receive); return true; } if (message is SelectionHandler.ChannelReadable) { DoReceive(registration, _bind.Handler); return true; } if (message is Udp.Unbind) { _log.Debug("Unbinding endpoint [{0}]", _bind.LocalAddress); try { Channel.Close(); Sender.Tell(IO.Udp.Unbound.Instance); _log.Debug("Unbound endpoint [{0}], stopping listener", _bind.LocalAddress); } finally { Context.Stop(Self); } return true; } return false; }); }
public Receive SendHandlers(ChannelRegistration registration) { return(message => { var send = message as Udp.Send; if (send != null && HasWritePending) { if (Udp.Setting.TraceLogging) { _log.Debug("Dropping write because queue is full"); } Sender.Tell(new Udp.CommandFailed(send)); return true; } if (send != null && send.Payload.IsEmpty) { if (send.WantsAck) { Sender.Tell(send.Ack); } return true; } if (send != null) { _pendingSend = send; _pendingCommander = Sender; var dns = send.Target as DnsEndPoint; if (dns != null) { var resolved = Dns.ResolveName(dns.Host, Context.System, Self); if (resolved != null) { try { _pendingSend = new Udp.Send(_pendingSend.Payload, new IPEndPoint(resolved.Addr, dns.Port), _pendingSend.Ack); DoSend(registration); } catch (Exception ex) { Sender.Tell(new Udp.CommandFailed(send)); _log.Debug("Failure while sending UDP datagram to remote address [{0}]: {1}", send.Target, ex); _retriedSend = false; _pendingSend = null; _pendingCommander = null; } } } else { DoSend(registration); } return true; } if (message is SelectionHandler.ChannelWritable && HasWritePending) { DoSend(registration); return true; } return false; }); }
private Receive Connected(ChannelRegistration registration) { return(message => { if (message is UdpConnected.SuspendReading) { registration.DisableInterest(SocketAsyncOperation.Receive); return true; } if (message is UdpConnected.ResumeReading) { registration.EnableInterest(SocketAsyncOperation.Receive); return true; } if (message is SelectionHandler.ChannelReadable) { DoRead(registration, _connect.Handler); return true; } if (message is UdpConnected.Disconnect) { _log.Debug("Closing UDP connection to [{0}]", _connect.RemoteAddress); _channel.Close(); Sender.Tell(UdpConnected.Disconnected.Instance); _log.Debug("Connection closed to [{0}], stopping listener", _connect.RemoteAddress); Context.Stop(Self); return true; } var send = message as UdpConnected.Send; if (send != null && WritePending) { if (_udpConn.Settings.TraceLogging) { _log.Debug("Dropping write because queue is full"); } Sender.Tell(new UdpConnected.CommandFailed(send)); return true; } if (send != null && send.Payload.IsEmpty) { if (send.WantsAck) { Sender.Tell(send.Ack); } return true; } if (send != null) { _pendingSend = Tuple.Create(send, Sender); registration.EnableInterest(SocketAsyncOperation.Send); return true; } if (message is SelectionHandler.ChannelWritable) { DoWrite(); return true; } return false; }); }