PJSIP2.6支持IPv6笔记

作者: 14bf7199f818 | 来源:发表于2017-07-23 07:57 被阅读428次

    PJSIP2.6支持IPv6笔记

    ��前段时间做了一个Voip的应用,在上架时�因为IPv6的原因连续被拒三次,��网上试了很多���方法,都没能成功,当时真是心力交瘁。最终在google的帮助下顺利解决了IPv6问题并成功上架。希望这篇文章能帮助后来人能少走弯路。

    编译�支持IPv6的�静态库

    �下载pjsip源码,在pjsip目录pjlib/include/pj/config_site.h中添加: #define PJ_HAS_IPV6 1,然后重新编译生成支持��IPv6的静态库

    �具体编译��步骤可参考:

    Getting Started: Building for Apple iPhone, iPad and iPod Touch

    pjsip for iOS:编译多平台支持的静态库

    �在PJSUA中添加IPv6支持

    �选择TCP,UDP时,首先得�确认SIP�服务器支持UDP协议还是TCP协议。��然后�服务器地址�不能用IPv4地址,需要改为域名。

    pjsua_transport_config tp_cfg;
    pjsip_transport_type_e tp_type;
    pjsua_transport_id     tp_id = -1;
    
    pjsua_transport_config_default(&tp_cfg);
    tp_cfg.port = 5060;
    
    /* TCP */
    tp_type = PJSIP_TRANSPORT_TCP6;
    status = pjsua_transport_create(tp_type, &tp_cfg, &tp_id);
    if (status != PJ_SUCCESS)
        ...
    
    /* UDP */
    tp_type = PJSIP_TRANSPORT_UDP6;
    status = pjsua_transport_create(tp_type, &tp_cfg, &tp_id);
    if (status != PJ_SUCCESS)
    
    acc_cfg.transport_id = udp6_tp_id; // udp6_tp_id is an UDP IPv6 transport ID, e.g: outputed by
                                       // pjsua_transport_create(PJSIP_TRANSPORT_UDP6, ..., &udp6_tp_id)
    
    /* Enable IPv6 in media transport */
    acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED;
    
    /* Finally */
    status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL);
    if (status != PJ_SUCCESS)
    
    

    这是从pjsip官方文档复制过来的代码片段,��详细的��代码请查阅pjsip IPv6 支持

    �走到这一步,没问题的话,�在IPv6环境下�可以进行SIP���注册,但是不能打电话和接电话。

    ����用PJ-nat64�临时解决IPv6�问题

    ��pjsip�开启��IPv6支持不能打电话和接电话。最后无发现有pj-nat64�开源代码,尝试后在IPv6环境能成功解决打电话和接电话功能,并不需要服务器做其它的处理。地址:pj-nat64

    �pj-nat64�集成��步骤

    pj-nat64.cpj-nat64.h放进项目中,然后�在合适的地方启用。在启动pjsip的地方,加上这段代码。可以�通过判断在IPv6��环境下再启用pj-nat64。判断IPv6的代码,��见文章未。

        pj_nat64_enable_rewrite_module();
    

    on_reg_state回调中,打开PJSUA�_IPV6_ENABLED属性,并激活PJ_NAT64重写。

        if (isIPv6) {
            yourAccountConfig.ipv6_media_use = PJSUA_IPV6_ENABLED;
            pj_nat64_set_options(NAT64_REWRITE_ROUTE_AND_CONTACT);
        }
    

    代码需要按照自己的情况进行适配修改。

    �问题�排�错

    �Sip在IPv6上的消息体

    ���贴上正确的Sip IPv6消息体,以检查�SIP�消息是否正确,以排错,�报文数据摘自IE�TF - Sip Test Messages on IPv6

    注册

    // Message Details: reg-good
    
        REGISTER sip:[2001:db8::10] SIP/2.0
        To: sip:user@example.com
        From: sip:user@example.com;tag=81x2
        Via: SIP/2.0/UDP [2001:db8::9:1];branch=z9hG4bKas3-111
        Call-ID: SSG9559905523997077@hlau_4100
        Contact: "Caller" <sip:caller@[2001:db8::1]>
        CSeq: 98176 REGISTER
        Content-Length: 0
    

    加上端口

    // Message Details: reg-good-port
    
        REGISTER sip:[2001:db8::10]:5070 SIP/2.0
        To: sip:user@example.com
        From: sip:user@example.com;tag=81x2
        Via: SIP/2.0/UDP [2001:db8::9:1];branch=z9hG4bKas3-111
        Call-ID: SSG9559905523997077@hlau_4100
        Contact: "Caller" <sip:caller@[2001:db8::1]>
        CSeq: 98176 REGISTER
        Content-Length: 0
    

    IPv6的SIP请求放在SDP消息体中

    // Message Details: inv-good
    
        INVITE sip:user@[2001:db8::10] SIP/2.0
        To: sip:user@[2001:db8::10]
        From: sip:user@example.com;tag=81x2
        Via: SIP/2.0/UDP [2001:db8::9:1];branch=z9hG4bKas3-111
        Call-ID: SSG9559905523997077@hlau_4100
        Contact: "Caller" <sip:caller@[2001:db8::1]>
        CSeq: 8612 INVITE
        Content-Type: application/sdp
        Content-Length: 268
    
        v=0
        o=assistant 971731711378798081 0 IN IP6 2001:db8::20
        s=Live video feed for today's meeting
        c=IN IP6 2001:db8::1
        t=3338481189 3370017201
        m=audio 6000 RTP/AVP 2
        a=rtpmap:2 G726-32/8000
        m=video 6024 RTP/AVP 107
        a=rtpmap:107 H263-1998/90000
    

    IPv6的bye请求

    // Message Details: bye-good
    
        BYE sip:user@host.example.com SIP/2.0
        Via: SIP/2.0/UDP [2001:db8::9:1]:6050;branch=z9hG4bKas3-111
        Via: SIP/2.0/UDP 192.0.2.1;branch=z9hG4bKjhja8781hjuaij65144
        Via: SIP/2.0/TCP [2001:db8::9:255];branch=z9hG4bK451jj;
          received=192.0.2.200
        Call-ID: 997077@lau_4100
        CSeq: 89187 BYE
        To: sip:user@example.net;tag=9817--94
        From: sip:user@example.com;tag=81x2
    

    �判断IPv6��环境代码

    当时项目时间急,就在网上Copy了这段代码,现在已无法知道原出处,对�原作者表示抱歉。

    
    #define IOS_CELLULAR    @"pdp_ip0"
    #define IOS_WIFI        @"en0"
    #define IOS_VPN         @"utun0"
    #define IP_ADDR_IPv4    @"ipv4"
    #define IP_ADDR_IPv6    @"ipv6"
    #import <ifaddrs.h>
    #import <arpa/inet.h>
    #import <net/if.h>
    
    + (BOOL)isIpv6{
        NSArray *searchArray =
        @[ IOS_VPN @"/" IP_ADDR_IPv6,
           IOS_VPN @"/" IP_ADDR_IPv4,
           IOS_WIFI @"/" IP_ADDR_IPv6,
           IOS_WIFI @"/" IP_ADDR_IPv4,
           IOS_CELLULAR @"/" IP_ADDR_IPv6,
           IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
        
        NSDictionary *addresses = [self getIPAddresses];
        NSLog(@"addresses: %@", addresses);
        
        __block BOOL isIpv6 = NO;
        [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
         {
             NSLog(@"---%@---%@---",key, addresses[key] );
             
             if ([key rangeOfString:@"ipv6"].length > 0  && ![[NSString stringWithFormat:@"%@",addresses[key]] hasPrefix:@"(null)"] ) {
                 
                 if ( ![addresses[key] hasPrefix:@"fe80"]) {
                     isIpv6 = YES;
                 }
             }
             
         } ];
        
        return isIpv6;
    }
    
    + (NSDictionary *)getIPAddresses
    {
        NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
        // retrieve the current interfaces - returns 0 on success
        struct ifaddrs *interfaces;
        if(!getifaddrs(&interfaces)) {
            // Loop through linked list of interfaces
            struct ifaddrs *interface;
            for(interface=interfaces; interface; interface=interface->ifa_next) {
                if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                    continue; // deeply nested code harder to read
                }
                const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
                char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
                if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
                    NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                    NSString *type;
                    if(addr->sin_family == AF_INET) {
                        if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                            type = IP_ADDR_IPv4;
                            
                            NSLog(@"ipv4 %@",name);
                        }
                    } else {
                        const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                        if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                            type = IP_ADDR_IPv6;
                            NSLog(@"ipv6 %@",name);
                            
                        }
                    }
                    if(type) {
                        NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                        addresses[key] = [NSString stringWithUTF8String:addrBuf];
                    }
                }
            }
            // Free memory
            freeifaddrs(interfaces);
        }
        return [addresses count] ? addresses : nil;
    }
    
    

    ———————————————————————————————
    自己维护的几个专题,不定期更新高质量文章,欢迎关注!!
    http://www.jianshu.com/c/563ba4d42d38[iOS - 大杂烩]
    http://www.jianshu.com/c/1fee819318a7[iOS - 内存/数据/存储]
    http://www.jianshu.com/c/6a28d1d173b5[iOS - 线程/底层]
    http://www.jianshu.com/c/4dd5a67bbe1d[iOS - 音视频/图文/动画]
    http://www.jianshu.com/c/2de7446d0de9[iOS - 网络处理]
    http://www.jianshu.com/c/5458bca566a9[iOS - 安全/逆向]
    http://www.jianshu.com/c/ca237eb95714[iOS - 优化/质量]

    相关文章

      网友评论

      • 小饼干是只松鼠:请问,这段代码是写在 登录方法里面还是写在 pjsip注册里面?

        pjsua_transport_config tp_cfg;
        pjsip_transport_type_e tp_type;
        pjsua_transport_id tp_id = -1;

        pjsua_transport_config_default(&tp_cfg);
        tp_cfg.port = 5060;

        /* TCP */
        tp_type = PJSIP_TRANSPORT_TCP6;
        status = pjsua_transport_create(tp_type, &tp_cfg, &tp_id);
        if (status != PJ_SUCCESS)
        ...

        /* UDP */
        tp_type = PJSIP_TRANSPORT_UDP6;
        status = pjsua_transport_create(tp_type, &tp_cfg, &tp_id);
        if (status != PJ_SUCCESS)

        acc_cfg.transport_id = udp6_tp_id; // udp6_tp_id is an UDP IPv6 transport ID, e.g: outputed by
        // pjsua_transport_create(PJSIP_TRANSPORT_UDP6, ..., &udp6_tp_id)

        /* Enable IPv6 in media transport */
        acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED;

        /* Finally */
        status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL);
        if (status != PJ_SUCCESS)
        Mnnni:这是连接sip服务
      • 三越:In more detail, an IPv6-only SIP client behind a NAT64 can communicate with IPv6 (or dual stack) server or clients just fine, but will experience problems with IPv4-only server or clients, because there are IPv6 address literals in the SIP/SDP fields (Via, Contact, SDP), which the IPv4 instance cannot understand.
        https://trac.pjsip.org/repos/wiki/IPv6 官网这句话完美解释了pjsip在nat64环境下是不能正常工作的,具体表现是:1.能登录上。2. ipv4端呼叫ipv6端,可以接收到呼叫,但是接听失败。3.ipv6呼叫ipv4,呼不通。
      • Mnnni:使用2.7.1 适配ipv6注册成功后,打电话没有声音,报这个错误 Error sending RTP: Network is unreachable。
        小饼干是只松鼠:问题解决了吗
        14bf7199f818:@Mnnni 2.7的我还没适配,你可以问一下楼上的,他已经测试成功了。
        Mnnni:能不能截取下 注册sip和拨号的完整代码。 谢谢。
      • 倚楼听风雨wing:请问你你升到pjsip2.7了这个方法还有效吗,我用的pjsip2.7发现接通了过后直接挂断了,提示错误:pjmedia_stream_info_from_sdp() failed for call_id 1 media 0: Unsupported address family (PJ_EAFNOTSUP)
        小饼干是只松鼠:@youngliuxx 接通了吗
        倚楼听风雨wing:@youngliuxx 我试了也可以,并且服务器用ipv4的ip也是可以的,谢谢你的文章
        14bf7199f818:pjsip2.7我还没试过.

      本文标题:PJSIP2.6支持IPv6笔记

      本文链接:https://www.haomeiwen.com/subject/smsrnttx.html