public void HandleAckMessage(AckMessage ackMessage) { OutboundMessage outboundMessage = null; if (outboundMessagesBySequence.TryGetValue(ackMessage.AckedSequenceNumber, out outboundMessage)) { outboundMessages.Remove(outboundMessage); outboundMessagesBySequence.Remove(ackMessage.AckedSequenceNumber); outboundMessagePool.Push(outboundMessage); } if (isResetPending && outboundMessages.FirstOrDefault(x => x.NeedsAck) == null) { if (IsVerbose) { NeutrinoConfig.Log(node.Name + " drained all outbound - resetting sequence and sending queued"); } isResetPending = false; nextSequence = 0; foreach (byte[] buffer in pendingResetOutboundMessages) { Enqueue(msgFactory.Read(buffer)); } pendingResetOutboundMessages.Clear(); } }
private void HandleMessageReceived(IPEndPoint receivedFrom, byte[] buffer, int numBytesReceived) { NetworkPeer peer = null; if (peersByEndpoint.TryGetValue(receivedFrom, out peer)) { peer.HandleMessageReceived(buffer, numBytesReceived); } else { if (NeutrinoConfig.LogLevel == NeutrinoLogLevel.Debug) { NeutrinoConfig.Log("Received from potentially new peer at " + receivedFrom); } List <NetworkMessage> initialMessages = new List <NetworkMessage>(msgFactory.Read(buffer, numBytesReceived)); var connectMsg = initialMessages.FirstOrDefault <NetworkMessage>(x => (x is ConnectMessage)); if (connectMsg == null) { NeutrinoConfig.Log("Ignoring peer who didn't send a ConnectMessage with his initial traffic"); } else { var newPeer = NeutrinoConfig.CreatePeer(); newPeer.Init(this, serverSocket, receivedFrom.Address, receivedFrom.Port, ((ConnectMessage)connectMsg).Nickname); peersByEndpoint[(IPEndPoint)receivedFrom] = newPeer; endpointsByPeer[newPeer] = (IPEndPoint)receivedFrom; if (OnPeerConnected != null) { OnPeerConnected(newPeer); } newPeer.HandleMessageReceived(buffer, numBytesReceived); } } }
private void BuildInstances(params Assembly[] messageAssemblies) { BuildInstances(typeof(NetworkMessage).Assembly); foreach (Assembly a in messageAssemblies) { BuildInstances(a); } NeutrinoConfig.Log("Built " + messages.Count + " registered network messages"); }
public void Dispose() { NeutrinoConfig.Log("Node shutting down..."); if (serverSocket != null) { serverSocket.Close(1000); serverSocket = null; NeutrinoConfig.Log("Node shutdown"); } }
internal void DisconnectPeer(NetworkPeer peer) { if (NeutrinoConfig.LogLevel == NeutrinoLogLevel.Debug) { NeutrinoConfig.Log("Peer disconnected: " + peer); } if (OnPeerDisconnected != null) { OnPeerDisconnected(peer); } peersByEndpoint.Remove(peer.Endpoint); endpointsByPeer.Remove(peer); }
public void Start() { NeutrinoConfig.Log("Node starting..."); serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); if (ServerHostname == null) { serverSocket.Bind(new IPEndPoint(IPAddress.Any, ServerPort)); } else { serverSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); var addresses = Dns.GetHostAddresses(ServerHostname); if (addresses == null || addresses.Length == 0) { throw new ApplicationException("Unable to resolve server [" + ServerHostname + "]"); } else { IPAddress address = addresses.FirstOrDefault <IPAddress>(x => x.AddressFamily == AddressFamily.InterNetwork); if (address == null) { address = addresses.FirstOrDefault <IPAddress>(x => x.AddressFamily == AddressFamily.InterNetworkV6); } if (address == null) { throw new ApplicationException("Unable to find an IP address for server [" + ServerHostname + "]"); } var serverPeer = NeutrinoConfig.CreatePeer(); serverPeer.Init(this, serverSocket, address, ServerPort, "Server"); IPEndPoint serverEndpoint = new IPEndPoint(address, ServerPort); peersByEndpoint[serverEndpoint] = serverPeer; endpointsByPeer[serverPeer] = serverEndpoint; if (OnPeerConnected != null) { OnPeerConnected(serverPeer); } var connectMsg = msgFactory.Get <ConnectMessage>(); connectMsg.Nickname = localNickname; SendToAll(connectMsg); } } var asyncResult = serverSocket.BeginReceiveFrom(receiveBuffer, 0, NeutrinoConfig.MaxMessageSize, SocketFlags.None, ref receivedEndPoint, new AsyncCallback(HandleMessageReceived), null); if (asyncResult.CompletedSynchronously) { HandleMessageReceived(asyncResult); } NeutrinoConfig.Log("Node started"); }
internal void Update() { outboundQueue.Send(); int ticksSinceActivity = Environment.TickCount - previousActivityTimeTicks; if (ticksSinceActivity >= NeutrinoConfig.PeerTimeoutMillis) { if (NeutrinoConfig.LogLevel == NeutrinoLogLevel.Debug) { NeutrinoConfig.Log("Disconnecting peer " + this + " because of inactivity for " + ticksSinceActivity + " millis"); } Disconnect(); } }
private void ProcessMessage(NetworkMessage msg) { ResetNetworkIdsMessage resetMsg = msg as ResetNetworkIdsMessage; if (resetMsg != null) { Array.Clear(idempotentSequenceNumbers, 0, idempotentSequenceNumbers.Length); if (pendingOutOfSequenceMessages.Count != 0) { NeutrinoConfig.LogError(node.Name + " there were still pending messages when resetting id's!"); pendingOutOfSequenceMessages.Clear(); } } node.OnReceived(msg); }
public void Enqueue(NetworkMessage msg) { if (isResetPending && msg.IsGuaranteed) { if (IsVerbose) { NeutrinoConfig.Log(node.Name + " reset pending enqueuing for later: " + msg); } byte[] buffer = new byte[NeutrinoConfig.MaxMessageSize]; msg.Write(buffer); pendingResetOutboundMessages.Add(buffer); } else { var outboundMessage = outboundMessagePool.Pop(); Assign(msg, outboundMessage); outboundMessages.Add(outboundMessage); } }
public void Update() { lock (readyBuffers) { buffersToProcess.AddRange(readyBuffers); readyBuffers.Clear(); } foreach (var bufferToProcess in buffersToProcess) { HandleMessageReceived(bufferToProcess.Endpoint, bufferToProcess.Buffer, bufferToProcess.NumBytesReceived); receivedBuffers.Push(bufferToProcess); } buffersToProcess.Clear(); #if DEBUG lock (receivedBuffersForShuffling) { for (int i = receivedBuffersForShuffling.Count - 1; i >= 0; i--) { var deferred = receivedBuffersForShuffling[i]; if (deferred.TimeToReceiveTicks <= Environment.TickCount) { NeutrinoConfig.LogWarning(Name + " injecting shuffled receipt..."); HandleMessageReceived(deferred.Endpoint, deferred.ReceivedBuffer, deferred.ReceivedBuffer.Length); receivedBuffersForShuffling.RemoveAt(i); } } } #endif foreach (NetworkPeer c in peersByEndpoint.Values) { c.Update(); if (!c.IsConnected) { peersPendingDisconnect.Add(c); } } foreach (NetworkPeer c in peersPendingDisconnect) { DisconnectPeer(c); } peersPendingDisconnect.Clear(); }
private void BuildInstances(Assembly messageAssembly) { Type networkMsgType = typeof(NetworkMessage); foreach (Type t in messageAssembly.GetTypes()) { if (t.IsSubclassOf(networkMsgType) && !messagesByType.ContainsKey(t)) { if (messages.Count == Byte.MaxValue) { throw new ApplicationException("The maximum number of network messages has been reached - you need to use fewer message types in this project"); } var msg = (NetworkMessage)t.GetConstructor(Type.EmptyTypes).Invoke(Utility.emptyArgs); msg.Id = (byte)messages.Count; messages[msg.Id] = msg; messagesByType[msg.GetType()] = msg; NeutrinoConfig.Log("Registered message type " + msg.GetType() + " as Id " + msg.Id); } } }
private void Assign(NetworkMessage msg, OutboundMessage target) { target.ContainedMessageType = msg.GetType(); if (msg.IsGuaranteed) { target.SequenceNumber = nextSequence++; outboundMessagesBySequence[target.SequenceNumber] = target; msg.SequenceNumber = target.SequenceNumber; } target.PayloadLength = msg.Write(target.Payload); target.NeedsAck = msg.IsGuaranteed; target.PreviousSendTicks = Environment.TickCount - resendGuaranteedPeriodTicks - 1; if (!(msg is ResetNetworkIdsMessage) && nextSequence == maxGuaranteedBeforeReset) { if (IsVerbose) { NeutrinoConfig.Log(node.Name + " reached max sequence - resetting..."); } Enqueue(msgFactory.Get <ResetNetworkIdsMessage>()); isResetPending = true; } }
private void HandleMessageReceived(IAsyncResult result) { if (serverSocket != null) { try { #if DEBUG if (SimulatedPacketLossRate > 0.0 && (randomGenerator.NextDoublePositive() <= SimulatedPacketLossRate)) { NeutrinoConfig.LogWarning("SIMULATING PACKET LOSS!"); receivedEndPoint = new IPEndPoint(IPAddress.Any, 0); IAsyncResult asyncResult = serverSocket.BeginReceiveFrom(receiveBuffer, 0, NeutrinoConfig.MaxMessageSize, SocketFlags.None, ref receivedEndPoint, new AsyncCallback(HandleMessageReceived), null); if (asyncResult.CompletedSynchronously) { HandleMessageReceived(asyncResult); } return; } else if (SimulatedPacketShuffleRate > 0.0 && (randomGenerator.NextDoublePositive() <= SimulatedPacketShuffleRate)) { NeutrinoConfig.LogWarning("SIMULATING PACKET OUT OF ORDER!"); int numReceived = serverSocket.EndReceiveFrom(result, ref receivedEndPoint); byte[] receivedForShuffle = new byte[numReceived]; Array.Copy(receiveBuffer, receivedForShuffle, numReceived); lock (receivedBuffersForShuffling) { receivedBuffersForShuffling.Add(new DeferredReceivable() { ReceivedBuffer = receivedForShuffle, TimeToReceiveTicks = Environment.TickCount + (int)(randomGenerator.NextDoublePositive() * 100.0), Endpoint = (IPEndPoint)receivedEndPoint }); } receivedEndPoint = new IPEndPoint(IPAddress.Any, 0); IAsyncResult asyncResult = serverSocket.BeginReceiveFrom(receiveBuffer, 0, NeutrinoConfig.MaxMessageSize, SocketFlags.None, ref receivedEndPoint, new AsyncCallback(HandleMessageReceived), null); if (asyncResult.CompletedSynchronously) { HandleMessageReceived(asyncResult); } return; } #endif int numBytesReceived = serverSocket.EndReceiveFrom(result, ref receivedEndPoint); var receivedBuffer = receivedBuffers.Pop(); Array.Copy(receiveBuffer, receivedBuffer.Buffer, numBytesReceived); receivedBuffer.NumBytesReceived = numBytesReceived; receivedBuffer.Endpoint = (IPEndPoint)receivedEndPoint; lock (readyBuffers) readyBuffers.Add(receivedBuffer); } catch (Exception ex) { NeutrinoConfig.LogError("Error handling message: " + ex); } // TBD: When tests are complete, test whether we need to reallocate here? receivedEndPoint = new IPEndPoint(IPAddress.Any, 0); IAsyncResult repeatAsyncResult = serverSocket.BeginReceiveFrom(receiveBuffer, 0, NeutrinoConfig.MaxMessageSize, SocketFlags.None, ref receivedEndPoint, new AsyncCallback(HandleMessageReceived), null); if (repeatAsyncResult.CompletedSynchronously) { HandleMessageReceived(repeatAsyncResult); } } }