mediaSoup 源码分析-Stun packet处理

#对着协议看代码就已经很清晰了。

#stun packet 包头

//    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|     STUN Message Type     |         Message Length        |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                         Magic Cookie                          |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                                                               |
//   |                     Transaction ID (96 bits)                  |
//   |                                                               |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

#解析处理

StunPacket* StunPacket::Parse(const uint8_t* data, size_t len)
	{
		MS_TRACE();

		if (!StunPacket::IsStun(data, len))
			return nullptr;

		/*
		  The message type field is decomposed further into the following
		    structure:

		    0                 1
		    2  3  4 5 6 7 8 9 0 1 2 3 4 5
		       +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
		       |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
		       |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
		       +--+--+-+-+-+-+-+-+-+-+-+-+-+-+

		    Figure 3: Format of STUN Message Type Field

		   Here the bits in the message type field are shown as most significant
		   (M11) through least significant (M0).  M11 through M0 represent a 12-
		   bit encoding of the method.  C1 and C0 represent a 2-bit encoding of
		   the class.
		 */

		// Get type field.
		uint16_t msgType = Utils::Byte::Get2Bytes(data, 0);

		// Get length field.
		uint16_t msgLength = Utils::Byte::Get2Bytes(data, 2);

		// length field must be total size minus header's 20 bytes, and must be multiple of 4 Bytes.
		if ((static_cast(msgLength) != len - 20) || ((msgLength & 0x03) != 0))
		{
			MS_WARN_TAG(
			  ice,
			  "length field + 20 does not match total size (or it is not multiple of 4 bytes), "
			  "packet discarded");

			return nullptr;
		}

		// Get STUN method.
		uint16_t msgMethod = (msgType & 0x000f) | ((msgType & 0x00e0) >> 1) | ((msgType & 0x3E00) >> 2);

		// Get STUN class.
		uint16_t msgClass = ((data[0] & 0x01) << 1) | ((data[1] & 0x10) >> 4);

		// Create a new StunPacket (data + 8 points to the received TransactionID field).
		auto packet = new StunPacket(
		  static_cast(msgClass), static_cast(msgMethod), data + 8, data, len);

		/*
		    STUN Attributes

		    After the STUN header are zero or more attributes.  Each attribute
		    MUST be TLV encoded, with a 16-bit type, 16-bit length, and value.
		    Each STUN attribute MUST end on a 32-bit boundary.  As mentioned
		    above, all fields in an attribute are transmitted most significant
		    bit first.

		        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 (variable)                ....
		       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 */

		// Start looking for attributes after STUN header (Byte #20).
		size_t pos{ 20 };
		// Flags (positions) for special MESSAGE-INTEGRITY and FINGERPRINT attributes.
		bool hasMessageIntegrity{ false };
		bool hasFingerprint{ false };
		size_t fingerprintAttrPos; // Will point to the beginning of the attribute.
		uint32_t fingerprint;      // Holds the value of the FINGERPRINT attribute.

		// Ensure there are at least 4 remaining bytes (attribute with 0 length).
		while (pos + 4 <= len)
		{
			// Get the attribute type.
			auto attrType = static_cast(Utils::Byte::Get2Bytes(data, pos));

			// Get the attribute length.
			uint16_t attrLength = Utils::Byte::Get2Bytes(data, pos + 2);

			// Ensure the attribute length is not greater than the remaining size.
			if ((pos + 4 + attrLength) > len)
			{
				MS_WARN_TAG(ice, "the attribute length exceeds the remaining size, packet discarded");

				delete packet;
				return nullptr;
			}

			// FINGERPRINT must be the last attribute.
			if (hasFingerprint)
			{
				MS_WARN_TAG(ice, "attribute after FINGERPRINT is not allowed, packet discarded");

				delete packet;
				return nullptr;
			}

			// After a MESSAGE-INTEGRITY attribute just FINGERPRINT is allowed.
			if (hasMessageIntegrity && attrType != Attribute::FINGERPRINT)
			{
				MS_WARN_TAG(
				  ice,
				  "attribute after MESSAGE-INTEGRITY other than FINGERPRINT is not allowed, "
				  "packet discarded");

				delete packet;
				return nullptr;
			}

			const uint8_t* attrValuePos = data + pos + 4;

			switch (attrType)
			{
				case Attribute::USERNAME:
				{
					packet->SetUsername(
					  reinterpret_cast(attrValuePos), static_cast(attrLength));

					break;
				}

				case Attribute::PRIORITY:
				{
					// Ensure attribute length is 4 bytes.
					if (attrLength != 4)
					{
						MS_WARN_TAG(ice, "attribute PRIORITY must be 4 bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					packet->SetPriority(Utils::Byte::Get4Bytes(attrValuePos, 0));

					break;
				}

				case Attribute::ICE_CONTROLLING:
				{
					// Ensure attribute length is 8 bytes.
					if (attrLength != 8)
					{
						MS_WARN_TAG(ice, "attribute ICE-CONTROLLING must be 8 bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					packet->SetIceControlling(Utils::Byte::Get8Bytes(attrValuePos, 0));

					break;
				}

				case Attribute::ICE_CONTROLLED:
				{
					// Ensure attribute length is 8 bytes.
					if (attrLength != 8)
					{
						MS_WARN_TAG(ice, "attribute ICE-CONTROLLED must be 8 bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					packet->SetIceControlled(Utils::Byte::Get8Bytes(attrValuePos, 0));

					break;
				}

				case Attribute::USE_CANDIDATE:
				{
					// Ensure attribute length is 0 bytes.
					if (attrLength != 0)
					{
						MS_WARN_TAG(ice, "attribute USE-CANDIDATE must be 0 bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					packet->SetUseCandidate();

					break;
				}

				case Attribute::MESSAGE_INTEGRITY:
				{
					// Ensure attribute length is 20 bytes.
					if (attrLength != 20)
					{
						MS_WARN_TAG(ice, "attribute MESSAGE-INTEGRITY must be 20 bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					hasMessageIntegrity = true;
					packet->SetMessageIntegrity(attrValuePos);

					break;
				}

				case Attribute::FINGERPRINT:
				{
					// Ensure attribute length is 4 bytes.
					if (attrLength != 4)
					{
						MS_WARN_TAG(ice, "attribute FINGERPRINT must be 4 bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					hasFingerprint     = true;
					fingerprintAttrPos = pos;
					fingerprint        = Utils::Byte::Get4Bytes(attrValuePos, 0);
					packet->SetFingerprint();

					break;
				}

				case Attribute::ERROR_CODE:
				{
					// Ensure attribute length >= 4bytes.
					if (attrLength < 4)
					{
						MS_WARN_TAG(ice, "attribute ERROR-CODE must be >= 4bytes length, packet discarded");

						delete packet;
						return nullptr;
					}

					uint8_t errorClass  = Utils::Byte::Get1Byte(attrValuePos, 2);
					uint8_t errorNumber = Utils::Byte::Get1Byte(attrValuePos, 3);
					auto errorCode      = static_cast(errorClass * 100 + errorNumber);

					packet->SetErrorCode(errorCode);

					break;
				}

				default:;
			}

			// Set next attribute position.
			pos =
			  static_cast(Utils::Byte::PadTo4Bytes(static_cast(pos + 4 + attrLength)));
		}

		// Ensure current position matches the total length.
		if (pos != len)
		{
			MS_WARN_TAG(ice, "computed packet size does not match total size, packet discarded");

			delete packet;
			return nullptr;
		}

		// If it has FINGERPRINT attribute then verify it.
		if (hasFingerprint)
		{
			// Compute the CRC32 of the received packet up to (but excluding) the
			// FINGERPRINT attribute and XOR it with 0x5354554e.
			uint32_t computedFingerprint = Utils::Crypto::GetCRC32(data, fingerprintAttrPos) ^ 0x5354554e;

			// Compare with the FINGERPRINT value in the packet.
			if (fingerprint != computedFingerprint)
			{
				MS_WARN_TAG(
				  ice,
				  "computed FINGERPRINT value does not match the value in the packet, "
				  "packet discarded");

				delete packet;
				return nullptr;
			}
		}

		return packet;
	}

#编码


	void StunPacket::Serialize(uint8_t* buffer)
	{
		MS_TRACE();

		// Some useful variables.
		uint16_t usernamePaddedLen{ 0 };
		uint16_t xorMappedAddressPaddedLen{ 0 };
		bool addXorMappedAddress =
		  ((this->xorMappedAddress != nullptr) && this->method == StunPacket::Method::BINDING &&
		   this->klass == Class::SUCCESS_RESPONSE);
		bool addErrorCode        = ((this->errorCode != 0u) && this->klass == Class::ERROR_RESPONSE);
		bool addMessageIntegrity = (this->klass != Class::ERROR_RESPONSE && !this->password.empty());
		bool addFingerprint{ true }; // Do always.

		// Update data pointer.
		this->data = buffer;

		// First calculate the total required size for the entire packet.
		this->size = 20; // Header.

		if (!this->username.empty())
		{
			usernamePaddedLen = Utils::Byte::PadTo4Bytes(static_cast(this->username.length()));
			this->size += 4 + usernamePaddedLen;
		}

		if (this->priority != 0u)
			this->size += 4 + 4;

		if (this->iceControlling != 0u)
			this->size += 4 + 8;

		if (this->iceControlled != 0u)
			this->size += 4 + 8;

		if (this->hasUseCandidate)
			this->size += 4;

		if (addXorMappedAddress)
		{
			switch (this->xorMappedAddress->sa_family)
			{
				case AF_INET:
				{
					xorMappedAddressPaddedLen = 8;
					this->size += 4 + 8;

					break;
				}

				case AF_INET6:
				{
					xorMappedAddressPaddedLen = 20;
					this->size += 4 + 20;

					break;
				}

				default:
				{
					MS_ERROR("invalid inet family in XOR-MAPPED-ADDRESS attribute");

					addXorMappedAddress = false;
				}
			}
		}

		if (addErrorCode)
			this->size += 4 + 4;

		if (addMessageIntegrity)
			this->size += 4 + 20;

		if (addFingerprint)
			this->size += 4 + 4;

		// Merge class and method fields into type.
		uint16_t typeField = (static_cast(this->method) & 0x0f80) << 2;

		typeField |= (static_cast(this->method) & 0x0070) << 1;
		typeField |= (static_cast(this->method) & 0x000f);
		typeField |= (static_cast(this->klass) & 0x02) << 7;
		typeField |= (static_cast(this->klass) & 0x01) << 4;

		// Set type field.
		Utils::Byte::Set2Bytes(buffer, 0, typeField);
		// Set length field.
		Utils::Byte::Set2Bytes(buffer, 2, static_cast(this->size) - 20);
		// Set magic cookie.
		std::memcpy(buffer + 4, StunPacket::magicCookie, 4);
		// Set TransactionId field.
		std::memcpy(buffer + 8, this->transactionId, 12);
		// Update the transaction ID pointer.
		this->transactionId = buffer + 8;
		// Add atributes.
		size_t pos{ 20 };

		// Add USERNAME.
		if (usernamePaddedLen != 0u)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::USERNAME));
			Utils::Byte::Set2Bytes(buffer, pos + 2, static_cast(this->username.length()));
			std::memcpy(buffer + pos + 4, this->username.c_str(), this->username.length());
			pos += 4 + usernamePaddedLen;
		}

		// Add PRIORITY.
		if (this->priority != 0u)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::PRIORITY));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 4);
			Utils::Byte::Set4Bytes(buffer, pos + 4, this->priority);
			pos += 4 + 4;
		}

		// Add ICE-CONTROLLING.
		if (this->iceControlling != 0u)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::ICE_CONTROLLING));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 8);
			Utils::Byte::Set8Bytes(buffer, pos + 4, this->iceControlling);
			pos += 4 + 8;
		}

		// Add ICE-CONTROLLED.
		if (this->iceControlled != 0u)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::ICE_CONTROLLED));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 8);
			Utils::Byte::Set8Bytes(buffer, pos + 4, this->iceControlled);
			pos += 4 + 8;
		}

		// Add USE-CANDIDATE.
		if (this->hasUseCandidate)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::USE_CANDIDATE));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 0);
			pos += 4;
		}

		// Add XOR-MAPPED-ADDRESS
		if (addXorMappedAddress)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::XOR_MAPPED_ADDRESS));
			Utils::Byte::Set2Bytes(buffer, pos + 2, xorMappedAddressPaddedLen);

			uint8_t* attrValue = buffer + pos + 4;

			switch (this->xorMappedAddress->sa_family)
			{
				case AF_INET:
				{
					// Set first byte to 0.
					attrValue[0] = 0;
					// Set inet family.
					attrValue[1] = 0x01;
					// Set port and XOR it.
					std::memcpy(
					  attrValue + 2,
					  &(reinterpret_cast(this->xorMappedAddress))->sin_port,
					  2);
					attrValue[2] ^= StunPacket::magicCookie[0];
					attrValue[3] ^= StunPacket::magicCookie[1];
					// Set address and XOR it.
					std::memcpy(
					  attrValue + 4,
					  &(reinterpret_cast(this->xorMappedAddress))->sin_addr.s_addr,
					  4);
					attrValue[4] ^= StunPacket::magicCookie[0];
					attrValue[5] ^= StunPacket::magicCookie[1];
					attrValue[6] ^= StunPacket::magicCookie[2];
					attrValue[7] ^= StunPacket::magicCookie[3];

					pos += 4 + 8;

					break;
				}

				case AF_INET6:
				{
					// Set first byte to 0.
					attrValue[0] = 0;
					// Set inet family.
					attrValue[1] = 0x02;
					// Set port and XOR it.
					std::memcpy(
					  attrValue + 2,
					  &(reinterpret_cast(this->xorMappedAddress))->sin6_port,
					  2);
					attrValue[2] ^= StunPacket::magicCookie[0];
					attrValue[3] ^= StunPacket::magicCookie[1];
					// Set address and XOR it.
					std::memcpy(
					  attrValue + 4,
					  &(reinterpret_cast(this->xorMappedAddress))->sin6_addr.s6_addr,
					  16);
					attrValue[4] ^= StunPacket::magicCookie[0];
					attrValue[5] ^= StunPacket::magicCookie[1];
					attrValue[6] ^= StunPacket::magicCookie[2];
					attrValue[7] ^= StunPacket::magicCookie[3];
					attrValue[8] ^= this->transactionId[0];
					attrValue[9] ^= this->transactionId[1];
					attrValue[10] ^= this->transactionId[2];
					attrValue[11] ^= this->transactionId[3];
					attrValue[12] ^= this->transactionId[4];
					attrValue[13] ^= this->transactionId[5];
					attrValue[14] ^= this->transactionId[6];
					attrValue[15] ^= this->transactionId[7];
					attrValue[16] ^= this->transactionId[8];
					attrValue[17] ^= this->transactionId[9];
					attrValue[18] ^= this->transactionId[10];
					attrValue[19] ^= this->transactionId[11];

					pos += 4 + 20;

					break;
				}
			}
		}

		// Add ERROR-CODE.
		if (addErrorCode)
		{
			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::ERROR_CODE));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 4);

			auto codeClass     = static_cast(this->errorCode / 100);
			uint8_t codeNumber = static_cast(this->errorCode) - (codeClass * 100);

			Utils::Byte::Set2Bytes(buffer, pos + 4, 0);
			Utils::Byte::Set1Byte(buffer, pos + 6, codeClass);
			Utils::Byte::Set1Byte(buffer, pos + 7, codeNumber);
			pos += 4 + 4;
		}

		// Add MESSAGE-INTEGRITY.
		if (addMessageIntegrity)
		{
			// Ignore FINGERPRINT.
			if (addFingerprint)
				Utils::Byte::Set2Bytes(buffer, 2, static_cast(this->size - 20 - 8));

			// Calculate the HMAC-SHA1 of the packet according to MESSAGE-INTEGRITY rules.
			const uint8_t* computedMessageIntegrity =
			  Utils::Crypto::GetHmacShA1(this->password, buffer, pos);

			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::MESSAGE_INTEGRITY));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 20);
			std::memcpy(buffer + pos + 4, computedMessageIntegrity, 20);

			// Update the pointer.
			this->messageIntegrity = buffer + pos + 4;
			pos += 4 + 20;

			// Restore length field.
			if (addFingerprint)
				Utils::Byte::Set2Bytes(buffer, 2, static_cast(this->size - 20));
		}
		else
		{
			// Unset the pointer (if it was set).
			this->messageIntegrity = nullptr;
		}

		// Add FINGERPRINT.
		if (addFingerprint)
		{
			// Compute the CRC32 of the packet up to (but excluding) the FINGERPRINT
			// attribute and XOR it with 0x5354554e.
			uint32_t computedFingerprint = Utils::Crypto::GetCRC32(buffer, pos) ^ 0x5354554e;

			Utils::Byte::Set2Bytes(buffer, pos, static_cast(Attribute::FINGERPRINT));
			Utils::Byte::Set2Bytes(buffer, pos + 2, 4);
			Utils::Byte::Set4Bytes(buffer, pos + 4, computedFingerprint);
			pos += 4 + 4;

			// Set flag.
			this->hasFingerprint = true;
		}
		else
		{
			this->hasFingerprint = false;
		}

		MS_ASSERT(pos == this->size, "pos != this->size");
	}

 

你可能感兴趣的:(音视频处理)