/// <summary> /// Parses attribute from data. /// </summary> /// <param name="data">SIP message data.</param> /// <param name="offset">Offset in data.</param> private void ParseAttribute(byte[] data, ref int offset) { /* RFC 3489 11.2. * Each attribute is TLV encoded, with a 16 bit type, 16 bit length, and variable value: * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Value .... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ // Type AttributeType type = (AttributeType)(data[offset++] << 8 | data[offset++]); // Length int length = (data[offset++] << 8 | data[offset++]); // MAPPED-ADDRESS if (type == AttributeType.MappedAddress) { m_pMappedAddress = ParseEndPoint(data, ref offset); } // RESPONSE-ADDRESS else if (type == AttributeType.ResponseAddress) { m_pResponseAddress = ParseEndPoint(data, ref offset); } // CHANGE-REQUEST else if (type == AttributeType.ChangeRequest) { /* * The CHANGE-REQUEST attribute is used by the client to request that * the server use a different address and/or port when sending the * response. The attribute is 32 bits long, although only two bits (A * and B) are used: * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * The meaning of the flags is: * * A: This is the "change IP" flag. If true, it requests the server * to send the Binding Response with a different IP address than the * one the Binding Request was received on. * * B: This is the "change port" flag. If true, it requests the * server to send the Binding Response with a different port than the * one the Binding Request was received on. */ // Skip 3 bytes offset += 3; m_pChangeRequest = new STUN_t_ChangeRequest((data[offset] & 4) != 0, (data[offset] & 2) != 0); offset++; } // SOURCE-ADDRESS else if (type == AttributeType.SourceAddress) { m_pSourceAddress = ParseEndPoint(data, ref offset); } // CHANGED-ADDRESS else if (type == AttributeType.ChangedAddress) { m_pChangedAddress = ParseEndPoint(data, ref offset); } // USERNAME else if (type == AttributeType.Username) { m_UserName = Helpers.GetDefaultEncoding().GetString(data, offset, length); offset += length; } // PASSWORD else if (type == AttributeType.Password) { m_Password = Helpers.GetDefaultEncoding().GetString(data, offset, length); offset += length; } // MESSAGE-INTEGRITY else if (type == AttributeType.MessageIntegrity) { offset += length; } // ERROR-CODE else if (type == AttributeType.ErrorCode) { /* 3489 11.2.9. * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0 |Class| Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reason Phrase (variable) .. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ int errorCode = (data[offset + 2] & 0x7) * 100 + (data[offset + 3] & 0xFF); m_pErrorCode = new STUN_t_ErrorCode(errorCode, Helpers.GetDefaultEncoding().GetString(data, offset + 4, length - 4)); offset += length; } // UNKNOWN-ATTRIBUTES else if (type == AttributeType.UnknownAttribute) { offset += length; } // REFLECTED-FROM else if (type == AttributeType.ReflectedFrom) { m_pReflectedFrom = ParseEndPoint(data, ref offset); } // XorMappedAddress // XorOnly // ServerName else if (type == AttributeType.ServerName) { m_ServerName = Helpers.GetDefaultEncoding().GetString(data, offset, length); offset += length; } // Unknown else { offset += length; } }
/// <summary> /// Parses attribute from data. /// </summary> /// <param name="data">SIP message data.</param> /// <param name="offset">Offset in data.</param> private void ParseAttribute(byte[] data,ref int offset) { /* RFC 3489 11.2. Each attribute is TLV encoded, with a 16 bit type, 16 bit length, and variable value: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Value .... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ // Type AttributeType type = (AttributeType)(data[offset++] << 8 | data[offset++]); // Length int length = (data[offset++] << 8 | data[offset++]); // MAPPED-ADDRESS if(type == AttributeType.MappedAddress){ m_pMappedAddress = ParseEndPoint(data,ref offset); } // RESPONSE-ADDRESS else if(type == AttributeType.ResponseAddress){ m_pResponseAddress = ParseEndPoint(data,ref offset); } // CHANGE-REQUEST else if(type == AttributeType.ChangeRequest){ /* The CHANGE-REQUEST attribute is used by the client to request that the server use a different address and/or port when sending the response. The attribute is 32 bits long, although only two bits (A and B) are used: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The meaning of the flags is: A: This is the "change IP" flag. If true, it requests the server to send the Binding Response with a different IP address than the one the Binding Request was received on. B: This is the "change port" flag. If true, it requests the server to send the Binding Response with a different port than the one the Binding Request was received on. */ // Skip 3 bytes offset += 3; m_pChangeRequest = new STUN_t_ChangeRequest((data[offset] & 4) != 0,(data[offset] & 2) != 0); offset++; } // SOURCE-ADDRESS else if(type == AttributeType.SourceAddress){ m_pSourceAddress = ParseEndPoint(data,ref offset); } // CHANGED-ADDRESS else if(type == AttributeType.ChangedAddress){ m_pChangedAddress = ParseEndPoint(data,ref offset); } // USERNAME else if(type == AttributeType.Username){ m_UserName = Encoding.Default.GetString(data,offset,length); offset += length; } // PASSWORD else if(type == AttributeType.Password){ m_Password = Encoding.Default.GetString(data,offset,length); offset += length; } // MESSAGE-INTEGRITY else if(type == AttributeType.MessageIntegrity){ offset += length; } // ERROR-CODE else if(type == AttributeType.ErrorCode){ /* 3489 11.2.9. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0 |Class| Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reason Phrase (variable) .. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ int errorCode = (data[offset + 2] & 0x7) * 100 + (data[offset + 3] & 0xFF); m_pErrorCode = new STUN_t_ErrorCode(errorCode,Encoding.Default.GetString(data,offset + 4,length - 4)); offset += length; } // UNKNOWN-ATTRIBUTES else if(type == AttributeType.UnknownAttribute){ offset += length; } // REFLECTED-FROM else if(type == AttributeType.ReflectedFrom){ m_pReflectedFrom = ParseEndPoint(data,ref offset); } // XorMappedAddress // XorOnly // ServerName else if(type == AttributeType.ServerName){ m_ServerName = Encoding.Default.GetString(data,offset,length); offset += length; } // Unknown else{ offset += length; } }