Esempio n. 1
0
        internal static void HandlePacket(byte[] payload)
        {
            bool SYN = (payload[47] & (1<<1)) != 0;  // Synchronize
            bool ACK = (payload[47] & (1<<4)) != 0;  // Acknoledge
            bool FIN = (payload[47] & (1<<0)) != 0;  // Finish
            bool PSH = (payload[47] & (1<<3)) != 0;  // Push
            bool RST = (payload[47] & (1<<2)) != 0;  // Reset

            byte[] SourceIP = Utility.ExtractRangeFromArray(payload, 26, 4);
            byte[] SourcePort = Utility.ExtractRangeFromArray(payload, 34, 2);
            byte[] LocalPort = Utility.ExtractRangeFromArray(payload, 36, 2);
            ulong connectionID = GenerateConnectionID(payload);
            Connection con = null;

            //TODO: Validate TCP checksum and reject packet if invalid!

            uint packetSeqNumber = Utility.ExtractRangeFromArray(payload, 38, 4).ToInt();

            // Handle a new request
            // if this is a new connection SYN, add to the Connections collection
            if (SYN && !ACK)   // new connection
            {
                //Debug.WriteLine("SYN");

                if (Connections.Contains(connectionID) && (Connections[connectionID] as Connection).IsOpen) Connections.Remove(connectionID);  // remove old connection?

                // Prune old Connections

                var keys = new ulong[Connections.Count];
                Connections.Keys.CopyTo(keys, 0);

                foreach (var key in keys)
                {
                    con = Connections[key] as Connection;

                    if (Microsoft.SPOT.Hardware.Utility.GetMachineTime().Subtract((Connections[key] as Connection).LastActivity).Seconds > ConnectionIdleLimit)
                    {
                        con.isClosing = true;
                        //Adapter.StopListeningToPort(con.LocalPort);
                        //Debug.WriteLine("FIN -- Closing idle connection");
                        con.SeqNumber++;
                        con.SendAck(false, true);  // SendAck Fin/Ack
                        Connections.Remove(key);
                    }
                }

                if (!Connections.Contains(connectionID)) Connections.Add(connectionID, new Connection());

                con = Connections[connectionID] as Connection;

                con.RemoteIP = SourceIP;
                con.RemotePort = SourcePort.ToShort();
                con.RemoteMac = Utility.ExtractRangeFromArray(payload, 6, 6);
                con.LocalPort = LocalPort.ToShort();
                con.SeqNumber = packetSeqNumber + 1;
                con.StartSeqNumber = packetSeqNumber;
                con.AckNumber = 2380; //Utility.ExtractRangeFromArray(payload, 42, 4).ToInt(), //TODO: this should be a random number initially?
                con.WindowSize = 1024; //Utility.ExtractRangeFromArray(payload, 48, 2).ToShort()

                con.ReadyForRequest = true;
                con.SendAck(true); // Syn/Ack

                con.AckNumber++;
                con.IsOpen = true;  // This needs to be last because a call to the Connection.Open() may be blocked until this property gets set!
            }
            else if (Connections.Contains(connectionID) && (ACK || FIN || PSH || RST))
            {
                con = Connections[connectionID] as Connection;

                ushort totalLength = Utility.ExtractRangeFromArray(payload, 16, 2).ToShort();
                ushort ipHeaderLength = (ushort)((payload[14] & 0x0f) * 4);
                ushort tcpHeaderLength = (ushort)((payload[26 + ipHeaderLength] >> 4) * 4);

                if (totalLength + 14 > payload.Length)
                {
                    // No Good -- Does not account for 0 padding?
                    Debug.WriteLine("Bad packet size detected?  " + totalLength.ToString() + "/" + payload.Length.ToString());
                    return;
                }

                //Debug.WriteLine("1 - con.seqnum = " + con.SeqNumber);

                con.SeqNumber += (uint)(totalLength - (tcpHeaderLength + ipHeaderLength));
                con.WindowSize -= (ushort)(totalLength - (tcpHeaderLength + ipHeaderLength));

                //Debug.WriteLine("2 - con.seqnum = " + con.SeqNumber);

                if (PSH)
                {
                    //Debug.WriteLine("PSH");
                    con.SendAck();  // PSH indicates we want an ACK after this packet?
                }
                else if (SYN && ACK)
                {
                    con.SeqNumber = packetSeqNumber + 1;
                    con.StartSeqNumber = packetSeqNumber;
                    con.AckNumber++;
                    con.SendAck();
                    con.IsOpen = true;
                    return;
                }
                else if ((FIN || RST) && ACK)
                {
                    // Debug.WriteLine("FIN/RST + ACK");
                    con.isClosing = true;
                    //Adapter.StopListeningToPort(con.LocalPort);
                    con.SeqNumber++;
                    con.SendAck();
                    // This is an ACKnowledgement that the connection is now closed, so delete it.
                    Connections.Remove(connectionID);
                    return;
                }
                else if (FIN)
                {
                    con.isClosing = true;
                    //Adapter.StopListeningToPort(con.LocalPort);
                    // Debug.WriteLine("FIN");

                    con.SeqNumber++;
                    con.SendAck(false, true);
                    return;
                }
                else if (RST)
                {
                    con.isClosing = true;
                    //Adapter.StopListeningToPort(con.LocalPort);
                    // Debug.WriteLine("FIN");
                    con.SeqNumber++;
                    //con.SendAck(false, true);
                    return;
                }
                else if (ACK && con.isClosing)
                {
                    // Debug.WriteLine("ACK + Closing");
                    // This is an ACKnowledgement that the connection is now closed, so delete it.
                    //Adapter.StopListeningToPort(con.LocalPort);
                    Connections.Remove(connectionID);
                    return;
                }

                if (Adapter.VerboseDebugging) Debug.WriteLine("Check for data");

                //We got some data!?
                if ((totalLength - (tcpHeaderLength + ipHeaderLength)) > 0)
                {
                    byte[] segment = Utility.ExtractRangeFromArray(payload, (14 + ipHeaderLength + tcpHeaderLength), (totalLength - (tcpHeaderLength + ipHeaderLength)));

                    if (Adapter.VerboseDebugging) Debug.WriteLine("got some data, psn: " + packetSeqNumber.ToString() + ", ssn: " + con.StartSeqNumber.ToString() + ", header delim: " + segment.Locate(HttpRequest.HeaderDelimiter).ToString());

                    Networking.Adapter.FireTcpPacketEvent(segment, packetSeqNumber - con.StartSeqNumber, con);  // TCP events always fire

                    con.FireOnConnectionPacketReceived(new Packet(PacketType.TCP) { SequenceNumber = packetSeqNumber - con.StartSeqNumber, Content = segment, Socket = con });

                    // Filters out anything that is not a GET or POST Http VERB (I did a byte comparison to avoid utf decoding exceptions, since we don't know that we actually have text yet)
                    //if (packetSeqNumber - con.StartSeqNumber == 1)
                    if (segment.Length < 10 || !(segment[0] == 0x47 && segment[1] == 0x45 && segment[2] == 0x54) && !(segment[0] == 0x50 && segment[1] == 0x4F && segment[2] == 0x53 && segment[3] == 0x54)) return;  // if it is not a get, then we won't handle it through the HTTP Request Handler

                    //if (packetSeqNumber - con.StartSeqNumber == 1) // && segment.Locate(HttpRequest.HeaderDelimiter) > -1)
                    if (con.ReadyForRequest)
                    {
                        // get the TCP checksum from the current packet and make sure it does not match the last request for we start...
                        byte[] lrc = Utility.ExtractRangeFromArray(payload, (30 + ipHeaderLength), 2);

                        if (con.LastRequestChecksum.BytesEqual(lrc))
                        {
                            if (Adapter.VerboseDebugging) Debug.WriteLine("Retransmission of Request Ignored!");
                        }
                        else
                        {
                            con.LastRequestChecksum = lrc;
                            con.ReadyForRequest = false;
                            Networking.Adapter.FireHttpPacketEvent(segment, con);
                        }
                    }
                }
            }
            else if ((FIN || RST) && ACK)
            {
                //Debug.WriteLine("Handling RST for a connection that no longer exists!!!!!!!!!");

                con = new Connection();
                con.RemoteIP = SourceIP;
                con.RemotePort = SourcePort.ToShort();
                con.RemoteMac = Utility.ExtractRangeFromArray(payload, 6, 6);
                con.LocalPort = LocalPort.ToShort();
                con.SeqNumber = Utility.ExtractRangeFromArray(payload, 38, 4).ToInt();
                con.AckNumber = Utility.ExtractRangeFromArray(payload, 42, 4).ToInt();

                con.isClosing = true;
                //Adapter.StopListeningToPort(con.LocalPort);
                con.SendAck();
                return;
            }
        }
Esempio n. 2
0
        internal static void HandlePacket(byte[] payload)
        {
            bool SYN = (payload[47] & (1 << 1)) != 0;  // Synchronize
            bool ACK = (payload[47] & (1 << 4)) != 0;  // Acknoledge
            bool FIN = (payload[47] & (1 << 0)) != 0;  // Finish
            bool PSH = (payload[47] & (1 << 3)) != 0;  // Push
            bool RST = (payload[47] & (1 << 2)) != 0;  // Reset

            byte[]     SourceIP     = Utility.ExtractRangeFromArray(payload, 26, 4);
            byte[]     SourcePort   = Utility.ExtractRangeFromArray(payload, 34, 2);
            byte[]     LocalPort    = Utility.ExtractRangeFromArray(payload, 36, 2);
            ulong      connectionID = GenerateConnectionID(payload);
            Connection con          = null;

            //TODO: Validate TCP checksum and reject packet if invalid!

            uint packetSeqNumber = Utility.ExtractRangeFromArray(payload, 38, 4).ToInt();

            // Handle a new request
            // if this is a new connection SYN, add to the Connections collection
            if (SYN && !ACK)   // new connection
            {
                //Debug.WriteLine("SYN");

                if (Connections.Contains(connectionID) && (Connections[connectionID] as Connection).IsOpen)
                {
                    Connections.Remove(connectionID);                                                                                          // remove old connection?
                }
                // Prune old Connections

                var keys = new ulong[Connections.Count];
                Connections.Keys.CopyTo(keys, 0);

                foreach (var key in keys)
                {
                    con = Connections[key] as Connection;

                    if (Microsoft.SPOT.Hardware.Utility.GetMachineTime().Subtract((Connections[key] as Connection).LastActivity).Seconds > ConnectionIdleLimit)
                    {
                        con.isClosing = true;
                        //Adapter.StopListeningToPort(con.LocalPort);
                        //Debug.WriteLine("FIN -- Closing idle connection");
                        con.SeqNumber++;
                        con.SendAck(false, true);  // SendAck Fin/Ack
                        Connections.Remove(key);
                    }
                }

                if (!Connections.Contains(connectionID))
                {
                    Connections.Add(connectionID, new Connection());
                }

                con = Connections[connectionID] as Connection;

                con.RemoteIP       = SourceIP;
                con.RemotePort     = SourcePort.ToShort();
                con.RemoteMac      = Utility.ExtractRangeFromArray(payload, 6, 6);
                con.LocalPort      = LocalPort.ToShort();
                con.SeqNumber      = packetSeqNumber + 1;
                con.StartSeqNumber = packetSeqNumber;
                con.AckNumber      = 2380; //Utility.ExtractRangeFromArray(payload, 42, 4).ToInt(), //TODO: this should be a random number initially?
                con.WindowSize     = 1024; //Utility.ExtractRangeFromArray(payload, 48, 2).ToShort()

                con.ReadyForRequest = true;
                con.SendAck(true); // Syn/Ack

                con.AckNumber++;
                con.IsOpen = true;  // This needs to be last because a call to the Connection.Open() may be blocked until this property gets set!
            }
            else if (Connections.Contains(connectionID) && (ACK || FIN || PSH || RST))
            {
                con = Connections[connectionID] as Connection;

                ushort totalLength     = Utility.ExtractRangeFromArray(payload, 16, 2).ToShort();
                ushort ipHeaderLength  = (ushort)((payload[14] & 0x0f) * 4);
                ushort tcpHeaderLength = (ushort)((payload[26 + ipHeaderLength] >> 4) * 4);

                if (totalLength + 14 > payload.Length)
                {
                    // No Good -- Does not account for 0 padding?
                    Debug.WriteLine("Bad packet size detected?  " + totalLength.ToString() + "/" + payload.Length.ToString());
                    return;
                }

                //Debug.WriteLine("1 - con.seqnum = " + con.SeqNumber);

                con.SeqNumber  += (uint)(totalLength - (tcpHeaderLength + ipHeaderLength));
                con.WindowSize -= (ushort)(totalLength - (tcpHeaderLength + ipHeaderLength));

                //Debug.WriteLine("2 - con.seqnum = " + con.SeqNumber);


                if (PSH)
                {
                    //Debug.WriteLine("PSH");
                    con.SendAck();  // PSH indicates we want an ACK after this packet?
                }
                else if (SYN && ACK)
                {
                    con.SeqNumber      = packetSeqNumber + 1;
                    con.StartSeqNumber = packetSeqNumber;
                    con.AckNumber++;
                    con.SendAck();
                    con.IsOpen = true;
                    return;
                }
                else if ((FIN || RST) && ACK)
                {
                    // Debug.WriteLine("FIN/RST + ACK");
                    con.isClosing = true;
                    //Adapter.StopListeningToPort(con.LocalPort);
                    con.SeqNumber++;
                    con.SendAck();
                    // This is an ACKnowledgement that the connection is now closed, so delete it.
                    Connections.Remove(connectionID);
                    return;
                }
                else if (FIN)
                {
                    con.isClosing = true;
                    //Adapter.StopListeningToPort(con.LocalPort);
                    // Debug.WriteLine("FIN");

                    con.SeqNumber++;
                    con.SendAck(false, true);
                    return;
                }
                else if (RST)
                {
                    con.isClosing = true;
                    //Adapter.StopListeningToPort(con.LocalPort);
                    // Debug.WriteLine("FIN");
                    con.SeqNumber++;
                    //con.SendAck(false, true);
                    return;
                }
                else if (ACK && con.isClosing)
                {
                    // Debug.WriteLine("ACK + Closing");
                    // This is an ACKnowledgement that the connection is now closed, so delete it.
                    //Adapter.StopListeningToPort(con.LocalPort);
                    Connections.Remove(connectionID);
                    return;
                }

                if (Adapter.VerboseDebugging)
                {
                    Debug.WriteLine("Check for data");
                }

                //We got some data!?
                if ((totalLength - (tcpHeaderLength + ipHeaderLength)) > 0)
                {
                    byte[] segment = Utility.ExtractRangeFromArray(payload, (14 + ipHeaderLength + tcpHeaderLength), (totalLength - (tcpHeaderLength + ipHeaderLength)));

                    if (Adapter.VerboseDebugging)
                    {
                        Debug.WriteLine("got some data, psn: " + packetSeqNumber.ToString() + ", ssn: " + con.StartSeqNumber.ToString() + ", header delim: " + segment.Locate(HttpRequest.HeaderDelimiter).ToString());
                    }

                    Networking.Adapter.FireTcpPacketEvent(segment, packetSeqNumber - con.StartSeqNumber, con);  // TCP events always fire

                    con.FireOnConnectionPacketReceived(new Packet(PacketType.TCP)
                    {
                        SequenceNumber = packetSeqNumber - con.StartSeqNumber, Content = segment, Socket = con
                    });

                    // Filters out anything that is not a GET or POST Http VERB (I did a byte comparison to avoid utf decoding exceptions, since we don't know that we actually have text yet)
                    //if (packetSeqNumber - con.StartSeqNumber == 1)
                    if (segment.Length < 10 || !(segment[0] == 0x47 && segment[1] == 0x45 && segment[2] == 0x54) && !(segment[0] == 0x50 && segment[1] == 0x4F && segment[2] == 0x53 && segment[3] == 0x54))
                    {
                        return;                                                                                                                                                                                       // if it is not a get, then we won't handle it through the HTTP Request Handler
                    }
                    //if (packetSeqNumber - con.StartSeqNumber == 1) // && segment.Locate(HttpRequest.HeaderDelimiter) > -1)
                    if (con.ReadyForRequest)
                    {
                        // get the TCP checksum from the current packet and make sure it does not match the last request for we start...
                        byte[] lrc = Utility.ExtractRangeFromArray(payload, (30 + ipHeaderLength), 2);

                        if (con.LastRequestChecksum.BytesEqual(lrc))
                        {
                            if (Adapter.VerboseDebugging)
                            {
                                Debug.WriteLine("Retransmission of Request Ignored!");
                            }
                        }
                        else
                        {
                            con.LastRequestChecksum = lrc;
                            con.ReadyForRequest     = false;
                            Networking.Adapter.FireHttpPacketEvent(segment, con);
                        }
                    }
                }
            }
            else if ((FIN || RST) && ACK)
            {
                //Debug.WriteLine("Handling RST for a connection that no longer exists!!!!!!!!!");

                con            = new Connection();
                con.RemoteIP   = SourceIP;
                con.RemotePort = SourcePort.ToShort();
                con.RemoteMac  = Utility.ExtractRangeFromArray(payload, 6, 6);
                con.LocalPort  = LocalPort.ToShort();
                con.SeqNumber  = Utility.ExtractRangeFromArray(payload, 38, 4).ToInt();
                con.AckNumber  = Utility.ExtractRangeFromArray(payload, 42, 4).ToInt();

                con.isClosing = true;
                //Adapter.StopListeningToPort(con.LocalPort);
                con.SendAck();
                return;
            }
        }