最新live555優化擴展ipv6功能支持蘋果版本應用上架AppStore

live555的發展歷史實在是非常悠久,保守估計已經發展了至少18年以上了,同時,這也導致了live555在很多架構和考慮上面不能滿足現代化的多線程、ipv6方面的需求,雖然官方也開啓了對ipv6功能支持的衆籌,但是已經很久了,預計很長時間內是不會有這個計劃支持了,因爲要改動的地方還真是蠻多的:
live555
今天我們要來聊一下我們在live555擴展IPv6方面是怎麼做到的!

設計過程

  1. IPV4 地址
    rtsp://192.168.1.100:554/ch1
    rtsp://admin:[email protected]:554/ch1

  2. IPV6 地址
    rtsp://[2001:0:9d38:953c:38b0:d177:88d8:a5e0]:554/ch1
    rtsp://admin:12345@[2001:0:9d38:953c:38b0:d177:88d8:a5e0]:554/ch1

  3. 支持IPv6修改步驟
    增加live_ipv4_ipv6.h和live_ipv4_ipv6.cpp兩個文件
    用途: 在live所有用到類型爲netAddressBits的文件中,包含該頭文件,針對ipv4和ipv6進行不同的處理;

  • live_ipv4_ipv6.h

    #ifndef __LIVE_IPV4_IPV6
    #define __LIVE_IPV4_IPV6

    typedef enum LIVE_IPVER_ENUM
    {
    LIVE_IP_VER_4 = 0,
    LIVE_IP_VER_6
    }LIVE_IP_VER_ENUM;

    extern LIVE_IP_VER_ENUM live_ip_ver;

    #endif

  • live_ipv4_ipv6.cpp

    #include “live_ipv4_ipv6.h”
    LIVE_IP_VER_ENUM live_ip_ver = LIVE_IP_VER_6;

  • NetAddress.hh

增加以下定義, 並註釋掉typedef u_int32_t netAddressBits;
typedef struct __LIVE_NET_ADDRESS_INADDR
{
	struct in_addr sin_addr;
	struct in6_addr sin6_addr;

	__LIVE_NET_ADDRESS_INADDR()
	{
		sin_addr.s_addr = INADDR_ANY;
		sin6_addr = in6addr_any;
	};

}LIVE_NET_ADDRESS_INADDR;

//typedef u_int32_t netAddressBits;	//註釋掉該句,在所有用到netAddressBits的地方,均用LIVE_NET_ADDRESS_INADDR替代;

//增加以下定義
typedef struct __LIVE_NET_ADDRESS_SOCKADDR_IN
{
	struct sockaddr_in	saddr4;
	struct sockaddr_in6	saddr6;
}LIVE_NET_ADDRESS_SOCKADDR_IN;

將所有struct in_addr 改爲 LIVE_NET_ADDRESS, 除了以下幾處:
void AddressString::init(struct in_addr addr)

將所有struct sockaddr_in 改爲 LIVE_NET_ADDRESS_SOCKADDR_IN;

在EasyRTSPClient的live555中,將調用到LIVE_NET_ADDRESS_SOCKADDR_IN的函數,增加一個參數,用於標識是IPv4還是IPv6;
從調用以下代碼開始,進行區分,用於標識該客戶端需要使用IPv4還是IPv6進行連接;

Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url,
				 char*& username, char*& password,
				 NetAddress& address,
				 portNumBits& portNum,
				 char const** urlSuffix) {

		do {
		// Parse the URL as "rtsp://[<username>[:<password>]@]<server-address-or-name>[:<port>][/<stream-name>]"
		char const* prefix = "rtsp://";
		unsigned const prefixLength = 7;
		if (_strncasecmp(url, prefix, prefixLength) != 0) {
			env.setResultMsg("URL is not of the form \"", prefix, "\"");
			break;
		}

		unsigned const parseBufferSize = 100;
		char parseBuffer[parseBufferSize] = {0};
		char const* from = &url[prefixLength];

		// Check whether "<username>[:<password>]@" occurs next.
		// We do this by checking whether '@' appears before the end of the URL, or before the first '/'.
		username = password = NULL; // default return values
		char const* colonPasswordStart = NULL;
		char const* p;
        //此處檢查字符[
		for (p = from; *p != '\0' && *p != '/' && *p != '['; ++p) {
			if (*p == ':' && colonPasswordStart == NULL) {
		colonPasswordStart = p;
			} else if (*p == '@') {
		// We found <username> (and perhaps <password>).  Copy them into newly-allocated result strings:
		if (colonPasswordStart == NULL) colonPasswordStart = p;

		char const* usernameStart = from;
		unsigned usernameLen = colonPasswordStart - usernameStart;
		username = new char[usernameLen + 1] ; // allow for the trailing '\0'
		copyUsernameOrPasswordStringFromURL(username, usernameStart, usernameLen);

		char const* passwordStart = colonPasswordStart;
		if (passwordStart < p) ++passwordStart; // skip over the ':'
		unsigned passwordLen = p - passwordStart;
		password = new char[passwordLen + 1]; // allow for the trailing '\0'
		copyUsernameOrPasswordStringFromURL(password, passwordStart, passwordLen);

		from = p + 1; // skip over the '@'
		break;
			}
		}

		// Next, parse <server-address-or-name>
		char* to = &parseBuffer[0];
		unsigned i;

		live_ip_ver = LIVE_IP_VER_4;	//默認爲IPv4
		if (*from == '[')		//如果地址是以符號[開頭,則爲IPv6  因爲ipv6的地址是以符號[開頭
		{
			live_ip_ver = LIVE_IP_VER_6;
		}

		if (live_ip_ver == LIVE_IP_VER_6)
		{
			*from ++;	//  跳過符號[
			for (i = 0; i < parseBufferSize; ++i) {
				if (*from == '\0' || *from == ']' || *from == '/') {
			// We've completed parsing the address
			*to = '\0';
			break;
				}
				*to++ = *from++;
			}
			if (i == parseBufferSize) {
				env.setResultMsg("URL is too long");
				break;
			}

			*from ++;		//  跳過符號]
		}
		else		//IPV4
		{
			for (i = 0; i < parseBufferSize; ++i) {
				if (*from == '\0' || *from == ':' || *from == '/') {
			// We've completed parsing the address
			*to = '\0';
			break;
				}
				*to++ = *from++;
			}
			if (i == parseBufferSize) {
				env.setResultMsg("URL is too long");
				break;
			}
		}
		//rtsp://[2001:0:9d38:953c:14b3:7a:3f57:fe40]:554/ch1
		//strcpy(parseBuffer, "2001:0:9d38:953c:38b0:d177:88d8:a5e0");

		NetAddressList addresses(parseBuffer);
		if (addresses.numAddresses() == 0) {
			env.setResultMsg("Failed to find network address for \"",
					parseBuffer, "\"");
			break;
		}
		address = *(addresses.firstAddress());

		portNum = 554; // default value

		char nextChar = *from;
		if (nextChar == ':') {
			int portNumInt;
			if (sscanf(++from, "%d", &portNumInt) != 1) {
		env.setResultMsg("No port number follows ':'");
		break;
			}
			if (portNumInt < 1 || portNumInt > 65535) {
		env.setResultMsg("Bad port number");
		break;
			}
			portNum = (portNumBits)portNumInt;
			while (*from >= '0' && *from <= '9') ++from; // skip over port number
		}

		// The remainder of the URL is the suffix:
		if (urlSuffix != NULL) *urlSuffix = from;

		return True;
		} while (0);

  return False;
}

其中, live_ip_ver 爲全局變量,用於標識該IP地址類型;
後面用到struct sockaddr_in 和 struct in_addr 的地方, 使用LIVE_NET_ADDRESS_SOCKADDR_IN來區分,並進行相應的處理;

live555中,就不能使用live_ip_ver這個全局變量了, 因爲要同時兼容IPv4和IPv6, 將在下篇說明;

live555-ipv6

重要性

live555的ipv6技術雖然是很小的一個點,但是在越來越物聯網的現在,無論是上架AppStore還是投標競標,ipv6都將成爲一個關鍵的技術點;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章