具有iOS获取错误的pjusa(PJSIP_ENOCREDENTIAL)[状态=171101]

具有iOS获取错误的pjusa(PJSIP_ENOCREDENTIAL)[状态=171101],ios,voip,pjsip,Ios,Voip,Pjsip,我已经将pjsip构建并链接到iOS项目中,并尝试与服务器连接,但即使在初始连接之后,也会出现身份验证错误 Via: SIP/2.0/UDP 10.43.63.254:5060;rport;branch=z9hG4bKPjyz5KLZ5cAoAaP.96GU5qmAQrGzODseG1 Max-Forwards: 70 From: <sip:1002@10.26.114.254>;tag=ChTUlN6dHJvWFN3YicTHmHefICLRGRdX To: <sip:

我已经将pjsip构建并链接到iOS项目中,并尝试与服务器连接,但即使在初始连接之后,也会出现身份验证错误

Via: SIP/2.0/UDP 10.43.63.254:5060;rport;branch=z9hG4bKPjyz5KLZ5cAoAaP.96GU5qmAQrGzODseG1

Max-Forwards: 70

From: <sip:1002@10.26.114.254>;tag=ChTUlN6dHJvWFN3YicTHmHefICLRGRdX

To: <sip:1002@10.26.114.254>

Call-ID: fWdvvDT-ublTnJ5dUQ0lNd2HHyS4qbKV

CSeq: 54957 REGISTER

Contact: <sip:1002@10.43.63.254:5060;ob>

Expires: 300

Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS

Content-Length:  0




--end msg--
18:33:35.333    pjsua_acc.c  ..Acc 0: Registration sent
18:33:35.348   pjsua_core.c  .RX 649 bytes Response msg 401/REGISTER/cseq=54957 (rdata0x150fe814) from UDP 10.26.114.254:5060:
SIP/2.0 401 Unauthorized

Via: SIP/2.0/UDP 10.43.63.254:5060;rport=5060;branch=z9hG4bKPjyz5KLZ5cAoAaP.96GU5qmAQrGzODseG1

From: <sip:1002@10.26.114.254>;tag=ChTUlN6dHJvWFN3YicTHmHefICLRGRdX

To: <sip:1002@10.26.114.254>;tag=ZBZyaF3DN6Qvm

Call-ID: fWdvvDT-ublTnJ5dUQ0lNd2HHyS4qbKV

CSeq: 54957 REGISTER

User-Agent: FreeSWITCH-mod_sofia/1.4.14+git~20141119T221113Z~ca1d990cfc~64bit

Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY

Supported: timer, path, replaces

WWW-Authenticate: Digest realm="10.26.114.254", nonce="2e1d2722-d226-11e4-b20b-df8fe843b705", algorithm=MD5, qop="auth"

Content-Length: 0




--end msg--
18:33:35.348 sip_auth_clien  ...Unable to set auth for tdta0x150d7000: can not find credential for 10.26.114.254/Digest
18:33:35.348    pjsua_acc.c  ....SIP registration error: No suitable credential (PJSIP_ENOCREDENTIAL) [status=171101]
和c函数

int startPjsip(char *sipUser, char* sipDomain)
{
    pj_status_t status;
    // Create pjsua first
    status = pjsua_create();
    if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status);

    // Init pjsua
    {
        // Init the config structure
        pjsua_config cfg;
        pjsua_config_default (&cfg);

        cfg.cb.on_incoming_call = &on_incoming_call;
        cfg.cb.on_call_media_state = &on_call_media_state;
        cfg.cb.on_call_state = &on_call_state;

        // Init the logging config structure
        pjsua_logging_config log_cfg;
        pjsua_logging_config_default(&log_cfg);
        log_cfg.console_level = 4;

        // Init the pjsua
        status = pjsua_init(&cfg, &log_cfg, NULL);
        if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status);
    }

    // Add UDP transport.
    {
        // Init transport config structure
        pjsua_transport_config cfg;
        pjsua_transport_config_default(&cfg);
        cfg.port = 5060;

        // Add TCP transport.
        status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL);
        if (status != PJ_SUCCESS) error_exit("Error creating transport", status);
    }

    // Add TCP transport.
    {
        // Init transport config structure
        pjsua_transport_config cfg;
        pjsua_transport_config_default(&cfg);
        cfg.port = 5060;

        // Add TCP transport.
        status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg, NULL);
        if (status != PJ_SUCCESS) error_exit("Error creating transport", status);
    }

    // Initialization is done, now start pjsua
    status = pjsua_start();
    if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status);

    // Register the account on local sip server
    {
        pjsua_acc_config cfg;

        pjsua_acc_config_default(&cfg);

        char sipId[MAX_SIP_ID_LENGTH];
        sprintf(sipId, "sip:%s@%s", sipUser, sipDomain);
        cfg.id = pj_str(sipId);

        char regUri[MAX_SIP_REG_URI_LENGTH];
        sprintf(regUri, "sip:%s", sipDomain);
        cfg.reg_uri = pj_str(regUri);

        cfg.cred_info[0].realm = pj_str((char *)"*");

        cfg.cred_info[0].scheme = pj_str((char *)"digest");

        cfg.cred_info[0].username = pj_str((char *)"1002");

        cfg.cred_info[0].data_type = PJSIP_CRED_DATA_EXT_AKA;
        cfg.cred_info[0].data = pj_str((char *)"1234");

        status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id);
        if (status != PJ_SUCCESS) error_exit("Error adding account", status);
    }

    return 0;
}
这是pjusa中的配置结构

/** 
 * This structure describes credential information. 
 * A credential information is a static, persistent information that identifies
 * username and password required to authorize to a specific realm.
 *
 * Note that since PJSIP 0.7.0.1, it is possible to make a credential that is
 * valid for any realms, by setting the realm to star/wildcard character,
 * i.e. realm = pj_str("*");.
 */
struct pjsip_cred_info
{
    pj_str_t    realm;      /**< Realm. Use "*" to make a credential that
                     can be used to authenticate against any
                     challenges.                */
    pj_str_t    scheme;     /**< Scheme (e.g. "digest").            */
    pj_str_t    username;   /**< User name.                 */
    int     data_type;  /**< Type of data (0 for plaintext passwd). */
    pj_str_t    data;       /**< The data, which can be a plaintext 
                     password or a hashed digest.       */

    /** Extended data */
    union {
    /** Digest AKA credential information. Note that when AKA credential
     *  is being used, the \a data field of this #pjsip_cred_info is
     *  not used, but it still must be initialized to an empty string.
     * Please see \ref PJSIP_AUTH_AKA_API for more information.
     */
    struct {
        pj_str_t      k;    /**< Permanent subscriber key.      */
        pj_str_t      op;   /**< Operator variant key.      */
        pj_str_t      amf;  /**< Authentication Management Field    */
        pjsip_cred_cb cb;   /**< Callback to create AKA digest. */
    } aka;

    } ext;
};
/**
*此结构描述凭据信息。
*凭证信息是一种静态、持久的信息,用于标识
*授权到特定领域所需的用户名和密码。
*
*请注意,由于PJSIP0.7.0.1,因此可以创建
*通过将领域设置为星号/通配符,对任何领域都有效,
*即realm=pj_str(“*”);。
*/
结构pjsip\u cred\u信息
{
pj_str_t realm;/**
您正在填充凭证数组,但没有告诉pjsip应该使用多少条记录。在配置中设置凭证计数(在上述情况下:设置为1):


但是pjusa_acc_配置中没有像cread_count这样的变量?这个放在哪里?
/** 
 * This structure describes credential information. 
 * A credential information is a static, persistent information that identifies
 * username and password required to authorize to a specific realm.
 *
 * Note that since PJSIP 0.7.0.1, it is possible to make a credential that is
 * valid for any realms, by setting the realm to star/wildcard character,
 * i.e. realm = pj_str("*");.
 */
struct pjsip_cred_info
{
    pj_str_t    realm;      /**< Realm. Use "*" to make a credential that
                     can be used to authenticate against any
                     challenges.                */
    pj_str_t    scheme;     /**< Scheme (e.g. "digest").            */
    pj_str_t    username;   /**< User name.                 */
    int     data_type;  /**< Type of data (0 for plaintext passwd). */
    pj_str_t    data;       /**< The data, which can be a plaintext 
                     password or a hashed digest.       */

    /** Extended data */
    union {
    /** Digest AKA credential information. Note that when AKA credential
     *  is being used, the \a data field of this #pjsip_cred_info is
     *  not used, but it still must be initialized to an empty string.
     * Please see \ref PJSIP_AUTH_AKA_API for more information.
     */
    struct {
        pj_str_t      k;    /**< Permanent subscriber key.      */
        pj_str_t      op;   /**< Operator variant key.      */
        pj_str_t      amf;  /**< Authentication Management Field    */
        pjsip_cred_cb cb;   /**< Callback to create AKA digest. */
    } aka;

    } ext;
};
/** 
 * Number of credentials in the credential array.
 */
unsigned        cred_count;