iOS - 网络处理iOS - 大杂烩程序员

PJSIP2.6支持IPv6笔记

2017-07-23  本文已影响428人  14bf7199f818

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 - 优化/质量]

上一篇 下一篇

猜你喜欢

热点阅读