zoukankan      html  css  js  c++  java
  • 成功扩展live555支持ipv6,同时支持RTSPServer & RTSPClient

    live555对ipv6的扩展

    从live555的官网看live555的发展历史,实在是历史悠久,保守估计已经发展了至少16年以上了,同时,这也导致了live555在很多架构和考虑上面不能满足现代化的多线程、ipv6方面的需求,虽然官方也开启了对ipv6功能支持的众筹,但是已经很久了,预计很长时间内是不会有这个计划支持了,因为要改动的地方还真是蛮多的:

    live555

    ,在上一期中我们已经为live555的多线程开了个头《经过两个多月的攻关,终于搞定了live555多线程并稳定压测通过》,今天我们要来聊一下我们在live555扩展IPv6方面是怎么做到的!

    设计过程

    IPV4 地址

    rtsp://192.168.1.100:554/ch1
    rtsp://admin:12345@192.168.1.100:554/ch1

    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

    支持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中,将调用到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 != '' && *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 ''
            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 ''
            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 == '' || *from == ']' || *from == '/') {
                // We've completed parsing the address
                *to = '';
                break;
                    }
                    *to++ = *from++;
                }
                if (i == parseBufferSize) {
                    env.setResultMsg("URL is too long");
                    break;
                }
    
                *from ++;       //  跳过符号]
            }
            else        //IPV4
            {
                for (i = 0; i < parseBufferSize; ++i) {
                    if (*from == '' || *from == ':' || *from == '/') {
                // We've completed parsing the address
                *to = '';
                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技术交流

    • 邮件:289042893@qq.com

    • live555技术交流群:475947825

  • 相关阅读:
    关于c语言变量的内存分布测试程序
    常用ARM指令集及汇编_破解
    CPU读取内存0x30000000地址4个字节数据
    打印十六进制字符串查看内存地址
    JZ2440串口打印字符作为调试
    搭建Linux3.4.2内核编辑环境
    网卡驱动程序
    同步互斥阻塞
    poll机制分析[转]
    安装、配置、启动FTP、SSH或NFS服务
  • 原文地址:https://www.cnblogs.com/babosa/p/8996605.html
Copyright © 2011-2022 走看看