我正在尝试让PJSIP在我的iOS项目中工作以连接到我的Asterisk服务器。我使用wireshark进行了数据包捕获,由于某种原因,PJSIP没有像应有的那样响应401挑战。

更奇怪的是,这种情况确实很少见。就像正在发生某种竞争状况一样,但这全部存在于PJSIP本身中。因为我只想...

pjsua_acc_add(&accountConfig, PJ_TRUE, &accID);


然后由PJSIP库执行其操作。

这是数据包捕获的一个片段。10.200.0.72是我的Asterisk服务器。 10.200.154.118是我的测试iOS设备。

REGISTER sip:10.200.0.72 SIP/2.0
Via: SIP/2.0/UDP 10.200.154.118:5080;rport;branch=z9hG4bKPjLjNBXVcaqqPqYVtTR2GDEQJhhGYG7Fo3
Max-Forwards: 70
From: <sip:[email protected]>;tag=JgDAcidZf0Ew-Jqgei0Am3Znyl2SEFg.
To: <sip:[email protected]>
Call-ID: hTMu0Vi.Kte6PntnMJdxQmeBWtKdXZd0
CSeq: 59555 REGISTER
Contact: <sip:[email protected]:5080;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length:  0

REGISTER sip:10.200.0.72 SIP/2.0
Via: SIP/2.0/UDP 10.200.154.118:5080;rport;branch=z9hG4bKPjLjNBXVcaqqPqYVtTR2GDEQJhhGYG7Fo3
Max-Forwards: 70
From: <sip:[email protected]>;tag=JgDAcidZf0Ew-Jqgei0Am3Znyl2SEFg.
To: <sip:[email protected]>
Call-ID: hTMu0Vi.Kte6PntnMJdxQmeBWtKdXZd0
CSeq: 59555 REGISTER
Contact: <sip:[email protected]:5080;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length:  0

SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 10.200.154.118:5080;rport=5080;received=10.200.154.118;branch=z9hG4bKPjLjNBXVcaqqPqYVtTR2GDEQJhhGYG7Fo3
Call-ID: hTMu0Vi.Kte6PntnMJdxQmeBWtKdXZd0
From: <sip:[email protected]>;tag=JgDAcidZf0Ew-Jqgei0Am3Znyl2SEFg.
To: <sip:[email protected]>;tag=z9hG4bKPjLjNBXVcaqqPqYVtTR2GDEQJhhGYG7Fo3
CSeq: 59555 REGISTER
WWW-Authenticate: Digest  realm="asterisk",nonce="1485330086/50f04167f65383db99f5c0cf17651984",opaque="73b3a6a8599485f8",algorithm=md5,qop="auth"
Server: FPBX-13.0.190.11(13.12.1)
Content-Length:  0

SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 10.200.154.118:5080;rport=5080;received=10.200.154.118;branch=z9hG4bKPjLjNBXVcaqqPqYVtTR2GDEQJhhGYG7Fo3
Call-ID: hTMu0Vi.Kte6PntnMJdxQmeBWtKdXZd0
From: <sip:[email protected]>;tag=JgDAcidZf0Ew-Jqgei0Am3Znyl2SEFg.
To: <sip:[email protected]>;tag=z9hG4bKPjLjNBXVcaqqPqYVtTR2GDEQJhhGYG7Fo3
CSeq: 59555 REGISTER
WWW-Authenticate: Digest  realm="asterisk",nonce="1485330086/50f04167f65383db99f5c0cf17651984",opaque="73b3a6a8599485f8",algorithm=md5,qop="auth"
Server: FPBX-13.0.190.11(13.12.1)
Content-Length:  0


这是我的OBJ-C代码,用于实现此目标...

- (void) startAndRegisterOnServer:(NSString *)sipDomain withUserName:(NSString *)sipUser andPassword:(NSString *)password success:(void (^)(void))success failure:(void (^)(int errorCode, NSString *errorMessage))failure
{
    pj_status_t status;

    status = pjsua_create();

    if (status != PJ_SUCCESS)
    {
        failure (status, @"Error in pjsua_create");

        return;
    }

    // Setup Config and Initialize

    pjsua_config config;
    pjsua_config_default (&config);

    config.cb.on_incoming_call = &on_incoming_call;
    config.cb.on_call_media_state = &on_call_media_state;
    config.cb.on_call_state = &on_call_state;
    config.cb.on_reg_state2 = &on_reg_state2;

    pjsua_logging_config logConfig;
    pjsua_logging_config_default(&logConfig);
    logConfig.console_level = 5;

    status = pjsua_init(&config, &logConfig, NULL);

    if (status != PJ_SUCCESS)
    {
        failure (status, @"Error in pjsua_init");

        return;
    }

    // Add UDP transport

    pjsua_transport_config udpTransportConfig;
    pjsua_transport_config_default(&udpTransportConfig);
    udpTransportConfig.port = 5080;

    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &udpTransportConfig, NULL);

    if (status != PJ_SUCCESS)
    {
        failure (status, @"Error adding UDP transport");

        return;
    }

    // Add TCP transport.

    pjsua_transport_config tcpTransportConfig;
    pjsua_transport_config_default(&tcpTransportConfig);
    tcpTransportConfig.port = 5080;

    status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &tcpTransportConfig, NULL);

    if (status != PJ_SUCCESS)
    {
        failure (status, @"Error adding TCP transport");

        return;
    }

    // Startup PJSUA

    status = pjsua_start();

    if (status != PJ_SUCCESS)
    {
        failure (status, @"Error starting PJSUA");

        return;
    }

    // Register with SIP Server

    pjsua_acc_config accountConfig;
    pjsua_acc_config_default(&accountConfig);

    // Account ID

    char sipAccount [MAX_SIP_ACCOUNT_LENGTH];
    sprintf (sipAccount, "sip:%s@%s", [sipUser UTF8String], [sipDomain UTF8String]);
    accountConfig.id = pj_str(sipAccount);

    // Register URI

    char regUri[MAX_SIP_REGISTER_URI_LENGTH];
    sprintf(regUri, "sip:%s", [sipDomain UTF8String]);
    accountConfig.reg_uri = pj_str(regUri);

    // Set the credentials in accountConfig

    accountConfig.cred_count = 1;
    accountConfig.cred_info[0].scheme = pj_str("digest");
    accountConfig.cred_info[0].realm = pj_str("asterisk");
    accountConfig.cred_info[0].username = pj_str((char *)[sipUser UTF8String]);
    accountConfig.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
    accountConfig.cred_info[0].data = pj_str((char *)[password UTF8String]);

    pjsua_acc_id accID;

    status = pjsua_acc_add(&accountConfig, PJ_TRUE, &accID);

    [PJSIPInterfaceManager sharedInstance].accountID = accID;

    if (status != PJ_SUCCESS)
    {
        failure (status, @"Error registering account with server");

        return;
    }

    success();
}


有什么想法吗?同样,在极少数情况下,我可以使它工作,但它就像50次中的1次。



**更新**



因此经过大量的故障排除。我相信这可能与NAT有关。我有两台服务器。一个位于我的网络内部,这是此示例基于(10.200.0.72)和一台外部服务器的基础。但是我在两台服务器上都有问题。因此,接下来是我使用外部Asterisk服务器进行的通宵测试。我让我的iOS客户端整夜运行,但无法注册。它设置为默认的5分钟重试。这是因为CSeq没有增加时,它始终一直在重新发送同一数据包。然后在深夜,客户端终于连接了。

在日志中,我注意到了这一点...

04:19:22.706    pjsua_acc.c  ...SIP registration failed, status=408 (Request Timeout)
04:24:20.767    pjsua_acc.c  ....IP address change detected for account 0 (10.200.154.118:5080 --> [MY EXTERNAL IP]:31943). Updating registration (using method 4)
04:24:20.810    pjsua_acc.c  ....sip:100@[EXTERNAL ASTERISK IP]: registration success, status=200 (OK), will re-register in 300 seconds


请注意,我编辑了外部Asterisk服务器的IP和公共IP。

您会在第二行看到PJSIP客户端注意到我的IP已更改。实际上,设备保留了10.200.154.118。但是由于某种原因,它突然开始在数据包的VIA线路中为路由器发送我的公共IP。然后,您可以在下一行中看到它已成功注册。

这是数据包捕获中的VIA行...

从:

Via: SIP/2.0/UDP 10.200.154.118:5080;rport;branch=z9hG4bKPjegwWD-UEDhH3c5cShdumEEbKvfmK45Zl


至:

Via: SIP/2.0/UDP [MY EXTERNAL IP]:31943;rport;branch=z9hG4bKPjxcKgVfSngqxxTy7MnGhZU5Y3RrjpczNr


CSeq编号也最终增加,并且发送了Authorization标头。

然后大约3小时20分钟后,它又回到了失败状态。但是它仍在使用我的外部IP(它没有还原回它的10个地址。)这是在服务器发送大量OPTIONS消息之后。连续20个小时,客户没有回应...

OPTIONS sip:100@[MY EXTERNAL IP]:31943;ob SIP/2.0
Via: SIP/2.0/UDP [EXTERNAL ASTERISK IP]:5060;branch=z9hG4bK6128eaf9;rport
Max-Forwards: 70
From: "Unknown" <sip:Unknown@[EXTERNAL ASTERISK IP]>;tag=as165c224d
To: <sip:100@[MY EXTERNAL IP]:31943;ob>
Contact: <sip:Unknown@[EXTERNAL ASTERISK IP]:5060>
Call-ID: 341a15d536c3a3b45a73567056e34b6b@[EXTERNAL ASTERISK IP]:5060
CSeq: 102 OPTIONS
User-Agent: Mozilla
Date: Fri, 27 Jan 2017 14:45:48 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Content-Length: 0


老实说,我不知道此OPTION消息的全部含义。但是在连续执行约20个操作后,随后的REGISTER失败了,并继续这样做。

我也刚注意到一些东西。该端口从客户端上的静态5080侦听端口更改为随机动态端口。您会在两条VIA行中看到这一点。这使我认为,即使我在网络中看到该数据包,也不会到达客户端,因为它没有在该端口上侦听?我应该在客户端上设置任何配置以解决此问题?

有什么见解吗?

最佳答案

前一段时间我在PJSIP上工作。我将启动代码与现有代码进行了比较,这里有些差异。不确定是否会有所帮助。

在顶部,我做一个:

    if (pjsua_acc_get_count() > 0)
    {
        [self unregisterAccount];
    }


有点下降:

    accountConfig.reg_timeout          = 110;
    accountConfig.ka_interval           = 5;
    accountConfig.allow_contact_rewrite = 0;


最后,这是unregisterAccount方法:

- (void)unregisterAccount
{
    @synchronized(self)
    {
        pj_status_t status;
        unsigned    count;

        [self registerThread];

        count = pjsua_acc_get_count();

        if (count > 0)
        {
            pjsua_acc_info* info = calloc(count, sizeof(pjsua_acc_info));

            for (int n = 0; n < count; n++)
            {
                status = pjsua_acc_enum_info(info, &count);

                if (status == PJ_SUCCESS)
                {
                    status = pjsua_acc_del(info[n].id);
                    if (status != PJ_SUCCESS)
                    {
                        NSLog(@"Unregister unsuccessful");
                    }
                }
            }

            free(info);
        }

        accountId = -1;
    }
}


我希望这会有所帮助,但我想不会。并非只有您一个人,PJSIP和SIP通常很难在每种情况下都能正常工作。祝您成功!

如果没有帮助,我想PJSIP的论坛仍在工作吗?

关于ios - PJSIP不响应身份验证到401,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41846403/

10-12 14:31