Example #1
0
 internal void EnqueueReceivedMessage(IncomingNetMessage msg)
 {
     lock (m_receivedMessages)
     {
         m_receivedMessages.Enqueue(msg);
     }
     m_dataReceivedEvent.Set();
 }
Example #2
0
        /// <summary>
        /// Creates an incoming net message
        /// </summary>
        internal IncomingNetMessage CreateIncomingMessage()
        {
            // no recycling for messages
            IncomingNetMessage msg = new IncomingNetMessage();

            msg.m_msgType = NetMessageType.Data;
            msg.m_data    = CreateBuffer();
            return(msg);
        }
Example #3
0
        internal void NotifyApplication(NetMessageType tp, NetBuffer buffer, NetConnection conn, IPEndPoint ep)
        {
            IncomingNetMessage msg = new IncomingNetMessage();

            msg.m_data           = buffer;
            msg.m_msgType        = tp;
            msg.m_sender         = conn;
            msg.m_senderEndPoint = ep;

            EnqueueReceivedMessage(msg);
        }
        /// <summary>
        /// Returns a NetMessage to return to application; or null if nothing
        /// </summary>
        internal IncomingNetMessage HandleResponse(
            IncomingNetMessage message,
            NetworkEndPoint endPoint
            )
        {
            if ((m_netBase.m_enabledMessageTypes & NetMessageType.ServerDiscovered) != NetMessageType.ServerDiscovered)
            {
                return(null);                // disabled
            }
            if (message.m_data == null || m_requests == null)
            {
                return(null);
            }

            ushort number = message.m_data.ReadUInt16();

            // find corresponding request
            NetDiscoveryRequest found = null;

            foreach (NetDiscoveryRequest request in m_requests)
            {
                if (request.Number == number)
                {
                    found = request;
                    break;
                }
            }

            if (found == null)
            {
                m_netBase.LogVerbose("Received discovery response to request " + number + " - unknown/old request!");
                return(null);                // Timed out request or not found
            }

            if (found.HasDiscovered(endPoint))
            {
                m_netBase.LogVerbose("Received discovery response to request " + number + " - previously known response!");
                return(null);                // Already discovered in this request, else stored it
            }

            m_netBase.LogVerbose("Received discovery response to request " + number + " - passing on to app...");

            IncomingNetMessage resMsg = m_netBase.CreateIncomingMessage();

            resMsg.m_msgType = NetMessageType.ServerDiscovered;

            // write sender, assume ipv4
            resMsg.m_data.Write(endPoint);

            return(resMsg);
        }
Example #5
0
        /// <summary>
        /// Emit receipt event
        /// </summary>
        internal void FireReceipt(NetConnection connection, NetBuffer receiptData)
        {
            if ((m_enabledMessageTypes & NetMessageType.Receipt) != NetMessageType.Receipt)
            {
                return;                 // disabled
            }
            IncomingNetMessage msg = CreateIncomingMessage();

            msg.m_sender  = connection;
            msg.m_msgType = NetMessageType.Receipt;
            msg.m_data    = receiptData;

            EnqueueReceivedMessage(msg);
        }
Example #6
0
        /// <summary>
        /// Returns true if message should be dropped
        /// </summary>
        internal bool HandleNATIntroduction(IncomingNetMessage message)
        {
            if (message.m_type == NetMessageLibraryType.System)
            {
                if (message.m_data.LengthBytes > 4 && message.m_data.PeekByte() == (byte)NetSystemType.NatIntroduction)
                {
                    if ((m_enabledMessageTypes & NetMessageType.NATIntroduction) != NetMessageType.NATIntroduction)
                    {
                        return(true);                        // drop
                    }
                    try
                    {
                        message.m_data.ReadByte();                         // step past system type byte
                        IPEndPoint presented = message.m_data.ReadIPEndPoint();

                        LogVerbose("Received NATIntroduction to " + presented + "; sending punching ping...");

                        double now = NetTime.Now;
                        NetConnection.SendPing(this, presented, now);

                        if (m_holePunches == null)
                        {
                            m_holePunches = new List <IPEndPoint>();
                        }

                        for (int i = 0; i < 5; i++)
                        {
                            m_holePunches.Add(new IPEndPoint(presented.Address, presented.Port));
                        }

                        NetBuffer info = CreateBuffer();
                        info.Write(presented);
                        NotifyApplication(NetMessageType.NATIntroduction, info, message.m_sender, message.m_senderEndPoint);
                        return(true);
                    }
                    catch (Exception ex)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Bad NAT introduction message received: " + ex.Message, message.m_sender, message.m_senderEndPoint);
                        return(true);
                    }
                }
            }
            return(false);
        }
        internal bool VerifyIdentifiers(
            IncomingNetMessage message,
            NetworkEndPoint endPoint,
            out ushort number
            )
        {
            number = 0;
            int payLen = message.m_data.LengthBytes;

            if (payLen < 13)
            {
                if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                {
                    m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Discovery message received from " + endPoint, null, message.m_senderEndPoint);
                }
                return(false);
            }

            // check app identifier
            string appIdent2 = message.m_data.ReadString();

            if (appIdent2 != m_netBase.m_config.ApplicationIdentifier)
            {
                if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                {
                    m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Discovery for different application identification received: " + appIdent2, null, message.m_senderEndPoint);
                }
                return(false);
            }

            // check netbase identifier
            byte[] nbid = message.m_data.ReadBytes(m_netBase.m_localRndSignature.Length);
            if (NetUtility.CompareElements(nbid, m_netBase.m_localRndSignature))
            {
                return(false);                // don't respond to your own discovery request
            }
            // retrieve number
            number = message.m_data.ReadUInt16();

            // it's ok
            return(true);
        }
Example #8
0
        /// <summary>
        /// Notify application that a connection changed status
        /// </summary>
        internal void NotifyStatusChange(NetConnection connection, string reason)
        {
            if ((m_enabledMessageTypes & NetMessageType.StatusChanged) != NetMessageType.StatusChanged)
            {
                return;                 // disabled
            }
            //NotifyApplication(NetMessageType.StatusChanged, reason, connection);
            NetBuffer buffer = CreateBuffer(reason.Length + 2);

            buffer.Write(reason);
            buffer.Write((byte)connection.Status);

            IncomingNetMessage msg = new IncomingNetMessage();

            msg.m_data           = buffer;
            msg.m_msgType        = NetMessageType.StatusChanged;
            msg.m_sender         = connection;
            msg.m_senderEndPoint = null;

            EnqueueReceivedMessage(msg);
        }
Example #9
0
        /// <summary>
        /// Handle a discovery request
        /// </summary>
        internal void HandleRequest(IncomingNetMessage message, IPEndPoint senderEndpoint)
        {
            ushort number;

            if (!VerifyIdentifiers(message, senderEndpoint, out number))
                return; // bad app ident or self discovery

            NetBuffer buf = m_netBase.CreateBuffer(2);
            buf.Write(number);

            m_netBase.LogVerbose("Sending discovery response to request " + number);

            // send discovery response
            m_netBase.SendSingleUnreliableSystemMessage(
                NetSystemType.DiscoveryResponse,
                buf,
                senderEndpoint,
                false
            );

            m_netBase.RecycleBuffer(buf);
        }
        /// <summary>
        /// Handle a discovery request
        /// </summary>
        internal void HandleRequest(IncomingNetMessage message, NetworkEndPoint senderEndpoint)
        {
            ushort number;

            if (!VerifyIdentifiers(message, senderEndpoint, out number))
            {
                return;                 // bad app ident or self discovery
            }
            NetBuffer buf = m_netBase.CreateBuffer(2);

            buf.Write(number);

            m_netBase.LogWrite("Sending discovery response to " + senderEndpoint + " request " + number);

            // send discovery response
            m_netBase.SendSingleUnreliableSystemMessage(
                NetSystemType.DiscoveryResponse,
                buf,
                senderEndpoint,
                null
                );

            m_netBase.RecycleBuffer(buf);
        }
        internal override void HandleReceivedMessage(IncomingNetMessage message, NetworkEndPoint senderEndpoint, double localTimeRecv)
        {
            //LogWrite("NetClient received message " + message);
            double now = NetTime.Now;

            int payLen = message.m_data.LengthBytes;

            // Discovery response?
            if (message.m_type == NetMessageLibraryType.System && payLen > 0)
            {
                NetSystemType sysType = (NetSystemType)message.m_data.PeekByte();

                if (sysType == NetSystemType.DiscoveryResponse)
                {
                    message.m_data.ReadByte();                     // step past system type byte
                    IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint);
                    if (resMsg != null)
                    {
                        resMsg.m_senderEndPoint = senderEndpoint;
                        EnqueueReceivedMessage(resMsg);
                    }
                    return;
                }
            }

            // Out of band?
            if (message.m_type == NetMessageLibraryType.OutOfBand)
            {
                if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData)
                {
                    return;                     // drop
                }
                // just deliver
                message.m_msgType        = NetMessageType.OutOfBandData;
                message.m_senderEndPoint = senderEndpoint;
                EnqueueReceivedMessage(message);
                return;
            }

            if (message.m_sender != m_serverConnection && m_serverConnection != null)
            {
                return;                 // don't talk to strange senders after this
            }
            if (message.m_type == NetMessageLibraryType.Acknowledge)
            {
                m_serverConnection.HandleAckMessage(now, message);
                return;
            }

            // Handle system types
            if (message.m_type == NetMessageLibraryType.System)
            {
                if (payLen < 1)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message: " + message, m_serverConnection, senderEndpoint);
                    }
                    return;
                }
                NetSystemType sysType = (NetSystemType)message.m_data.Data[0];
                switch (sysType)
                {
                case NetSystemType.ConnectResponse:
                case NetSystemType.Ping:
                case NetSystemType.Pong:
                case NetSystemType.Disconnect:
                case NetSystemType.ConnectionRejected:
                case NetSystemType.StringTableAck:
                    if (m_serverConnection != null)
                    {
                        m_serverConnection.HandleSystemMessage(message, localTimeRecv);
                    }
                    return;

                case NetSystemType.Connect:
                case NetSystemType.ConnectionEstablished:
                case NetSystemType.Discovery:
                case NetSystemType.Error:
                default:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for client and " + sysType, m_serverConnection, senderEndpoint);
                    }
                    return;
                }
            }

            Debug.Assert(
                message.m_type == NetMessageLibraryType.User ||
                message.m_type == NetMessageLibraryType.UserFragmented
                );

            if (m_serverConnection.Status == NetConnectionStatus.Connecting)
            {
                m_serverConnection.Disconnect("Received user message before ConnectResponse", 0.0f, true, true);
                return;

                /*
                 * // lost connectresponse packet?
                 * // Emulate it;
                 * LogVerbose("Received user message before ConnectResponse; emulating ConnectResponse...", m_serverConnection);
                 * IncomingNetMessage emuMsg = CreateIncomingMessage();
                 * emuMsg.m_type = NetMessageLibraryType.System;
                 * emuMsg.m_data.Reset();
                 * emuMsg.m_data.Write((byte)NetSystemType.ConnectResponse);
                 * m_serverConnection.HandleSystemMessage(emuMsg, now);
                 */

                // ... and proceed to pick up user message
            }

            // add to pick-up queue
            m_serverConnection.HandleUserMessage(message, now);
        }
Example #12
0
 /// <summary>
 /// Creates an incoming net message
 /// </summary>
 internal IncomingNetMessage CreateIncomingMessage()
 {
     // no recycling for messages
     IncomingNetMessage msg = new IncomingNetMessage();
     msg.m_msgType = NetMessageType.Data;
     msg.m_data = CreateBuffer();
     return msg;
 }
Example #13
0
		/*
		internal void HandleUserMessage(NetMessage msg)
		{
			int seqNr = msg.m_sequenceNumber;
			int chanNr = (int)msg.m_sequenceChannel;
			bool isDuplicate = false;

			int relation = RelateToExpected(seqNr, chanNr, out isDuplicate);

			//
			// Unreliable
			//
			if (msg.m_sequenceChannel == NetChannel.Unreliable)
			{
				// It's all good; add message
				if (isDuplicate)
				{
					m_statistics.CountDuplicateMessage(msg);
					m_owner.LogVerbose("Rejecting duplicate " + msg, this);
				}
				else
				{
					AcceptMessage(msg);
				}
				return;
			}

			//
			// Reliable unordered
			//
			if (msg.m_sequenceChannel == NetChannel.ReliableUnordered)
			{
				// send acknowledge (even if duplicate)
				m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber);

				if (isDuplicate)
				{
					m_statistics.CountDuplicateMessage(msg);
					m_owner.LogVerbose("Rejecting duplicate " + msg, this);
					return; // reject duplicates
				}

				// It's good; add message
				AcceptMessage(msg);

				return;
			}

			ushort nextSeq = (ushort)(seqNr + 1);

			if (chanNr < (int)NetChannel.ReliableInOrder1)
			{
				//
				// Sequenced
				//
				if (relation < 0)
				{
					// late sequenced message
					m_statistics.CountDroppedSequencedMessage();
					m_owner.LogVerbose("Dropping late sequenced " + msg, this);
					return;
				}

				// It's good; add message
				AcceptMessage(msg);

				m_nextExpectedSequence[chanNr] = nextSeq;
				return;
			}
			else
			{
				//
				// Ordered
				// 

				// send ack (regardless)
				m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber);

				if (relation < 0)
				{
					// late ordered message
#if DEBUG
					if (!isDuplicate)
						m_owner.LogWrite("Ouch, weird! Late ordered message that's NOT a duplicate?! seqNr: " + seqNr + " expecting: " + m_nextExpectedSequence[chanNr], this);
#endif
					// must be duplicate
					m_owner.LogVerbose("Dropping duplicate message " + seqNr, this);
					m_statistics.CountDuplicateMessage(msg);
					return; // rejected; don't advance next expected
				}

				if (relation > 0)
				{
					// early message; withhold ordered
					m_owner.LogVerbose("Withholding " + msg + " (expecting " + m_nextExpectedSequence[chanNr] + ")", this);
					m_withheldMessages.Add(msg);
					return; // return without advancing next expected
				}

				// It's right on time!
				AcceptMessage(msg);

				// ordered; release other withheld messages?
				bool released = false;
				do
				{
					released = false;
					foreach (NetMessage wm in m_withheldMessages)
					{
						if ((int)wm.m_sequenceChannel == chanNr && wm.m_sequenceNumber == nextSeq)
						{
							m_owner.LogVerbose("Releasing withheld message " + wm, this);
							m_withheldMessages.Remove(wm);
							AcceptMessage(wm);
							// no need to set rounds for this message; it was one when first related() and withheld
							nextSeq++;
							if (nextSeq >= NetConstants.NumSequenceNumbers)
								nextSeq -= NetConstants.NumSequenceNumbers;
							released = true;
							break;
						}
					}
				} while (released);
			}

			// Common to Sequenced and Ordered

			//m_owner.LogVerbose("Setting next expected for " + (NetChannel)chanNr + " to " + nextSeq);
			m_nextExpectedSequence[chanNr] = nextSeq;

			return;
		}
		*/

		internal void HandleSystemMessage(IncomingNetMessage msg, double now)
		{
			msg.m_data.Position = 0;
			NetSystemType sysType = (NetSystemType)msg.m_data.ReadByte();
			OutgoingNetMessage response = null;
			switch (sysType)
			{
				case NetSystemType.Disconnect:
					if (m_status == NetConnectionStatus.Disconnected)
						return;
					Disconnect(msg.m_data.ReadString(), 0.75f + ((float)m_currentAvgRoundtrip * 4), false, false);
					break;
				case NetSystemType.ConnectionRejected:
					m_owner.NotifyApplication(NetMessageType.ConnectionRejected, msg.m_data.ReadString(), msg.m_sender, msg.m_senderEndPoint);
					break;
				case NetSystemType.Connect:

					// ConnectReponse must have been losts
					
					string appIdent = msg.m_data.ReadString();
					if (appIdent != m_owner.m_config.ApplicationIdentifier)
					{
						if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
							m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, msg.m_senderEndPoint);
						return;
					}

					// read random identifer
					byte[] rnd = msg.m_data.ReadBytes(8);
					if (NetUtility.CompareElements(rnd, m_owner.m_randomIdentifier))
					{
						// don't allow self-connect
						if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
							m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint);
						return;
					}

					// read hail data
					m_remoteHailData = null;
					int hailBytesCount = (msg.m_data.LengthBits - msg.m_data.Position) / 8;
					if (hailBytesCount > 0)
						m_remoteHailData = msg.m_data.ReadBytes(hailBytesCount);

					// finalize disconnect if it's in process
					if (m_status == NetConnectionStatus.Disconnecting)
						FinalizeDisconnect();

					// send response; even if connected
					response = m_owner.CreateSystemMessage(NetSystemType.ConnectResponse);
					if (m_localHailData != null)
						response.m_data.Write(m_localHailData);
					m_unsentMessages.Enqueue(response);

					break;
				case NetSystemType.ConnectResponse:
					if (m_status != NetConnectionStatus.Connecting && m_status != NetConnectionStatus.Connected)
					{
						m_owner.LogWrite("Received connection response but we're not connecting...", this);
						return;
					}
					
					// read hail data
					m_remoteHailData = null;
					int numHailBytes = (msg.m_data.LengthBits - msg.m_data.Position) / 8;
					if (numHailBytes > 0)
						m_remoteHailData = msg.m_data.ReadBytes(numHailBytes);

					// Send connectionestablished
					response = m_owner.CreateSystemMessage(NetSystemType.ConnectionEstablished);
					if (m_localHailData != null)
						response.m_data.Write(m_localHailData);
					m_unsentMessages.Enqueue(response);

					// send first ping 250ms after connected
					m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f);
					m_statistics.Reset();
					SetInitialAveragePing(now - m_handshakeInitiated);
					SetStatus(NetConnectionStatus.Connected, "Connected");
					break;
				case NetSystemType.ConnectionEstablished:
					if (m_status != NetConnectionStatus.Connecting)
					{
						if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
							m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Received connection response but we're not connecting...", this, msg.m_senderEndPoint);
						return;
					}

					// read hail data
					if (m_remoteHailData == null)
					{
						int hbc = (msg.m_data.LengthBits - msg.m_data.Position) / 8;
						if (hbc > 0)
							m_remoteHailData = msg.m_data.ReadBytes(hbc);
					}

					// send first ping 100-350ms after connected
					m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f);
					m_statistics.Reset();
					SetInitialAveragePing(now - m_handshakeInitiated);
					SetStatus(NetConnectionStatus.Connected, "Connected");
					break;
				case NetSystemType.Ping:
					// also accepted as ConnectionEstablished
					if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting)
					{
						m_owner.LogWrite("Received ping; interpreted as ConnectionEstablished", this);
						m_statistics.Reset();
						SetInitialAveragePing(now - m_handshakeInitiated);
						SetStatus(NetConnectionStatus.Connected, "Connected");
					}

					//LogWrite("Received ping; sending pong...");
					SendPong(m_owner, m_remoteEndPoint, now);
					break;
				case NetSystemType.Pong:
					double twoWayLatency = now - m_lastSentPing;
					if (twoWayLatency < 0)
						break;
					ReceivedPong(twoWayLatency, msg);
					break;
				case NetSystemType.StringTableAck:
					ushort val = msg.m_data.ReadUInt16();
					StringTableAcknowledgeReceived(val);
					break;
				default:
					m_owner.LogWrite("Undefined behaviour in NetConnection for system message " + sysType, this);
					break;
			}
		}
		/// <summary>
		/// Called when a message should be released to the application
		/// </summary>
		private void AcceptMessage(IncomingNetMessage msg)
		{
			if (msg.m_type == NetMessageLibraryType.UserFragmented)
			{
				// parse
				int id = msg.m_data.ReadUInt16();
				int number = (int)msg.m_data.ReadVariableUInt32(); // 0 to total-1
				int total = (int)msg.m_data.ReadVariableUInt32();

				int bytePtr = msg.m_data.Position / 8;
				int payloadLen = msg.m_data.LengthBytes - bytePtr;

				FragmentedMessage fmsg;
				if (!m_fragments.TryGetValue(id, out fmsg))
				{
					fmsg = new FragmentedMessage();
					fmsg.TotalFragments = total;
					fmsg.FragmentsReceived = 0;
					fmsg.ChunkSize = payloadLen;
					fmsg.Data = new byte[payloadLen * total];
					m_fragments[id] = fmsg;
				}

				// insert this fragment
				Array.Copy(
					msg.m_data.Data,
					bytePtr,
					fmsg.Data,
					number * fmsg.ChunkSize,
					payloadLen
				);

				fmsg.BitLength += (msg.m_data.m_bitLength - msg.m_data.Position);
				fmsg.FragmentsReceived++;

				m_owner.LogVerbose("Fragment " + id + " - " + (number+1) + "/" + total + " received; chunksize " + fmsg.ChunkSize + " this size " + payloadLen, this);

				if (fmsg.FragmentsReceived < fmsg.TotalFragments)
				{
					// Not yet complete
					return;
				}

				// Done! Release it as a complete message
				NetBuffer buf = new NetBuffer(false);
				buf.Data = fmsg.Data;

				//int bitLen = (fmsg.TotalFragments - 1) * fmsg.ChunkSize * 8;
				//bitLen += msg.m_data.m_bitLength - (bytePtr * 8);

				buf.m_bitLength = fmsg.BitLength;

				m_fragments.Remove(id);

				// reuse "msg"
				m_owner.LogVerbose("All fragments received; complete length is " + buf.LengthBytes, this);
				msg.m_data = buf;
			}

			// release
			// m_owner.LogVerbose("Accepted " + msg, this);

			// Debug.Assert(msg.m_type == NetMessageLibraryType.User);

			lock(m_owner.m_receivedMessages)
				m_owner.m_receivedMessages.Enqueue(msg);
		}
 internal void EnqueueReceivedMessage(IncomingNetMessage msg)
 {
     m_receivedMessages.Enqueue(msg);
 }
Example #16
0
        internal override void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint)
        {
            double now = NetTime.Now;

            int payLen = message.m_data.LengthBytes;

            // NAT introduction?
            if (HandleNATIntroduction(message))
                return;

            // Out of band?
            if (message.m_type == NetMessageLibraryType.OutOfBand)
            {
                if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData)
                    return; // drop

                // just deliever
                message.m_msgType = NetMessageType.OutOfBandData;
                message.m_senderEndPoint = senderEndpoint;

                EnqueueReceivedMessage(message);
                return;
            }

            if (message.m_sender == null)
            {
                //
                // Handle unconnected message
                //

                // not a connected sender; only allow System messages
                if (message.m_type != NetMessageLibraryType.System)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        NotifyApplication(NetMessageType.BadMessageReceived, "Rejecting non-system message from unconnected source: " + message, null, message.m_senderEndPoint);
                    return;
                }

                // read type of system message
                NetSystemType sysType = (NetSystemType)message.m_data.ReadByte();
                switch (sysType)
                {
                    case NetSystemType.Connect:

                        LogVerbose("Connection request received from " + senderEndpoint);

                        // check app ident
                        if (payLen < 4)
                        {
                            if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                                NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Connect message received from " + senderEndpoint, null, senderEndpoint);
                            return;
                        }
                        string appIdent = message.m_data.ReadString();
                        if (appIdent != m_config.ApplicationIdentifier)
                        {
                            if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                                NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, senderEndpoint);
                            return;
                        }

                        // read random identifer
                        byte[] rnd = message.m_data.ReadBytes(8);
                        if (NetUtility.CompareElements(rnd, m_randomIdentifier))
                        {
                            // don't allow self-connect
                            if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                                NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, senderEndpoint);
                            return;
                        }

                        int bytesReadSoFar = (message.m_data.Position / 8);
                        int hailLen = message.m_data.LengthBytes - bytesReadSoFar;
                        byte[] hailData = null;
                        if (hailLen > 0)
                        {
                            hailData = new byte[hailLen];
                            Buffer.BlockCopy(message.m_data.Data, bytesReadSoFar, hailData, 0, hailLen);
                        }

                        if (m_connections.Count >= m_config.m_maxConnections)
                        {
                            if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                                NotifyApplication(NetMessageType.ConnectionRejected, "Server full; rejecting connect from " + senderEndpoint, null, senderEndpoint);
                            return;
                        }

                        // Create connection
                        LogWrite("New connection: " + senderEndpoint);
                        NetConnection conn = new NetConnection(this, senderEndpoint, null, hailData);

                        // Connection approval?
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionApproval) == NetMessageType.ConnectionApproval)
                        {
                            // Ask application if this connection is allowed to proceed
                            IncomingNetMessage app = CreateIncomingMessage();
                            app.m_msgType = NetMessageType.ConnectionApproval;
                            if (hailData != null)
                                app.m_data.Write(hailData);
                            app.m_sender = conn;
                            conn.m_approved = false;
                            EnqueueReceivedMessage(app);
                            // Don't add connection; it's done as part of the approval procedure
                            return;
                        }

                        // it's ok
                        AddConnection(now, conn);
                        break;
                    case NetSystemType.ConnectionEstablished:
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                            NotifyApplication(NetMessageType.BadMessageReceived, "Connection established received from non-connection! " + senderEndpoint, null, senderEndpoint);
                        return;
                    case NetSystemType.Discovery:
                        if (m_config.AnswerDiscoveryRequests)
                            m_discovery.HandleRequest(message, senderEndpoint);
                        break;
                    case NetSystemType.DiscoveryResponse:
                        if (m_allowOutgoingConnections)
                        {
                            // NetPeer
                            IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint);
                            if (resMsg != null)
                            {
                                resMsg.m_senderEndPoint = senderEndpoint;
                                EnqueueReceivedMessage(resMsg);
                            }
                        }
                        break;
                    default:
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                            NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint);
                        break;
                }
                // done
                return;
            }

            // ok, we have a sender
            if (message.m_type == NetMessageLibraryType.Acknowledge)
            {
                message.m_sender.HandleAckMessage(message);
                return;
            }

            if (message.m_type == NetMessageLibraryType.System)
            {
                //
                // Handle system messages from connected source
                //

                if (payLen < 1)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message; payload length less than 1 byte", null, senderEndpoint);
                    return;
                }
                NetSystemType sysType = (NetSystemType)message.m_data.ReadByte();
                switch (sysType)
                {
                    case NetSystemType.Connect:
                    case NetSystemType.ConnectionEstablished:
                    case NetSystemType.Ping:
                    case NetSystemType.Pong:
                    case NetSystemType.Disconnect:
                    case NetSystemType.ConnectionRejected:
                    case NetSystemType.StringTableAck:
                        message.m_sender.HandleSystemMessage(message, now);
                        break;
                    case NetSystemType.ConnectResponse:
                        if (m_allowOutgoingConnections)
                        {
                            message.m_sender.HandleSystemMessage(message, now);
                        }
                        else
                        {
                            if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                                NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint);
                        }
                        break;
                    case NetSystemType.Discovery:
                        // Allow discovery even if connected
                        if (m_config.AnswerDiscoveryRequests)
                            m_discovery.HandleRequest(message, senderEndpoint);
                        break;
                    default:
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                            NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint);
                        break;
                }
                return;
            }

            message.m_sender.HandleUserMessage(message);
        }
Example #17
0
        internal override void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint)
        {
            //LogWrite("NetClient received message " + message);
            double now = NetTime.Now;

            int payLen = message.m_data.LengthBytes;

            // Discovery response?
            if (message.m_type == NetMessageLibraryType.System && payLen > 0)
            {
                NetSystemType sysType = (NetSystemType)message.m_data.PeekByte();

                // NAT introduction?
                if (HandleNATIntroduction(message))
                    return;

                if (sysType == NetSystemType.DiscoveryResponse)
                {
                    message.m_data.ReadByte(); // step past system type byte
                    IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint);
                    if (resMsg != null)
                    {
                        resMsg.m_senderEndPoint = senderEndpoint;
                        lock (m_receivedMessages)
                            m_receivedMessages.Enqueue(resMsg);
                    }
                    return;
                }
            }

            // Out of band?
            if (message.m_type == NetMessageLibraryType.OutOfBand)
            {
                if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData)
                    return; // drop

                // just deliever
                message.m_msgType = NetMessageType.OutOfBandData;
                message.m_senderEndPoint = senderEndpoint;
                lock (m_receivedMessages)
                    m_receivedMessages.Enqueue(message);
                return;
            }

            if (message.m_sender != m_serverConnection && m_serverConnection != null)
                return; // don't talk to strange senders after this

            if (message.m_type == NetMessageLibraryType.Acknowledge)
            {
                m_serverConnection.HandleAckMessage(message);
                return;
            }

            // Handle system types
            if (message.m_type == NetMessageLibraryType.System)
            {
                if (payLen < 1)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message: " + message, m_serverConnection, senderEndpoint);
                    return;
                }
                NetSystemType sysType = (NetSystemType)message.m_data.Data[0];
                switch (sysType)
                {
                    case NetSystemType.ConnectResponse:
                    case NetSystemType.Ping:
                    case NetSystemType.Pong:
                    case NetSystemType.Disconnect:
                    case NetSystemType.ConnectionRejected:
                    case NetSystemType.StringTableAck:
                        if (m_serverConnection != null)
                            m_serverConnection.HandleSystemMessage(message, now);
                        return;
                    case NetSystemType.Connect:
                    case NetSystemType.ConnectionEstablished:
                    case NetSystemType.Discovery:
                    case NetSystemType.Error:
                    default:
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                            NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for client and " + sysType, m_serverConnection, senderEndpoint);
                        return;
                }
            }

            Debug.Assert(
                message.m_type == NetMessageLibraryType.User ||
                message.m_type == NetMessageLibraryType.UserFragmented
            );

            if (m_serverConnection.Status == NetConnectionStatus.Connecting)
            {
                // lost connectresponse packet?
                // Emulate it;
                LogVerbose("Received user message before ConnectResponse; emulating ConnectResponse...", m_serverConnection);
                IncomingNetMessage emuMsg = CreateIncomingMessage();
                emuMsg.m_type = NetMessageLibraryType.System;
                emuMsg.m_data.Reset();
                emuMsg.m_data.Write((byte)NetSystemType.ConnectResponse);
                m_serverConnection.HandleSystemMessage(emuMsg, now);

                // ... and proceed to pick up user message
            }

            // add to pick-up queue
            m_serverConnection.HandleUserMessage(message);
        }
Example #18
0
        internal override void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint)
        {
            double now = NetTime.Now;

            int payLen = message.m_data.LengthBytes;

            // NAT introduction?
            if (HandleNATIntroduction(message))
            {
                return;
            }

            // Out of band?
            if (message.m_type == NetMessageLibraryType.OutOfBand)
            {
                if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData)
                {
                    return;                     // drop
                }
                // just deliever
                message.m_msgType        = NetMessageType.OutOfBandData;
                message.m_senderEndPoint = senderEndpoint;
                lock (m_receivedMessages)
                    m_receivedMessages.Enqueue(message);
                return;
            }

            if (message.m_sender == null)
            {
                //
                // Handle unconnected message
                //

                // not a connected sender; only allow System messages
                if (message.m_type != NetMessageLibraryType.System)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Rejecting non-system message from unconnected source: " + message, null, message.m_senderEndPoint);
                    }
                    return;
                }

                // read type of system message
                NetSystemType sysType = (NetSystemType)message.m_data.ReadByte();
                switch (sysType)
                {
                case NetSystemType.Connect:

                    LogVerbose("Connection request received from " + senderEndpoint);

                    // check app ident
                    if (payLen < 4)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Connect message received from " + senderEndpoint, null, senderEndpoint);
                        }
                        return;
                    }
                    string appIdent = message.m_data.ReadString();
                    if (appIdent != m_config.ApplicationIdentifier)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, senderEndpoint);
                        }
                        return;
                    }

                    // read random identifer
                    byte[] rnd = message.m_data.ReadBytes(8);
                    if (NetUtility.CompareElements(rnd, m_randomIdentifier))
                    {
                        // don't allow self-connect
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                        {
                            NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, senderEndpoint);
                        }
                        return;
                    }

                    int    bytesReadSoFar = (message.m_data.Position / 8);
                    int    hailLen        = message.m_data.LengthBytes - bytesReadSoFar;
                    byte[] hailData       = null;
                    if (hailLen > 0)
                    {
                        hailData = new byte[hailLen];
                        Buffer.BlockCopy(message.m_data.Data, bytesReadSoFar, hailData, 0, hailLen);
                    }

                    if (m_connections.Count >= m_config.m_maxConnections)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                        {
                            NotifyApplication(NetMessageType.ConnectionRejected, "Server full; rejecting connect from " + senderEndpoint, null, senderEndpoint);
                        }
                        return;
                    }

                    // Create connection
                    LogWrite("New connection: " + senderEndpoint);
                    NetConnection conn = new NetConnection(this, senderEndpoint, null, hailData);

                    // Connection approval?
                    if ((m_enabledMessageTypes & NetMessageType.ConnectionApproval) == NetMessageType.ConnectionApproval)
                    {
                        // Ask application if this connection is allowed to proceed
                        IncomingNetMessage app = CreateIncomingMessage();
                        app.m_msgType = NetMessageType.ConnectionApproval;
                        if (hailData != null)
                        {
                            app.m_data.Write(hailData);
                        }
                        app.m_sender    = conn;
                        conn.m_approved = false;
                        lock (m_receivedMessages)
                            m_receivedMessages.Enqueue(app);
                        // Don't add connection; it's done as part of the approval procedure
                        return;
                    }

                    // it's ok
                    AddConnection(now, conn);
                    break;

                case NetSystemType.ConnectionEstablished:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Connection established received from non-connection! " + senderEndpoint, null, senderEndpoint);
                    }
                    return;

                case NetSystemType.Discovery:
                    if (m_config.AnswerDiscoveryRequests)
                    {
                        m_discovery.HandleRequest(message, senderEndpoint);
                    }
                    break;

                case NetSystemType.DiscoveryResponse:
                    if (m_allowOutgoingConnections)
                    {
                        // NetPeer
                        IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint);
                        resMsg.m_senderEndPoint = senderEndpoint;
                        if (resMsg != null)
                        {
                            lock (m_receivedMessages)
                                m_receivedMessages.Enqueue(resMsg);
                        }
                    }
                    break;

                default:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint);
                    }
                    break;
                }
                // done
                return;
            }

            // ok, we have a sender
            if (message.m_type == NetMessageLibraryType.Acknowledge)
            {
                message.m_sender.HandleAckMessage(message);
                return;
            }

            if (message.m_type == NetMessageLibraryType.System)
            {
                //
                // Handle system messages from connected source
                //

                if (payLen < 1)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message; payload length less than 1 byte", null, senderEndpoint);
                    }
                    return;
                }
                NetSystemType sysType = (NetSystemType)message.m_data.ReadByte();
                switch (sysType)
                {
                case NetSystemType.Connect:
                case NetSystemType.ConnectionEstablished:
                case NetSystemType.Ping:
                case NetSystemType.Pong:
                case NetSystemType.Disconnect:
                case NetSystemType.ConnectionRejected:
                case NetSystemType.StringTableAck:
                    message.m_sender.HandleSystemMessage(message, now);
                    break;

                case NetSystemType.ConnectResponse:
                    if (m_allowOutgoingConnections)
                    {
                        message.m_sender.HandleSystemMessage(message, now);
                    }
                    else
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint);
                        }
                    }
                    break;

                case NetSystemType.Discovery:
                    // Allow discovery even if connected
                    if (m_config.AnswerDiscoveryRequests)
                    {
                        m_discovery.HandleRequest(message, senderEndpoint);
                    }
                    break;

                default:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint);
                    }
                    break;
                }
                return;
            }

            message.m_sender.HandleUserMessage(message);
        }
        public bool ReadMessage(
            NetBuffer intoBuffer,
            out NetMessageType type,
            out NetConnection sender,
            out NetworkEndPoint senderEndPoint,
            out NetChannel channel,
            out double localTimeRecv)
        {
            if (intoBuffer == null)
            {
                throw new ArgumentNullException("intoBuffer");
            }

            if (m_receivedMessages.Count < 1)
            {
                type           = NetMessageType.None;
                sender         = null;
                senderEndPoint = NetworkEndPoint.unassigned;
                channel        = NetChannel.Unreliable;
                localTimeRecv  = 0;
                return(false);
            }

            IncomingNetMessage msg = m_receivedMessages.Dequeue();

            if (msg == null)
            {
                type           = NetMessageType.None;
                sender         = null;
                senderEndPoint = NetworkEndPoint.unassigned;
                channel        = NetChannel.Unreliable;
                localTimeRecv  = 0;
                return(false);
            }

            senderEndPoint = msg.m_senderEndPoint;
            sender         = msg.m_sender;
            localTimeRecv  = NetTime.Now;            // TODO: this is a ugly hack, should instead get value when reading from socket. Merging/switching to Speedgren will solve that.
            channel        = msg.m_sequenceChannel;

            // recycle NetMessage object
            var content = msg.m_data;

            msg.m_data = null;
            type       = msg.m_msgType;

            if (content == null)
            {
                intoBuffer.m_bitLength    = 0;
                intoBuffer.m_readPosition = 0;
                return(true);
            }

            // swap content of buffers
            byte[] tmp = intoBuffer.Data;
            intoBuffer.Data = content.Data;
            content.Data    = tmp;

            // set correct values for returning value (ignore the other, it's being recycled anyway)
            intoBuffer.m_bitLength    = content.m_bitLength;
            intoBuffer.m_readPosition = 0;

            // recycle buffer
            RecycleBuffer(content);

            return(true);
        }
        /// <summary>
        /// Called when a message should be released to the application
        /// </summary>
        private void AcceptMessage(IncomingNetMessage msg)
        {
            if (msg.m_type == NetMessageLibraryType.UserFragmented)
            {
                // parse
                int id     = msg.m_data.ReadUInt16();
                int number = (int)msg.m_data.ReadVariableUInt32();                 // 0 to total-1
                int total  = (int)msg.m_data.ReadVariableUInt32();

                int bytePtr    = msg.m_data.Position / 8;
                int payloadLen = msg.m_data.LengthBytes - bytePtr;

                FragmentedMessage fmsg;
                if (!m_fragments.TryGetValue(id, out fmsg))
                {
                    fmsg = new FragmentedMessage();
                    fmsg.TotalFragments    = total;
                    fmsg.FragmentsReceived = 0;
                    fmsg.ChunkSize         = payloadLen;
                    fmsg.Data       = new byte[payloadLen * total];
                    m_fragments[id] = fmsg;
                }

                // insert this fragment
                Array.Copy(
                    msg.m_data.Data,
                    bytePtr,
                    fmsg.Data,
                    number * fmsg.ChunkSize,
                    payloadLen
                    );

                fmsg.BitLength += (msg.m_data.m_bitLength - msg.m_data.Position);
                fmsg.FragmentsReceived++;

                m_owner.LogVerbose("Fragment " + id + " - " + (number + 1) + "/" + total + " received; chunksize " + fmsg.ChunkSize + " this size " + payloadLen, this);

                if (fmsg.FragmentsReceived < fmsg.TotalFragments)
                {
                    // Not yet complete
                    return;
                }

                // Done! Release it as a complete message
                NetBuffer buf = new NetBuffer(false);
                buf.Data = fmsg.Data;

                //int bitLen = (fmsg.TotalFragments - 1) * fmsg.ChunkSize * 8;
                //bitLen += msg.m_data.m_bitLength - (bytePtr * 8);

                buf.m_bitLength = fmsg.BitLength;

                m_fragments.Remove(id);

                // reuse "msg"
                m_owner.LogVerbose("All fragments received; complete length is " + buf.LengthBytes, this);
                msg.m_data = buf;
            }

            // release
            // m_owner.LogVerbose("Accepted " + msg, this);

            // Debug.Assert(msg.m_type == NetMessageLibraryType.User);

            // do custom handling on networking thread
            m_owner.ProcessReceived(msg.m_data);
            m_owner.EnqueueReceivedMessage(msg);
        }
        /*
         * internal void HandleUserMessage(NetMessage msg)
         * {
         *      int seqNr = msg.m_sequenceNumber;
         *      int chanNr = (int)msg.m_sequenceChannel;
         *      bool isDuplicate = false;
         *
         *      int relation = RelateToExpected(seqNr, chanNr, out isDuplicate);
         *
         *      //
         *      // Unreliable
         *      //
         *      if (msg.m_sequenceChannel == NetChannel.Unreliable)
         *      {
         *              // It's all good; add message
         *              if (isDuplicate)
         *              {
         *                      m_statistics.CountDuplicateMessage(msg);
         *                      m_owner.LogVerbose("Rejecting duplicate " + msg, this);
         *              }
         *              else
         *              {
         *                      AcceptMessage(msg);
         *              }
         *              return;
         *      }
         *
         *      //
         *      // Reliable unordered
         *      //
         *      if (msg.m_sequenceChannel == NetChannel.ReliableUnordered)
         *      {
         *              // send acknowledge (even if duplicate)
         *              m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber);
         *
         *              if (isDuplicate)
         *              {
         *                      m_statistics.CountDuplicateMessage(msg);
         *                      m_owner.LogVerbose("Rejecting duplicate " + msg, this);
         *                      return; // reject duplicates
         *              }
         *
         *              // It's good; add message
         *              AcceptMessage(msg);
         *
         *              return;
         *      }
         *
         *      ushort nextSeq = (ushort)(seqNr + 1);
         *
         *      if (chanNr < (int)NetChannel.ReliableInOrder1)
         *      {
         *              //
         *              // Sequenced
         *              //
         *              if (relation < 0)
         *              {
         *                      // late sequenced message
         *                      m_statistics.CountDroppedSequencedMessage();
         *                      m_owner.LogVerbose("Dropping late sequenced " + msg, this);
         *                      return;
         *              }
         *
         *              // It's good; add message
         *              AcceptMessage(msg);
         *
         *              m_nextExpectedSequence[chanNr] = nextSeq;
         *              return;
         *      }
         *      else
         *      {
         *              //
         *              // Ordered
         *              //
         *
         *              // send ack (regardless)
         *              m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber);
         *
         *              if (relation < 0)
         *              {
         *                      // late ordered message
         #if DEBUG
         *                      if (!isDuplicate)
         *                              m_owner.LogWrite("Ouch, weird! Late ordered message that's NOT a duplicate?! seqNr: " + seqNr + " expecting: " + m_nextExpectedSequence[chanNr], this);
         #endif
         *                      // must be duplicate
         *                      m_owner.LogVerbose("Dropping duplicate message " + seqNr, this);
         *                      m_statistics.CountDuplicateMessage(msg);
         *                      return; // rejected; don't advance next expected
         *              }
         *
         *              if (relation > 0)
         *              {
         *                      // early message; withhold ordered
         *                      m_owner.LogVerbose("Withholding " + msg + " (expecting " + m_nextExpectedSequence[chanNr] + ")", this);
         *                      m_withheldMessages.Add(msg);
         *                      return; // return without advancing next expected
         *              }
         *
         *              // It's right on time!
         *              AcceptMessage(msg);
         *
         *              // ordered; release other withheld messages?
         *              bool released = false;
         *              do
         *              {
         *                      released = false;
         *                      foreach (NetMessage wm in m_withheldMessages)
         *                      {
         *                              if ((int)wm.m_sequenceChannel == chanNr && wm.m_sequenceNumber == nextSeq)
         *                              {
         *                                      m_owner.LogVerbose("Releasing withheld message " + wm, this);
         *                                      m_withheldMessages.Remove(wm);
         *                                      AcceptMessage(wm);
         *                                      // no need to set rounds for this message; it was one when first related() and withheld
         *                                      nextSeq++;
         *                                      if (nextSeq >= NetConstants.NumSequenceNumbers)
         *                                              nextSeq -= NetConstants.NumSequenceNumbers;
         *                                      released = true;
         *                                      break;
         *                              }
         *                      }
         *              } while (released);
         *      }
         *
         *      // Common to Sequenced and Ordered
         *
         *      //m_owner.LogVerbose("Setting next expected for " + (NetChannel)chanNr + " to " + nextSeq);
         *      m_nextExpectedSequence[chanNr] = nextSeq;
         *
         *      return;
         * }
         */

        internal void HandleSystemMessage(IncomingNetMessage msg, double timestamp)
        {
            msg.m_data.PositionBits = 0;
            NetSystemType sysType = (NetSystemType)msg.m_data.ReadByte();

            switch (sysType)
            {
            case NetSystemType.Disconnect:
                if (m_status == NetConnectionStatus.Disconnected)
                {
                    return;
                }
                Disconnect(msg.m_data.ReadString(), NetConstants.DisconnectLingerTime, false, false);
                break;

            case NetSystemType.ConnectionRejected:
                string reason = msg.m_data.ReadString();
                m_owner.NotifyApplication(NetMessageType.ConnectionRejected, reason, msg.m_sender, msg.m_senderEndPoint);
                Disconnect(reason, 0.0f, false, true);
                break;

            case NetSystemType.Connect:
            {
                // ConnectReponse must have been losts

                /*if (m_isInitiator) // this might be useful in the future
                 * {
                 *      m_owner.LogWrite("Received connect but we're the initiator...", this);
                 *      return; // ignore
                 * }*/

                if (Status != NetConnectionStatus.Connecting && Status != NetConnectionStatus.Connected)
                {
                    m_owner.LogWrite("Received connect but we're not connecting or connected...", this);
                    return;                                     // ignore if disconnecting
                }

                string appIdent = msg.m_data.ReadString();
                if (appIdent != m_owner.m_config.ApplicationIdentifier)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived,
                                                  "Connect for different application identification received: " + appIdent, null,
                                                  msg.m_senderEndPoint);
                    }
                    return;
                }

                // read random identifier
                var remoteRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize);
                if (!m_owner.Configuration.AllowConnectionToSelf && NetUtility.CompareElements(remoteRndSignature, m_owner.m_localRndSignature))
                {
                    // don't allow self-connect
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                    {
                        m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null,
                                                  msg.m_senderEndPoint);
                    }
                    return;
                }

                int remoteRndSeqNr = msg.m_data.ReadInt32();

                if (m_remoteRndSignature != null)
                {
                    if (!NetUtility.CompareElements(remoteRndSignature, m_remoteRndSignature) || remoteRndSeqNr != m_remoteRndSeqNr)
                    {
                        // this is not the same connection.
                        Disconnect("Not the same connection", 0, false, true);
                        return;
                    }
                }
                else                                 // this might happen if both try and connect at the same time.
                {
                    m_remoteRndSignature = remoteRndSignature;
                    m_remoteRndSeqNr     = remoteRndSeqNr;
                    ResetReliability();
                }

                m_connectLocalSentTime  = msg.m_data.ReadDouble();
                m_connectRemoteRecvTime = timestamp + m_owner.m_localTimeOffset;

                // read hail data
                m_remoteHailData = null;
                int hailBytesCount = (msg.m_data.LengthBits - msg.m_data.PositionBits) / 8;
                if (hailBytesCount > 0)
                {
                    m_remoteHailData = msg.m_data.ReadBytes(hailBytesCount);
                }

                // send response; even if connected
                var responseBuffer = m_owner.GetTempBuffer();
                responseBuffer.Write(m_owner.m_localRndSignature);
                responseBuffer.Write(m_localRndSeqNr);
                responseBuffer.Write(m_remoteRndSignature);
                responseBuffer.Write(m_remoteRndSeqNr);

                double localTimeSent = m_connectLocalSentTime;
                responseBuffer.Write(localTimeSent);
                double remoteTimeRecv = m_connectRemoteRecvTime;
                responseBuffer.Write(remoteTimeRecv);
                double remoteTimeSent = NetTime.Now + m_owner.m_localTimeOffset;
                responseBuffer.Write(remoteTimeSent);

                if (m_localHailData != null)
                {
                    responseBuffer.Write(m_localHailData);
                }

                m_handshakeInitiated = remoteTimeSent;
                SendSingleUnreliableSystemMessage(NetSystemType.ConnectResponse, responseBuffer);
                break;
            }

            case NetSystemType.ConnectResponse:
            {
                /*if (m_isInitiator) // this might be useful in the future
                 * {
                 *      m_owner.LogWrite("Received connect but we're the initiator...", this);
                 *      return; // ignore
                 * }*/

                if (m_status != NetConnectionStatus.Connecting && m_status != NetConnectionStatus.Connected)
                {
                    m_owner.LogWrite("Received connection response but we're not connecting or connected...", this);
                    return;
                }

                var remoteRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize);
                if (!m_owner.Configuration.AllowConnectionToSelf && NetUtility.CompareElements(remoteRndSignature, m_owner.m_localRndSignature))
                {
                    // don't allow self-connect
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                    {
                        m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null,
                                                  msg.m_senderEndPoint);
                    }
                    return;
                }

                int remoteRndSeqNr = msg.m_data.ReadInt32();

                if (m_remoteRndSignature != null)
                {
                    if (!NetUtility.CompareElements(remoteRndSignature, m_remoteRndSignature) || remoteRndSeqNr != m_remoteRndSeqNr)
                    {
                        // this is not the same connection.
                        Disconnect("Not the same connection", 0, false, true);
                        return;
                    }
                }
                else                                 // this might happen if both try and connect at the same time.
                {
                    m_remoteRndSignature = remoteRndSignature;
                    m_remoteRndSeqNr     = remoteRndSeqNr;
                    ResetReliability();
                }

                var myRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize);
                var myRndSeqNr     = msg.m_data.ReadInt32();

                if (!NetUtility.CompareElements(myRndSignature, m_owner.m_localRndSignature) || myRndSeqNr != m_localRndSeqNr)
                {
                    // this is not the same connection.
                    Disconnect("Not the same connection", 0, false, true);
                    return;
                }

                double localTimeSent  = msg.m_data.ReadDouble();
                double remoteTimeRecv = msg.m_data.ReadDouble();
                double remoteTimeSent = msg.m_data.ReadDouble();
                double localTimeRecv  = timestamp + m_owner.m_localTimeOffset;

                // read hail data
                m_remoteHailData = null;
                int numHailBytes = (msg.m_data.LengthBits - msg.m_data.PositionBits) / 8;
                if (numHailBytes > 0)
                {
                    m_remoteHailData = msg.m_data.ReadBytes(numHailBytes);
                }

                // Send connection established
                var responseBuffer = m_owner.GetTempBuffer();
                responseBuffer.Write(m_owner.m_localRndSignature);
                responseBuffer.Write(m_localRndSeqNr);
                responseBuffer.Write(m_remoteRndSignature);
                responseBuffer.Write(m_remoteRndSeqNr);

                double intiatorLocalTimeSent = remoteTimeSent;
                responseBuffer.Write(intiatorLocalTimeSent);
                double intiatorRemoteTimeRecv = localTimeRecv;
                responseBuffer.Write(intiatorRemoteTimeRecv);
                double intiatorRemoteTimeSent = NetTime.Now + m_owner.m_localTimeOffset;
                responseBuffer.Write(intiatorRemoteTimeSent);

                if (m_localHailData != null)
                {
                    responseBuffer.Write(m_localHailData);
                }

                SendSingleUnreliableSystemMessage(NetSystemType.ConnectionEstablished, responseBuffer);

                // send first ping 250ms after connected
                m_lastSentPing = timestamp - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f);
                m_statistics.Reset();
                SetInitialPongEntry(new PongEntry(localTimeSent, remoteTimeRecv, remoteTimeSent, localTimeRecv));
                SetStatus(NetConnectionStatus.Connected, "Connected");
                break;
            }

            case NetSystemType.ConnectionEstablished:
            {
                if (m_status != NetConnectionStatus.Connecting)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived,
                                                  "Received connection response but we're not connecting...", this, msg.m_senderEndPoint);
                    }
                    return;
                }

                var remoteRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize);
                if (!m_owner.Configuration.AllowConnectionToSelf && NetUtility.CompareElements(remoteRndSignature, m_owner.m_localRndSignature))
                {
                    // don't allow self-connect
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                    {
                        m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null,
                                                  msg.m_senderEndPoint);
                    }
                    return;
                }

                int remoteRndSeqNr = msg.m_data.ReadInt32();

                if (m_remoteRndSignature != null)
                {
                    if (!NetUtility.CompareElements(remoteRndSignature, m_remoteRndSignature) || remoteRndSeqNr != m_remoteRndSeqNr)
                    {
                        // this is not the same connection.
                        Disconnect("Not the same connection", 0, false, true);
                        return;
                    }
                }
                else                                 // this might happen if both try and connect at the same time.
                {
                    m_remoteRndSignature = remoteRndSignature;
                    m_remoteRndSeqNr     = remoteRndSeqNr;
                    ResetReliability();
                }

                var myRndSignature = msg.m_data.ReadBytes(NetConstants.SignatureByteSize);
                var myRndSeqNr     = msg.m_data.ReadInt32();

                if (!NetUtility.CompareElements(myRndSignature, m_owner.m_localRndSignature) || myRndSeqNr != m_localRndSeqNr)
                {
                    // this is not the same connection.
                    Disconnect("Not the same connection", 0, false, true);
                    return;
                }

                double localTimeSent  = msg.m_data.ReadDouble();
                double remoteTimeRecv = msg.m_data.ReadDouble();
                double remoteTimeSent = msg.m_data.ReadDouble();
                double localTimeRecv  = timestamp + m_owner.m_localTimeOffset;

                // read hail data
                if (m_remoteHailData == null)
                {
                    int hbc = (msg.m_data.LengthBits - msg.m_data.PositionBits) / 8;
                    if (hbc > 0)
                    {
                        m_remoteHailData = msg.m_data.ReadBytes(hbc);
                    }
                }

                // send first ping 100-350ms after connected
                m_lastSentPing = timestamp - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f);
                m_statistics.Reset();
                SetInitialPongEntry(new PongEntry(localTimeSent, remoteTimeRecv, remoteTimeSent, localTimeRecv));
                SetStatus(NetConnectionStatus.Connected, "Connected");
                break;
            }

            case NetSystemType.Ping:
                // also accepted as ConnectionEstablished
                if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting)
                {
                    m_owner.LogWrite("Received ping; interpreted as ConnectionEstablished", this);
                    m_statistics.Reset();
                    SetInitialPongEntryApprox(timestamp - m_handshakeInitiated);
                    SetStatus(NetConnectionStatus.Connected, "Connected");
                }

                if (m_status != NetConnectionStatus.Connected)
                {
                    m_owner.LogWrite("Received ping but we're not connected...", this);
                    if (m_status == NetConnectionStatus.Disconnected)
                    {
                        // this might cause a issue (especially if both are trying to connect at the same time).
                        Disconnect("We're not connected", 0, true, true);
                    }
                    return;
                }

                ReceivedPing(msg, timestamp + m_owner.m_localTimeOffset);
                break;

            case NetSystemType.Pong:
                ReceivedPong(msg, timestamp + m_owner.m_localTimeOffset);
                break;

            case NetSystemType.StringTableAck:
                ushort val = msg.m_data.ReadUInt16();
                StringTableAcknowledgeReceived(val);
                break;

            default:
                m_owner.LogWrite("Undefined behavior in NetConnection for system message " + sysType, this);
                break;
            }
        }
Example #22
0
        internal void NotifyApplication(NetMessageType tp, NetBuffer buffer, NetConnection conn, IPEndPoint ep)
        {
            IncomingNetMessage msg = new IncomingNetMessage();
            msg.m_data = buffer;
            msg.m_msgType = tp;
            msg.m_sender = conn;
            msg.m_senderEndPoint = ep;

            lock (m_receivedMessages)
                m_receivedMessages.Enqueue(msg);
        }
Example #23
0
 internal abstract void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint);
Example #24
0
        /// <summary>
        /// Returns true if message should be dropped
        /// </summary>
        internal bool HandleNATIntroduction(IncomingNetMessage message)
        {
            if (message.m_type == NetMessageLibraryType.System)
            {
                if (message.m_data.LengthBytes > 4 && message.m_data.PeekByte() == (byte)NetSystemType.NatIntroduction)
                {
                    if ((m_enabledMessageTypes & NetMessageType.NATIntroduction) != NetMessageType.NATIntroduction)
                        return true; // drop
                    try
                    {
                        message.m_data.ReadByte(); // step past system type byte
                        IPEndPoint presented = message.m_data.ReadIPEndPoint();

                        LogVerbose("Received NATIntroduction to " + presented + "; sending punching ping...");

                        double now = NetTime.Now;
                        NetConnection.SendPing(this, presented, now);

                        if (m_holePunches == null)
                            m_holePunches = new List<IPEndPoint>();

                        for (int i = 0; i < 5; i++)
                            m_holePunches.Add(new IPEndPoint(presented.Address, presented.Port));

                        NetBuffer info = CreateBuffer();
                        info.Write(presented);
                        NotifyApplication(NetMessageType.NATIntroduction, info, message.m_sender, message.m_senderEndPoint);
                        return true;
                    }
                    catch (Exception ex)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Bad NAT introduction message received: " + ex.Message, message.m_sender, message.m_senderEndPoint);
                        return true;
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// Process a user message
        /// </summary>
        internal void HandleUserMessage(IncomingNetMessage msg, double now)
        {
            // also accepted as ConnectionEstablished
            if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting)
            {
                m_owner.LogWrite("Received user message; interpreted as ConnectionEstablished", this);
                m_statistics.Reset();
                SetInitialPongEntryApprox(now - m_handshakeInitiated);
                SetStatus(NetConnectionStatus.Connected, "Connected");
            }

            if (m_status != NetConnectionStatus.Connected && m_status != NetConnectionStatus.Disconnecting)
            {
                m_owner.LogWrite("Received user message but we're not connected...", this);
                //Disconnect("We're not connected", 0, true, true); // we can't send disconnect because then we fail the redirect test for a reason that needs to be investigated.
                return;
            }

            //
            // Unreliable
            //
            if (msg.m_sequenceChannel == NetChannel.Unreliable)
            {
                AcceptMessage(msg);
                return;
            }

            //
            // Unreliable Sequenced
            //
            if (msg.m_sequenceChannel >= NetChannel.UnreliableInOrder1 && msg.m_sequenceChannel <= NetChannel.UnreliableInOrder15)
            {
                // relate to expected
                int seqChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.UnreliableInOrder1;
                int sdiff     = Relate(msg.m_sequenceNumber, m_nextExpectedSequenced[seqChanNr]);

                if (sdiff < 0)
                {
                    // Reject late sequenced message
                    m_owner.LogVerbose("Rejecting late sequenced " + msg);
                    m_statistics.CountDroppedSequencedMessage();
                    return;
                }
                AcceptMessage(msg);
                int nextExpected = msg.m_sequenceNumber + 1;
                if (nextExpected > NetConstants.NumSequenceNumbers)
                {
                    nextExpected = 0;
                }
                m_nextExpectedSequenced[seqChanNr] = nextExpected;
                return;
            }

            //
            // Reliable and ReliableOrdered
            //

            // Send ack, regardless of anything
            m_acknowledgesToSend.Enqueue(((int)msg.m_sequenceChannel << 16) | msg.m_sequenceNumber);

            // relate to all received up to
            int relChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.ReliableUnordered;
            int arut      = m_allReliableReceivedUpTo[relChanNr];
            int diff      = Relate(msg.m_sequenceNumber, arut);

            if (diff < 0)
            {
                // Reject duplicate
                m_statistics.CountDuplicateMessage(msg);
                m_owner.LogVerbose("Rejecting(1) duplicate reliable " + msg, this);
                return;
            }

            bool isOrdered = (msg.m_sequenceChannel >= NetChannel.ReliableInOrder1);

            if (arut == msg.m_sequenceNumber)
            {
                // Right on time
                AcceptMessage(msg);
                PostAcceptReliableMessage(msg, arut);
                return;
            }

            // get bools list we must check
            BitArray recList = m_reliableReceived[relChanNr];

            if (recList == null)
            {
                recList = new BitArray(NetConstants.NumSequenceNumbers);
                m_reliableReceived[relChanNr] = recList;
            }

            if (recList[msg.m_sequenceNumber])
            {
                // Reject duplicate
                m_statistics.CountDuplicateMessage(msg);
                m_owner.LogVerbose("Rejecting(2) duplicate reliable " + msg, this);
                return;
            }

            // It's an early reliable message
            if (m_reliableReceived[relChanNr] == null)
            {
                m_reliableReceived[relChanNr] = new BitArray(NetConstants.NumSequenceNumbers);
            }
            m_reliableReceived[relChanNr][msg.m_sequenceNumber] = true;

            if (!isOrdered)
            {
                AcceptMessage(msg);
                return;
            }

            // Early ordered message; withhold
            List <IncomingNetMessage> wmlist = m_withheldMessages[relChanNr];

            if (wmlist == null)
            {
                wmlist = new List <IncomingNetMessage>();
                m_withheldMessages[relChanNr] = wmlist;
            }

            m_owner.LogVerbose("Withholding " + msg + " (waiting for " + arut + ")", this);
            wmlist.Add(msg);
            return;
        }
        /// <summary>
        /// Process a user message
        /// </summary>
        internal void HandleUserMessage(IncomingNetMessage msg)
        {
            #if DEBUG
            if (System.Threading.Thread.CurrentThread != m_owner.m_heartbeatThread)
                throw new Exception("Threading error; should be heartbeat thread. Please check callstack!");
            #endif

            //
            // Unreliable
            //
            if (msg.m_sequenceChannel == NetChannel.Unreliable)
            {
                AcceptMessage(msg);
                return;
            }

            //
            // Sequenced
            //
            if (msg.m_sequenceChannel >= NetChannel.UnreliableInOrder1 && msg.m_sequenceChannel <= NetChannel.UnreliableInOrder15)
            {
                // relate to expected
                int seqChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.UnreliableInOrder1;
                int sdiff = Relate(msg.m_sequenceNumber, m_nextExpectedSequenced[seqChanNr]);

                if (sdiff < 0)
                {
                    // Reject late sequenced message
                    m_owner.LogVerbose("Rejecting late sequenced " + msg);
                    m_statistics.CountDroppedSequencedMessage();
                    return;
                }
                AcceptMessage(msg);
                int nextExpected = msg.m_sequenceNumber + 1;
                if (nextExpected > NetConstants.NumSequenceNumbers)
                    nextExpected = 0;
                m_nextExpectedSequenced[seqChanNr] = nextExpected;
                return;
            }

            //
            // Reliable and ReliableOrdered
            //

            // Send ack, regardless of anything
            m_acknowledgesToSend.Enqueue(((int)msg.m_sequenceChannel << 16) | msg.m_sequenceNumber);

            // relate to all received up to
            int relChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.ReliableUnordered;
            int arut = m_allReliableReceivedUpTo[relChanNr];
            int diff = Relate(msg.m_sequenceNumber, arut);

            if (diff < 0)
            {
                // Reject duplicate
                m_statistics.CountDuplicateMessage(msg);
                m_owner.LogVerbose("Rejecting(1) duplicate reliable " + msg, this);
                return;
            }

            bool isOrdered = (msg.m_sequenceChannel >= NetChannel.ReliableInOrder1);

            if (arut == msg.m_sequenceNumber)
            {
                // Right on time
                AcceptMessage(msg);
                PostAcceptReliableMessage(msg, arut);
                return;
            }

            // get bools list we must check
            bool[] recList = m_reliableReceived[relChanNr];
            if (recList == null)
            {
                recList = new bool[NetConstants.NumSequenceNumbers];
                m_reliableReceived[relChanNr] = recList;
            }

            if (recList[msg.m_sequenceNumber])
            {
                // Reject duplicate
                m_statistics.CountDuplicateMessage(msg);
                m_owner.LogVerbose("Rejecting(2) duplicate reliable " + msg, this);
                return;
            }

            // It's an early reliable message
            if (m_reliableReceived[relChanNr] == null)
                m_reliableReceived[relChanNr] = new bool[NetConstants.NumSequenceNumbers];
            m_reliableReceived[relChanNr][msg.m_sequenceNumber] = true;

            if (!isOrdered)
            {
                AcceptMessage(msg);
                return;
            }

            // Early ordered message; withhold
            List<IncomingNetMessage> wmlist = m_withheldMessages[relChanNr];
            if (wmlist == null)
            {
                wmlist = new List<IncomingNetMessage>();
                m_withheldMessages[relChanNr] = wmlist;
            }

            m_owner.LogVerbose("Withholding " + msg + " (waiting for " + arut + ")", this);
            wmlist.Add(msg);
            return;
        }
        internal void HandleAckMessage(double now, IncomingNetMessage ackMessage)
        {
            int len = ackMessage.m_data.LengthBytes;

            if ((len % 3) != 0)
            {
                if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                {
                    m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; length must be multiple of 3; it's " + len, this, ackMessage.m_senderEndPoint);
                }
                return;
            }

            for (int i = 0; i < len; i += 3)             //for each channel + seq nbr in ACK
            {
                NetChannel chan  = (NetChannel)ackMessage.m_data.ReadByte();
                int        seqNr = ackMessage.m_data.ReadUInt16();

                // LogWrite("Acknowledgement received: " + chan + "|" + seqNr);
                m_statistics.CountAcknowledgesReceived(1);

                // remove saved message
                int relChanNr = (int)chan - (int)NetChannel.ReliableUnordered;
                if (relChanNr < 0)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; indicated netchannel " + chan, this, ackMessage.m_senderEndPoint);
                    }
                    continue;
                }

                List <OutgoingNetMessage> list = m_storedMessages[relChanNr];
                if (list != null)
                {
                    int cnt = list.Count;
                    if (cnt > 0)
                    {
                        for (int j = 0; j < cnt; j++)                         //for each stored message on channel
                        {
                            OutgoingNetMessage msg = list[j];
                            if (msg.m_sequenceNumber == seqNr)                             //find correct message
                            {
                                // if (msg.m_numSent >= 10) UnityEngine.Debug.Log(now + ": Ack for " + msg.m_numSent + ": " + NetUtility.BytesToHex(msg.m_data.ToArray()));

                                //LogWrite("Removed stored message: " + msg);
                                list.RemoveAt(j);

                                // reduce estimated amount of packets on wire
                                //CongestionCountAck(msg.m_packetNumber);

                                // fire receipt
                                if (msg.m_receiptData != null)
                                {
                                    m_owner.LogVerbose("Got ack, removed from storage: " + msg + " firing receipt; " + msg.m_receiptData, this);
                                    m_owner.FireReceipt(this, msg.m_receiptData);
                                }
                                else
                                {
                                    m_owner.LogVerbose("Got ack, removed from storage: " + msg, this);
                                }

                                // recycle
                                msg.m_data.m_refCount--;
                                if (msg.m_data.m_refCount <= 0)
                                {
                                    m_owner.RecycleBuffer(msg.m_data);                                     // time to recycle buffer
                                }
                                msg.m_data = null;
                                //m_owner.m_messagePool.Push(msg);

#if !NO_NAK
                                if (j > 0)
                                {
                                    int k;
                                    for (k = 0; k < j; k++)                                     //for each message stored prior to the one matching seq nbr
                                    {
                                        var m = list[k];
                                        if (m.m_sequenceNumber > seqNr)
                                        {
                                            break;
                                        }

                                        // Re-enqueue message in unsent list
                                        m_owner.LogVerbose("Implicit NAK Resending " + m +
                                                           " now: " + NetTime.NowInMillis +
                                                           " nextResend: " + NetTime.ToMillis(m.m_nextResend), this);
                                        m_statistics.CountMessageResent(m.m_type);
                                        m_unsentMessages.Enqueue(m);
                                    }

                                    list.RemoveRange(0, k);
                                }
#endif

                                break;                                 //exit stored message loop since this was the message corresponding to seq nbr
                                //now returning to next sequence number in ACK packet
                            }
                        }
                    }
                }
            }

            // recycle
            NetBuffer rb = ackMessage.m_data;
            rb.m_refCount     = 0;         // ack messages can't be used by more than one message
            ackMessage.m_data = null;

            m_owner.RecycleBuffer(rb);
            //m_owner.m_messagePool.Push(ackMessage);
        }
Example #28
0
		/// <summary>
		/// Notify application that a connection changed status
		/// </summary>
		internal void NotifyStatusChange(NetConnection connection, string reason)
		{
			if ((m_enabledMessageTypes & NetMessageType.StatusChanged) != NetMessageType.StatusChanged)
				return; // disabled
			
			//NotifyApplication(NetMessageType.StatusChanged, reason, connection);
			NetBuffer buffer = CreateBuffer(reason.Length + 2);
			buffer.Write(reason);
			buffer.Write((byte)connection.Status);

			IncomingNetMessage msg = new IncomingNetMessage();
			msg.m_data = buffer;
			msg.m_msgType = NetMessageType.StatusChanged;
			msg.m_sender = connection;
			msg.m_senderEndPoint = null;

			EnqueueReceivedMessage(msg);
		}
Example #29
0
        internal bool VerifyIdentifiers(
            IncomingNetMessage message,
            IPEndPoint endPoint,
            out ushort number
            )
        {
            number = 0;
            int payLen = message.m_data.LengthBytes;
            if (payLen < 13)
            {
                if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Discovery message received from " + endPoint, null, message.m_senderEndPoint);
                return false;
            }

            // check app identifier
            string appIdent2 = message.m_data.ReadString();
            if (appIdent2 != m_netBase.m_config.ApplicationIdentifier)
            {
                if ((m_netBase.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    m_netBase.NotifyApplication(NetMessageType.BadMessageReceived, "Discovery for different application identification received: " + appIdent2, null, message.m_senderEndPoint);
                return false;
            }

            // check netbase identifier
            byte[] nbid = message.m_data.ReadBytes(m_netBase.m_randomIdentifier.Length);
            if (NetUtility.CompareElements(nbid, m_netBase.m_randomIdentifier))
                return false; // don't respond to your own discovery request

            // retrieve number
            number = message.m_data.ReadUInt16();

            // it's ok
            return true;
        }
Example #30
0
 internal abstract void HandleReceivedMessage(IncomingNetMessage message, IPEndPoint senderEndpoint);
Example #31
0
        /// <summary>
        /// Returns a NetMessage to return to application; or null if nothing
        /// </summary>
        internal IncomingNetMessage HandleResponse(
            IncomingNetMessage message,
            IPEndPoint endPoint
            )
        {
            if ((m_netBase.m_enabledMessageTypes & NetMessageType.ServerDiscovered) != NetMessageType.ServerDiscovered)
                return null; // disabled

            if (message.m_data == null || m_requests == null)
                return null;

            ushort number = message.m_data.ReadUInt16();

            // find corresponding request
            NetDiscoveryRequest found = null;
            foreach (NetDiscoveryRequest request in m_requests)
            {
                if (request.Number == number)
                {
                    found = request;
                    break;
                }
            }

            if (found == null)
            {
                m_netBase.LogVerbose("Received discovery response to request " + number + " - unknown/old request!");
                return null; // Timed out request or not found
            }

            if (found.HasDiscovered(endPoint))
            {
                m_netBase.LogVerbose("Received discovery response to request " + number + " - previously known response!");
                return null; // Already discovered in this request, else stored it
            }

            m_netBase.LogVerbose("Received discovery response to request " + number + " - passing on to app...");

            IncomingNetMessage resMsg = m_netBase.CreateIncomingMessage();
            resMsg.m_msgType = NetMessageType.ServerDiscovered;

            // write sender, assume ipv4
            resMsg.m_data.Write(endPoint);

            return resMsg;
        }
Example #32
0
        internal void HandleAckMessage(IncomingNetMessage ackMessage)
        {
            int len = ackMessage.m_data.LengthBytes;

            if ((len % 3) != 0)
            {
                if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                {
                    m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; length must be multiple of 3; it's " + len, this, ackMessage.m_senderEndPoint);
                }
                return;
            }

            for (int i = 0; i < len; i += 3)
            {
                NetChannel chan  = (NetChannel)ackMessage.m_data.ReadByte();
                int        seqNr = ackMessage.m_data.ReadUInt16();

                // LogWrite("Acknowledgement received: " + chan + "|" + seqNr);
                m_statistics.CountAcknowledgesReceived(1);

                // remove saved message
                int chanIdx = (int)chan - (int)NetChannel.ReliableUnordered;
                if (chanIdx < 0)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; indicated netchannel " + chan, this, ackMessage.m_senderEndPoint);
                    }
                    continue;
                }

                List <OutgoingNetMessage> list = m_storedMessages[chanIdx];
                if (list != null)
                {
                    int cnt = list.Count;
                    if (cnt > 0)
                    {
                        for (int o = 0; o < cnt; o++)
                        {
                            OutgoingNetMessage msg = list[o];
                            if (msg.m_sequenceNumber == seqNr)
                            {
                                //LogWrite("Removed stored message: " + msg);
                                list.RemoveAt(o);

                                // reduce estimated amount of packets on wire
                                //CongestionCountAck(msg.m_packetNumber);

                                // fire receipt
                                if (msg.m_receiptData != null)
                                {
                                    m_owner.LogVerbose("Got ack, removed from storage: " + msg + " firing receipt; " + msg.m_receiptData, this);
                                    m_owner.FireReceipt(this, msg.m_receiptData);
                                }
                                else
                                {
                                    m_owner.LogVerbose("Got ack, removed from storage: " + msg, this);
                                }

                                // recycle
                                msg.m_data.m_refCount--;
                                if (msg.m_data.m_refCount <= 0)
                                {
                                    m_owner.RecycleBuffer(msg.m_data);                                     // time to recycle buffer
                                }
                                msg.m_data = null;
                                //m_owner.m_messagePool.Push(msg);

                                break;
                            }
                        }
                    }
                }
            }

            // recycle
            NetBuffer rb = ackMessage.m_data;

            rb.m_refCount     = 0;         // ack messages can't be used by more than one message
            ackMessage.m_data = null;

            m_owner.RecycleBuffer(rb);
            //m_owner.m_messagePool.Push(ackMessage);
        }
        /*
         * internal void HandleUserMessage(NetMessage msg)
         * {
         *      int seqNr = msg.m_sequenceNumber;
         *      int chanNr = (int)msg.m_sequenceChannel;
         *      bool isDuplicate = false;
         *
         *      int relation = RelateToExpected(seqNr, chanNr, out isDuplicate);
         *
         *      //
         *      // Unreliable
         *      //
         *      if (msg.m_sequenceChannel == NetChannel.Unreliable)
         *      {
         *              // It's all good; add message
         *              if (isDuplicate)
         *              {
         *                      m_statistics.CountDuplicateMessage(msg);
         *                      m_owner.LogVerbose("Rejecting duplicate " + msg, this);
         *              }
         *              else
         *              {
         *                      AcceptMessage(msg);
         *              }
         *              return;
         *      }
         *
         *      //
         *      // Reliable unordered
         *      //
         *      if (msg.m_sequenceChannel == NetChannel.ReliableUnordered)
         *      {
         *              // send acknowledge (even if duplicate)
         *              m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber);
         *
         *              if (isDuplicate)
         *              {
         *                      m_statistics.CountDuplicateMessage(msg);
         *                      m_owner.LogVerbose("Rejecting duplicate " + msg, this);
         *                      return; // reject duplicates
         *              }
         *
         *              // It's good; add message
         *              AcceptMessage(msg);
         *
         *              return;
         *      }
         *
         *      ushort nextSeq = (ushort)(seqNr + 1);
         *
         *      if (chanNr < (int)NetChannel.ReliableInOrder1)
         *      {
         *              //
         *              // Sequenced
         *              //
         *              if (relation < 0)
         *              {
         *                      // late sequenced message
         *                      m_statistics.CountDroppedSequencedMessage();
         *                      m_owner.LogVerbose("Dropping late sequenced " + msg, this);
         *                      return;
         *              }
         *
         *              // It's good; add message
         *              AcceptMessage(msg);
         *
         *              m_nextExpectedSequence[chanNr] = nextSeq;
         *              return;
         *      }
         *      else
         *      {
         *              //
         *              // Ordered
         *              //
         *
         *              // send ack (regardless)
         *              m_acknowledgesToSend.Enqueue((chanNr << 16) | msg.m_sequenceNumber);
         *
         *              if (relation < 0)
         *              {
         *                      // late ordered message
         #if DEBUG
         *                      if (!isDuplicate)
         *                              m_owner.LogWrite("Ouch, weird! Late ordered message that's NOT a duplicate?! seqNr: " + seqNr + " expecting: " + m_nextExpectedSequence[chanNr], this);
         #endif
         *                      // must be duplicate
         *                      m_owner.LogVerbose("Dropping duplicate message " + seqNr, this);
         *                      m_statistics.CountDuplicateMessage(msg);
         *                      return; // rejected; don't advance next expected
         *              }
         *
         *              if (relation > 0)
         *              {
         *                      // early message; withhold ordered
         *                      m_owner.LogVerbose("Withholding " + msg + " (expecting " + m_nextExpectedSequence[chanNr] + ")", this);
         *                      m_withheldMessages.Add(msg);
         *                      return; // return without advancing next expected
         *              }
         *
         *              // It's right on time!
         *              AcceptMessage(msg);
         *
         *              // ordered; release other withheld messages?
         *              bool released = false;
         *              do
         *              {
         *                      released = false;
         *                      foreach (NetMessage wm in m_withheldMessages)
         *                      {
         *                              if ((int)wm.m_sequenceChannel == chanNr && wm.m_sequenceNumber == nextSeq)
         *                              {
         *                                      m_owner.LogVerbose("Releasing withheld message " + wm, this);
         *                                      m_withheldMessages.Remove(wm);
         *                                      AcceptMessage(wm);
         *                                      // no need to set rounds for this message; it was one when first related() and withheld
         *                                      nextSeq++;
         *                                      if (nextSeq >= NetConstants.NumSequenceNumbers)
         *                                              nextSeq -= NetConstants.NumSequenceNumbers;
         *                                      released = true;
         *                                      break;
         *                              }
         *                      }
         *              } while (released);
         *      }
         *
         *      // Common to Sequenced and Ordered
         *
         *      //m_owner.LogVerbose("Setting next expected for " + (NetChannel)chanNr + " to " + nextSeq);
         *      m_nextExpectedSequence[chanNr] = nextSeq;
         *
         *      return;
         * }
         */

        internal void HandleSystemMessage(IncomingNetMessage msg, double now)
        {
            msg.m_data.Position = 0;
            NetSystemType      sysType  = (NetSystemType)msg.m_data.ReadByte();
            OutgoingNetMessage response = null;

            switch (sysType)
            {
            case NetSystemType.Disconnect:
                if (m_status == NetConnectionStatus.Disconnected)
                {
                    return;
                }
                Disconnect(msg.m_data.ReadString(), 0.75f + ((float)m_currentAvgRoundtrip * 4), false, false);
                break;

            case NetSystemType.ConnectionRejected:
                string reason = msg.m_data.ReadString();
                m_owner.NotifyApplication(NetMessageType.ConnectionRejected, reason, msg.m_sender, msg.m_senderEndPoint);
                Disconnect(reason, 0.0f, false, true);
                break;

            case NetSystemType.Connect:

                // ConnectReponse must have been losts

                string appIdent = msg.m_data.ReadString();
                if (appIdent != m_owner.m_config.ApplicationIdentifier)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Connect for different application identification received: " + appIdent, null, msg.m_senderEndPoint);
                    }
                    return;
                }

                // read random identifer
                byte[] rnd = msg.m_data.ReadBytes(8);
                if (NetUtility.CompareElements(rnd, m_owner.m_randomIdentifier))
                {
                    // don't allow self-connect
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                    {
                        m_owner.NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, msg.m_senderEndPoint);
                    }
                    return;
                }

                // read hail data
                m_remoteHailData = null;
                int hailBytesCount = (msg.m_data.LengthBits - msg.m_data.Position) / 8;
                if (hailBytesCount > 0)
                {
                    m_remoteHailData = msg.m_data.ReadBytes(hailBytesCount);
                }

                // finalize disconnect if it's in process
                if (m_status == NetConnectionStatus.Disconnecting)
                {
                    FinalizeDisconnect();
                }

                // send response; even if connected
                response = m_owner.CreateSystemMessage(NetSystemType.ConnectResponse);
                if (m_localHailData != null)
                {
                    response.m_data.Write(m_localHailData);
                }
                m_unsentMessages.Enqueue(response);

                break;

            case NetSystemType.ConnectResponse:
                if (m_status != NetConnectionStatus.Connecting && m_status != NetConnectionStatus.Connected)
                {
                    m_owner.LogWrite("Received connection response but we're not connecting...", this);
                    return;
                }

                // read hail data
                m_remoteHailData = null;
                int numHailBytes = (msg.m_data.LengthBits - msg.m_data.Position) / 8;
                if (numHailBytes > 0)
                {
                    m_remoteHailData = msg.m_data.ReadBytes(numHailBytes);
                }

                // Send connectionestablished
                response = m_owner.CreateSystemMessage(NetSystemType.ConnectionEstablished);
                if (m_localHailData != null)
                {
                    response.m_data.Write(m_localHailData);
                }
                m_unsentMessages.Enqueue(response);

                // send first ping 250ms after connected
                m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f);
                m_statistics.Reset();
                SetInitialAveragePing(now - m_handshakeInitiated);
                SetStatus(NetConnectionStatus.Connected, "Connected");
                break;

            case NetSystemType.ConnectionEstablished:
                if (m_status != NetConnectionStatus.Connecting)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Received connection response but we're not connecting...", this, msg.m_senderEndPoint);
                    }
                    return;
                }

                // read hail data
                if (m_remoteHailData == null)
                {
                    int hbc = (msg.m_data.LengthBits - msg.m_data.Position) / 8;
                    if (hbc > 0)
                    {
                        m_remoteHailData = msg.m_data.ReadBytes(hbc);
                    }
                }

                // send first ping 100-350ms after connected
                m_lastSentPing = now - m_owner.Configuration.PingFrequency + 0.1 + (NetRandom.Instance.NextFloat() * 0.25f);
                m_statistics.Reset();
                SetInitialAveragePing(now - m_handshakeInitiated);
                SetStatus(NetConnectionStatus.Connected, "Connected");
                break;

            case NetSystemType.Ping:
                // also accepted as ConnectionEstablished
                if (m_isInitiator == false && m_status == NetConnectionStatus.Connecting)
                {
                    m_owner.LogWrite("Received ping; interpreted as ConnectionEstablished", this);
                    m_statistics.Reset();
                    SetInitialAveragePing(now - m_handshakeInitiated);
                    SetStatus(NetConnectionStatus.Connected, "Connected");
                }

                //LogWrite("Received ping; sending pong...");
                SendPong(m_owner, m_remoteEndPoint, now);
                break;

            case NetSystemType.Pong:
                double twoWayLatency = now - m_lastSentPing;
                if (twoWayLatency < 0)
                {
                    break;
                }
                ReceivedPong(twoWayLatency, msg);
                break;

            case NetSystemType.StringTableAck:
                ushort val = msg.m_data.ReadUInt16();
                StringTableAcknowledgeReceived(val);
                break;

            default:
                m_owner.LogWrite("Undefined behaviour in NetConnection for system message " + sysType, this);
                break;
            }
        }
 internal abstract void HandleReceivedMessage(IncomingNetMessage message, NetworkEndPoint senderEndpoint, double timestamp);
Example #35
0
        /// <summary>
        /// Reads all packets and create messages
        /// </summary>
        protected void BaseHeartbeat(double now)
        {
            if (!m_isBound)
            {
                return;
            }

            // discovery
            m_discovery.Heartbeat(now);

            // hole punching
            if (m_holePunches != null)
            {
                if (now > m_lastHolePunch + NetConstants.HolePunchingFrequency)
                {
                    if (m_holePunches.Count <= 0)
                    {
                        m_holePunches = null;
                    }
                    else
                    {
                        IPEndPoint dest = m_holePunches[0];
                        m_holePunches.RemoveAt(0);
                        NotifyApplication(NetMessageType.DebugMessage, "Sending hole punch to " + dest, null);
                        NetConnection.SendPing(this, dest, now);
                        if (m_holePunches.Count < 1)
                        {
                            m_holePunches = null;
                        }
                        m_lastHolePunch = now;
                    }
                }
            }

            // Send queued system messages
            if (m_susmQueue.Count > 0)
            {
                lock (m_susmQueue)
                {
                    while (m_susmQueue.Count > 0)
                    {
                        SUSystemMessage su = m_susmQueue.Dequeue();
                        SendSingleUnreliableSystemMessage(su.Type, su.Data, su.Destination, su.UseBroadcast);
                    }
                }
            }

            // Send out-of-band messages
            if (m_unsentOutOfBandMessages.Count > 0)
            {
                lock (m_unsentOutOfBandMessages)
                {
                    while (m_unsentOutOfBandMessages.Count > 0)
                    {
                        NetBuffer  buf = m_unsentOutOfBandMessages.Dequeue();
                        IPEndPoint ep  = m_unsentOutOfBandRecipients.Dequeue();
                        DoSendOutOfBandMessage(buf, ep);
                    }
                }
            }

            try
            {
#if DEBUG
                SendDelayedPackets(now);
#endif

                while (true)
                {
                    if (m_socket == null || m_socket.Available < 1)
                    {
                        return;
                    }
                    m_receiveBuffer.Reset();

                    int bytesReceived = 0;
                    try
                    {
                        bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer.Data, 0, m_receiveBuffer.Data.Length, SocketFlags.None, ref m_senderRemote);
                    }
                    catch (SocketException)
                    {
                        // no good response to this yet
                        return;
                    }
                    if (bytesReceived < 1)
                    {
                        return;
                    }
                    if (bytesReceived > 0)
                    {
                        m_statistics.CountPacketReceived(bytesReceived);
                    }
                    m_receiveBuffer.LengthBits = bytesReceived * 8;

                    //LogVerbose("Read packet: " + bytesReceived + " bytes");

                    IPEndPoint ipsender = (IPEndPoint)m_senderRemote;

                    NetConnection sender = GetConnection(ipsender);
                    if (sender != null)
                    {
                        sender.m_statistics.CountPacketReceived(bytesReceived, now);
                    }

                    // create messages from packet
                    while (m_receiveBuffer.Position < m_receiveBuffer.LengthBits)
                    {
                        int beginPosition = m_receiveBuffer.Position;

                        // read message header
                        IncomingNetMessage msg = CreateIncomingMessage();
                        msg.m_sender = sender;
                        msg.ReadFrom(m_receiveBuffer, ipsender);

                        // statistics
                        if (sender != null)
                        {
                            sender.m_statistics.CountMessageReceived(msg.m_type, msg.m_sequenceChannel, (m_receiveBuffer.Position - beginPosition) / 8, now);
                        }

                        // handle message
                        HandleReceivedMessage(msg, ipsender);
                    }
                }
            }
            catch (SocketException sex)
            {
                if (sex.ErrorCode == 10054)
                {
                    // forcibly closed; but m_senderRemote is unreliable, we can't trust it!
                    //NetConnection conn = GetConnection((IPEndPoint)m_senderRemote);
                    //HandleConnectionForciblyClosed(conn, sex);
                    return;
                }
            }
            catch (Exception ex)
            {
                throw new NetException("ReadPacket() exception", ex);
            }
        }
Example #36
0
        /*
         * /// <summary>
         * /// Read any received message in any connection queue
         * /// </summary>
         * public NetBuffer ReadMessage(out NetConnection sender)
         * {
         *      if (m_receivedMessages.Count < 1)
         *      {
         *              sender = null;
         *              return null;
         *      }
         *
         *      NetMessage msg = m_receivedMessages.Dequeue();
         *      sender = msg.m_sender;
         *
         *      NetBuffer retval = msg.m_data;
         *      msg.m_data = null;
         *      m_messagePool.Push(msg);
         *
         *      Debug.Assert(retval.Position == 0);
         *
         *      return retval;
         * }
         */

        /// <summary>
        /// Read any received message in any connection queue
        /// </summary>
        public bool ReadMessage(
            NetBuffer intoBuffer,
            IList <NetConnection> onlyFor,
            bool includeNullConnectionMessages,
            out NetMessageType type,
            out NetConnection sender)
        {
            if (m_receivedMessages.Count < 1)
            {
                sender = null;
                type   = NetMessageType.None;
                return(false);
            }

            IncomingNetMessage msg = null;

            lock (m_receivedMessages)
            {
                int sz = m_receivedMessages.Count;
                for (int i = 0; i < sz; i++)
                {
                    msg = m_receivedMessages.Peek(i);
                    if (msg != null)
                    {
                        if ((msg.m_sender == null && includeNullConnectionMessages) ||
                            onlyFor.Contains(msg.m_sender))
                        {
                            m_receivedMessages.Dequeue(i);
                            break;
                        }
                        msg = null;
                    }
                }
            }

            if (msg == null)
            {
                sender = null;
                type   = NetMessageType.None;
                return(false);
            }

            sender = msg.m_sender;

            // recycle NetMessage object
            NetBuffer content = msg.m_data;

            msg.m_data = null;
            type       = msg.m_msgType;

            // m_messagePool.Push(msg);

            Debug.Assert(content.Position == 0);

            // swap content of buffers
            byte[] tmp = intoBuffer.Data;
            intoBuffer.Data = content.Data;
            content.Data    = tmp;

            // set correct values for returning value (ignore the other, it's being recycled anyway)
            intoBuffer.m_bitLength    = content.m_bitLength;
            intoBuffer.m_readPosition = 0;

            // recycle NetBuffer object (incl. old intoBuffer byte array)
            RecycleBuffer(content);

            return(true);
        }
        internal override void HandleReceivedMessage(IncomingNetMessage message, NetworkEndPoint senderEndpoint, double timestamp)
        {
            double now = NetTime.Now;

            int payLen = message.m_data.LengthBytes;

            // Out of band?
            if (message.m_type == NetMessageLibraryType.OutOfBand)
            {
                if ((m_enabledMessageTypes & NetMessageType.OutOfBandData) != NetMessageType.OutOfBandData)
                {
                    return;                     // drop
                }
                // just deliver
                message.m_msgType        = NetMessageType.OutOfBandData;
                message.m_senderEndPoint = senderEndpoint;

                EnqueueReceivedMessage(message);
                return;
            }

            if (message.m_sender == null)
            {
                //
                // Handle unconnected message
                //

                // not a connected sender; only allow System messages
                if (message.m_type != NetMessageLibraryType.System)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Rejecting non-system message from unconnected source: " + message, null, message.m_senderEndPoint);
                    }
                    return;
                }

                // read type of system message
                NetSystemType sysType = (NetSystemType)message.m_data.ReadByte();
                switch (sysType)
                {
                case NetSystemType.Connect:

                    LogVerbose("Connection request received from " + senderEndpoint);

                    NetConnection conn;
                    if (m_pendingLookup.TryGetValue(senderEndpoint, out conn))
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Ignore connection request received because already pending", conn, senderEndpoint);
                        }
                        return;
                    }

                    if (m_connectionLookup.TryGetValue(senderEndpoint, out conn))
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Ignore connection request received because already connected", conn, senderEndpoint);
                        }
                        return;
                    }

                    // check app id
                    if (payLen < 4)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Malformed Connect message received from " + senderEndpoint, null, senderEndpoint);
                        }
                        return;
                    }
                    string appIdent = message.m_data.ReadString();
                    if (appIdent != m_config.ApplicationIdentifier)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                        {
                            NotifyApplication(NetMessageType.ConnectionRejected, "Bad app id", null, senderEndpoint);
                        }

                        // send connection rejected
                        NetBuffer rejreason = new NetBuffer("Bad app id");
                        QueueSingleUnreliableSystemMessage(
                            NetSystemType.ConnectionRejected,
                            rejreason,
                            senderEndpoint,
                            false
                            );
                        return;
                    }

                    // read random identifer
                    var rndSignature = message.m_data.ReadBytes(NetConstants.SignatureByteSize);
                    if (NetUtility.CompareElements(rndSignature, m_localRndSignature))
                    {
                        // don't allow self-connect
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                        {
                            NotifyApplication(NetMessageType.ConnectionRejected, "Connection to self not allowed", null, senderEndpoint);
                        }
                        return;
                    }

                    int rndSeqNr = message.m_data.ReadInt32();

                    double localTimeSent  = message.m_data.ReadDouble();
                    double remoteTimeRecv = timestamp + m_localTimeOffset;

                    int    bytesReadSoFar = message.m_data.PositionBytes;
                    int    hailLen        = message.m_data.LengthBytes - bytesReadSoFar;
                    byte[] hailData       = null;
                    if (hailLen > 0)
                    {
                        hailData = new byte[hailLen];
                        Buffer.BlockCopy(message.m_data.Data, bytesReadSoFar, hailData, 0, hailLen);
                    }

                    if (m_config.m_maxConnections != -1 && m_connections.Count >= m_config.m_maxConnections)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                        {
                            NotifyApplication(NetMessageType.ConnectionRejected, "Max connections", null, senderEndpoint);
                        }

                        // send connection rejected
                        NetBuffer rejreason = new NetBuffer("Server full");
                        QueueSingleUnreliableSystemMessage(
                            NetSystemType.ConnectionRejected,
                            rejreason,
                            senderEndpoint,
                            false
                            );

                        return;
                    }

#if LIMITED_BUILD
                    if (m_connections.Count >= 2)
                    {
                        if ((m_enabledMessageTypes & NetMessageType.ConnectionRejected) == NetMessageType.ConnectionRejected)
                        {
                            NotifyApplication(NetMessageType.ConnectionRejected, "I'm special", null, senderEndpoint);
                        }

                        // send connection rejected
                        NetBuffer rejreason = new NetBuffer("Special server");
                        QueueSingleUnreliableSystemMessage(
                            NetSystemType.ConnectionRejected,
                            rejreason,
                            senderEndpoint,
                            false
                            );

                        return;
                    }
#endif

                    // Create connection
                    LogWrite("New connection: " + senderEndpoint);
                    conn = new NetConnection(this, senderEndpoint, null, hailData, rndSignature, rndSeqNr);
                    m_pendingLookup.Add(senderEndpoint, conn);

                    conn.m_connectLocalSentTime  = localTimeSent;
                    conn.m_connectRemoteRecvTime = remoteTimeRecv;

                    // Connection approval?
                    if ((m_enabledMessageTypes & NetMessageType.ConnectionApproval) == NetMessageType.ConnectionApproval)
                    {
                        // Ask application if this connection is allowed to proceed
                        IncomingNetMessage app = CreateIncomingMessage();
                        app.m_msgType = NetMessageType.ConnectionApproval;
                        if (hailData != null)
                        {
                            app.m_data.Write(hailData);
                        }
                        app.m_sender    = conn;
                        conn.m_approved = false;
                        EnqueueReceivedMessage(app);
                        // Don't add connection; it's done as part of the approval procedure
                        return;
                    }

                    // it's ok
                    AddConnection(now, conn);
                    break;

                case NetSystemType.ConnectionEstablished:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Connection established received from non-connection! " + senderEndpoint, null, senderEndpoint);
                    }
                    return;

                case NetSystemType.Discovery:
                    if (m_config.AnswerDiscoveryRequests)
                    {
                        m_discovery.HandleRequest(message, senderEndpoint);
                    }
                    break;

                case NetSystemType.DiscoveryResponse:
                    if (m_allowOutgoingConnections)
                    {
                        // NetPeer
                        IncomingNetMessage resMsg = m_discovery.HandleResponse(message, senderEndpoint);
                        if (resMsg != null)
                        {
                            resMsg.m_senderEndPoint = senderEndpoint;
                            EnqueueReceivedMessage(resMsg);
                        }
                    }
                    break;

                case NetSystemType.Ping:
                {
                    var tempBuffer = GetTempBuffer();
                    tempBuffer.Write("We're not connected");
                    SendSingleUnreliableSystemMessage(
                        NetSystemType.Disconnect,
                        tempBuffer,
                        senderEndpoint,
                        null
                        );

                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Ignore " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint);
                    }

                    break;
                }

                default:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Ignore " + this + " receiving system type " + sysType + ": " + message + " from unconnected source", null, senderEndpoint);
                    }
                    break;
                }
                // done
                return;
            }

            // ok, we have a sender
            if (message.m_type == NetMessageLibraryType.Acknowledge)
            {
                message.m_sender.HandleAckMessage(now, message);
                return;
            }

            if (message.m_type == NetMessageLibraryType.System)
            {
                //
                // Handle system messages from connected source
                //

                if (payLen < 1)
                {
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Received malformed system message; payload length less than 1 byte", null, senderEndpoint);
                    }
                    return;
                }
                NetSystemType sysType = (NetSystemType)message.m_data.ReadByte();
                switch (sysType)
                {
                case NetSystemType.Connect:
                case NetSystemType.ConnectionEstablished:
                case NetSystemType.Ping:
                case NetSystemType.Pong:
                case NetSystemType.Disconnect:
                case NetSystemType.ConnectionRejected:
                case NetSystemType.StringTableAck:
                    message.m_sender.HandleSystemMessage(message, now);
                    break;

                case NetSystemType.ConnectResponse:
                    if (m_allowOutgoingConnections)
                    {
                        message.m_sender.HandleSystemMessage(message, now);
                    }
                    else
                    {
                        if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        {
                            NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint);
                        }
                    }
                    break;

                case NetSystemType.Discovery:
                    // Allow discovery even if connected
                    if (m_config.AnswerDiscoveryRequests)
                    {
                        m_discovery.HandleRequest(message, senderEndpoint);
                    }
                    break;

                default:
                    if ((m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    {
                        NotifyApplication(NetMessageType.BadMessageReceived, "Undefined behaviour for server and system type " + sysType, null, senderEndpoint);
                    }
                    break;
                }
                return;
            }

            message.m_sender.HandleUserMessage(message, now);
        }
Example #38
0
        /// <summary>
        /// Process a user message
        /// </summary>
        internal void HandleUserMessage(IncomingNetMessage msg)
        {
#if DEBUG
            if (System.Threading.Thread.CurrentThread != m_owner.m_heartbeatThread)
            {
                throw new Exception("Threading error; should be heartbeat thread. Please check callstack!");
            }
#endif

            //
            // Unreliable
            //
            if (msg.m_sequenceChannel == NetChannel.Unreliable)
            {
                AcceptMessage(msg);
                return;
            }

            //
            // Sequenced
            //
            if (msg.m_sequenceChannel >= NetChannel.UnreliableInOrder1 && msg.m_sequenceChannel <= NetChannel.UnreliableInOrder15)
            {
                // relate to expected
                int seqChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.UnreliableInOrder1;
                int sdiff     = Relate(msg.m_sequenceNumber, m_nextExpectedSequenced[seqChanNr]);

                if (sdiff < 0)
                {
                    // Reject late sequenced message
                    m_owner.LogVerbose("Rejecting late sequenced " + msg);
                    m_statistics.CountDroppedSequencedMessage();
                    return;
                }
                AcceptMessage(msg);
                int nextExpected = msg.m_sequenceNumber + 1;
                if (nextExpected > NetConstants.NumSequenceNumbers)
                {
                    nextExpected = 0;
                }
                m_nextExpectedSequenced[seqChanNr] = nextExpected;
                return;
            }

            //
            // Reliable and ReliableOrdered
            //

            // Send ack, regardless of anything
            m_acknowledgesToSend.Enqueue(((int)msg.m_sequenceChannel << 16) | msg.m_sequenceNumber);

            // relate to all received up to
            int relChanNr = (int)msg.m_sequenceChannel - (int)NetChannel.ReliableUnordered;
            int arut      = m_allReliableReceivedUpTo[relChanNr];
            int diff      = Relate(msg.m_sequenceNumber, arut);

            if (diff < 0)
            {
                // Reject duplicate
                m_statistics.CountDuplicateMessage(msg);
                m_owner.LogVerbose("Rejecting(1) duplicate reliable " + msg, this);
                return;
            }

            bool isOrdered = (msg.m_sequenceChannel >= NetChannel.ReliableInOrder1);

            if (arut == msg.m_sequenceNumber)
            {
                // Right on time
                AcceptMessage(msg);
                PostAcceptReliableMessage(msg, arut);
                return;
            }

            // get bools list we must check
            bool[] recList = m_reliableReceived[relChanNr];
            if (recList == null)
            {
                recList = new bool[NetConstants.NumSequenceNumbers];
                m_reliableReceived[relChanNr] = recList;
            }

            if (recList[msg.m_sequenceNumber])
            {
                // Reject duplicate
                m_statistics.CountDuplicateMessage(msg);
                m_owner.LogVerbose("Rejecting(2) duplicate reliable " + msg, this);
                return;
            }

            // It's an early reliable message
            if (m_reliableReceived[relChanNr] == null)
            {
                m_reliableReceived[relChanNr] = new bool[NetConstants.NumSequenceNumbers];
            }
            m_reliableReceived[relChanNr][msg.m_sequenceNumber] = true;

            if (!isOrdered)
            {
                AcceptMessage(msg);
                return;
            }

            // Early ordered message; withhold
            List <IncomingNetMessage> wmlist = m_withheldMessages[relChanNr];
            if (wmlist == null)
            {
                wmlist = new List <IncomingNetMessage>();
                m_withheldMessages[relChanNr] = wmlist;
            }

            m_owner.LogVerbose("Withholding " + msg + " (waiting for " + arut + ")", this);
            wmlist.Add(msg);
            return;
        }
        internal void HandleAckMessage(IncomingNetMessage ackMessage)
        {
            int len = ackMessage.m_data.LengthBytes;
            if ((len % 3) != 0)
            {
                if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                    m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; length must be multiple of 3; it's " + len, this, ackMessage.m_senderEndPoint);
                return;
            }

            for (int i = 0; i < len; i += 3)
            {

                NetChannel chan = (NetChannel)ackMessage.m_data.ReadByte();
                int seqNr = ackMessage.m_data.ReadUInt16();

                // LogWrite("Acknowledgement received: " + chan + "|" + seqNr);
                m_statistics.CountAcknowledgesReceived(1);

                // remove saved message
                int chanIdx = (int)chan - (int)NetChannel.ReliableUnordered;
                if (chanIdx < 0)
                {
                    if ((m_owner.m_enabledMessageTypes & NetMessageType.BadMessageReceived) == NetMessageType.BadMessageReceived)
                        m_owner.NotifyApplication(NetMessageType.BadMessageReceived, "Malformed ack message; indicated netchannel " + chan, this, ackMessage.m_senderEndPoint);
                    continue;
                }

                List<OutgoingNetMessage> list = m_storedMessages[chanIdx];
                if (list != null)
                {
                    int cnt = list.Count;
                    if (cnt > 0)
                    {
                        for (int o = 0; o < cnt; o++)
                        {
                            OutgoingNetMessage msg = list[o];
                            if (msg.m_sequenceNumber == seqNr)
                            {

                                //LogWrite("Removed stored message: " + msg);
                                list.RemoveAt(o);

                                // reduce estimated amount of packets on wire
                                //CongestionCountAck(msg.m_packetNumber);

                                // fire receipt
                                if (msg.m_receiptData != null)
                                {
                                    m_owner.LogVerbose("Got ack, removed from storage: " + msg + " firing receipt; " + msg.m_receiptData, this);
                                    m_owner.FireReceipt(this, msg.m_receiptData);
                                }
                                else
                                {
                                    m_owner.LogVerbose("Got ack, removed from storage: " + msg, this);
                                }

                                // recycle
                                msg.m_data.m_refCount--;
                                if (msg.m_data.m_refCount <= 0)
                                    m_owner.RecycleBuffer(msg.m_data); // time to recycle buffer

                                msg.m_data = null;
                                //m_owner.m_messagePool.Push(msg);

                                break;
                            }
                        }
                    }
                }
            }

            // recycle
            NetBuffer rb = ackMessage.m_data;
            rb.m_refCount = 0; // ack messages can't be used by more than one message
            ackMessage.m_data = null;

            m_owner.RecycleBuffer(rb);
            //m_owner.m_messagePool.Push(ackMessage);
        }
Example #40
0
		internal void EnqueueReceivedMessage(IncomingNetMessage msg)
		{
			lock (m_receivedMessages)
			{
				m_receivedMessages.Enqueue(msg);				
			}
            m_dataReceivedEvent.Set();
		}