public static List <STUNAttribute> ParseMessageAttributes(byte[] buffer, int startIndex, int endIndex)
        {
            if (buffer != null && buffer.Length > startIndex && buffer.Length >= endIndex)
            {
                List <STUNAttribute> attributes = new List <STUNAttribute>();
                int startAttIndex = startIndex;

                while (startAttIndex < endIndex)
                {
                    UInt16 stunAttributeType   = BitConverter.ToUInt16(buffer, startAttIndex);
                    UInt16 stunAttributeLength = BitConverter.ToUInt16(buffer, startAttIndex + 2);
                    byte[] stunAttributeValue  = null;

                    if (BitConverter.IsLittleEndian)
                    {
                        stunAttributeType   = Utility.ReverseEndian(stunAttributeType);
                        stunAttributeLength = Utility.ReverseEndian(stunAttributeLength);
                    }

                    if (stunAttributeLength > 0)
                    {
                        if (stunAttributeType == (int)STUNAttributeTypesEnum.Username && stunAttributeLength > buffer.Length - startIndex - 4)
                        {
                            // Received some STUN messages where the username is shorter than the claimed length.
                            int realLength = buffer.Length - startIndex - 4;
                            stunAttributeValue = new byte[realLength];
                            Buffer.BlockCopy(buffer, startIndex + 4, stunAttributeValue, 0, realLength);
                        }
                        else
                        {
                            stunAttributeValue = new byte[stunAttributeLength];
                            Buffer.BlockCopy(buffer, startIndex + 4, stunAttributeValue, 0, stunAttributeLength);
                        }
                    }

                    STUNAttributeTypesEnum attributeType = STUNAttributeTypes.GetSTUNAttributeTypeForId(stunAttributeType);

                    STUNAttribute attribute = null;
                    if (attributeType == STUNAttributeTypesEnum.ChangeRequest)
                    {
                        attribute = new STUNChangeRequestAttribute(stunAttributeValue);
                    }
                    else if (attributeType == STUNAttributeTypesEnum.MappedAddress)
                    {
                        attribute = new STUNAddressAttribute(stunAttributeValue);
                    }
                    else
                    {
                        attribute = new STUNAttribute(attributeType, stunAttributeLength, stunAttributeValue);
                    }

                    attributes.Add(attribute);

                    startAttIndex = startAttIndex + 4 + stunAttributeLength;
                }

                return(attributes);
            }
            else
            {
                return(null);
            }
        }
        public void STUNPrimaryReceived(IPEndPoint localEndPoint, IPEndPoint receivedEndPoint, byte[] buffer, int bufferLength)
        {
            try
            {
                //Console.WriteLine("\n=> received from " + IPSocketAddress.GetSocketString(receivedEndPoint) + " on " + IPSocketAddress.GetSocketString(receivedOnEndPoint));
                //Console.WriteLine(Utility.PrintBuffer(buffer));

                STUNMessage stunRequest = STUNMessage.ParseSTUNMessage(buffer, bufferLength);
                //Console.WriteLine(stunRequest.ToString());

                FireSTUNPrimaryRequestInTraceEvent(localEndPoint, receivedEndPoint, stunRequest);

                STUNMessage stunResponse       = GetResponse(receivedEndPoint, stunRequest, true);
                byte[]      stunResponseBuffer = stunResponse.ToByteBuffer();

                bool changeAddress = false;
                bool changePort    = false;
                foreach (STUNAttribute attr in stunRequest.Attributes)
                {
                    if (attr.AttributeType == STUNAttributeTypesEnum.ChangeRequest)
                    {
                        STUNChangeRequestAttribute changeReqAttr = (STUNChangeRequestAttribute)attr;
                        changeAddress = changeReqAttr.ChangeAddress;
                        changePort    = changeReqAttr.ChangePort;
                        break;
                    }
                }

                if (!changeAddress)
                {
                    if (!changePort)
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_primaryEndPoint));
                        m_primarySend(receivedEndPoint, stunResponseBuffer);

                        FireSTUNPrimaryResponseOutTraceEvent(m_primaryEndPoint, receivedEndPoint, stunResponse);
                    }
                    else
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_primaryDiffPortEndPoint));
                        m_primaryDiffPortSocket.Send(stunResponseBuffer, stunResponseBuffer.Length, receivedEndPoint);

                        FireSTUNPrimaryResponseOutTraceEvent(m_primaryDiffPortEndPoint, receivedEndPoint, stunResponse);
                    }
                }
                else
                {
                    if (!changePort)
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_secondaryEndPoint));
                        m_secondarySend(receivedEndPoint, stunResponseBuffer);

                        FireSTUNSecondaryResponseOutTraceEvent(m_secondaryEndPoint, receivedEndPoint, stunResponse);
                    }
                    else
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_secondaryDiffPortEndPoint));
                        m_secondaryDiffPortSocket.Send(stunResponseBuffer, stunResponseBuffer.Length, receivedEndPoint);

                        FireSTUNSecondaryResponseOutTraceEvent(m_secondaryDiffPortEndPoint, receivedEndPoint, stunResponse);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Debug("Exception STUNPrimaryReceived. " + excp.Message);
            }
        }