pjsip / pjproject

PJSIP project
http://www.pjsip.org
GNU General Public License v2.0
1.92k stars 753 forks source link

[Question]How to use the PJSIP library to send subscription messages and enable the receiving end to correctly recognize them using the Exosip library #3989

Closed ljpmingyue closed 2 weeks ago

ljpmingyue commented 3 weeks ago

Describe the bug

The PJSIP library sends subscribe messages, but the receiver of the Exosip library classifies the messages into the message class instead of subscribe class,and during the reprocessing process, exosip directly replied with 400。When I want to reply, prompt me that the message has already been replied to。But when I use the exosip library to send subscribe messages, the receiving end can process and reply normally

Steps to reproduce

I am sending the code for implementing subscribe messages using the pjsip library below. May I ask if there are any issues with my implementation 1

PJSIP version

2.13

Context

pj_status_t send_subscribe(pjsip_endpoint endpt, const pj_str_t local_uri, const pj_str_t target_uri) { pj_pool_t pool; pjsip_tx_data *tdata; pj_status_t status;

// 创建内存池
pool = pj_pool_create(&pj_caching_pool.factory, "subscribe", 512, 512, NULL);

// 创建请求 URI
pjsip_uri *req_uri = pjsip_parse_uri(pool, target_uri->ptr, target_uri->slen, 0);
if (!req_uri) {
    PJ_LOG(3, (THIS_FILE, "Invalid target URI"));
    pj_pool_release(pool);
    return PJ_EINVAL;
}

// 创建本地 URI
pjsip_sip_uri *from_uri = pjsip_sip_uri_create(pool, 0);
from_uri->user = pj_str(SIP_USER);
from_uri->host = pj_str(SIP_DOMAIN);

// 创建 To URI
pjsip_sip_uri *to_uri = pjsip_sip_uri_create(pool, 0);
to_uri->user = pj_str("bob");
to_uri->host = pj_str(SIP_DOMAIN);

// 创建 Contact URI
pjsip_sip_uri *contact_uri = pjsip_sip_uri_create(pool, 0);
contact_uri->user = pj_str(SIP_USER);
contact_uri->host = pj_str("localhost");

// 创建并初始化请求头
status = pjsip_endpt_create_request(endpt, 
                                    &subscribe_method, // 使用自定义 SUBSCRIBE 方法
                                    req_uri,
                                    (pjsip_uri*)from_uri,
                                    (pjsip_uri*)to_uri,
                                    (pjsip_uri*)contact_uri,
                                    NULL,
                                    NULL,
                                    &tdata);
if (status != PJ_SUCCESS) {
    pj_pool_release(pool);
    return status;
}

// 添加 Via 头部
pjsip_via_hdr *via_hdr = pjsip_via_hdr_create(tdata->pool);
via_hdr->transport = pj_str("UDP");
via_hdr->sent_by.host = pj_str("localhost");
via_hdr->sent_by.port = pj_str("5060");
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)via_hdr);

// 添加 CSeq 头部
pjsip_cseq_hdr *cseq_hdr = pjsip_cseq_hdr_create(tdata->pool);
cseq_hdr->cseq = 1;
cseq_hdr->method = subscribe_method; // 设置方法为 SUBSCRIBE
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)cseq_hdr);

// 添加 Call-ID 头部
pjsip_generic_string_hdr *call_id_hdr = pjsip_generic_string_hdr_create(tdata->pool, 
    &pj_str("Call-ID"), &pj_str("callid-12345"));
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)call_id_hdr);

// 添加 Event 头部
pjsip_generic_string_hdr *event_hdr = pjsip_generic_string_hdr_create(tdata->pool, 
    &pj_str("Event"), &pj_str("presence"));
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)event_hdr);

// 添加 Expires 头部
pjsip_expires_hdr *expires_hdr = pjsip_expires_hdr_create(tdata->pool);
expires_hdr->ivalue = 3600;  // 1 hour
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);

// 发送请求
status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, NULL);
if (status != PJ_SUCCESS) {
    pjsip_tx_data_dec_ref(tdata);
    pj_pool_release(pool);
    return status;
}

pj_pool_release(pool);
return PJ_SUCCESS;

}

int main() { pj_status_t status; pjsip_endpoint *endpt; pj_caching_pool cp; pj_str_t target_uri = pj_str(SIP_TARGET);

// 初始化 PJLIB
status = pj_init();
if (status != PJ_SUCCESS) {
    PJ_LOG(3, (THIS_FILE, "pj_init error"));
    return 1;
}

// 创建缓存池
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

// 创建 PJSIP 端点
status = pjsip_endpt_create(&cp.factory, NULL, &endpt);
if (status != PJ_SUCCESS) {
    PJ_LOG(3, (THIS_FILE, "pjsip_endpt_create error"));
    pj_shutdown();
    return 1;
}

// 初始化 PJSIP UA 模块
status = pjsip_ua_init_module(endpt, NULL);
if (status != PJ_SUCCESS) {
    PJ_LOG(3, (THIS_FILE, "pjsip_ua_init_module error"));
    pjsip_endpt_destroy(endpt);
    pj_shutdown();
    return 1;
}

// 启用详细日志记录
pj_log_set_level(5);

// 初始化 SUBSCRIBE 方法
init_subscribe_method();

// 创建并发送 SUBSCRIBE 请求
pj_str_t local_uri = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
status = send_subscribe(endpt, &local_uri, &target_uri);
if (status != PJ_SUCCESS) {
    PJ_LOG(3, (THIS_FILE, "send_subscribe error"));
    pjsip_endpt_destroy(endpt);
    pj_shutdown();
    return 1;
}

// 处理事件循环
while (1) {
    pjsip_endpt_handle_events(endpt, NULL);
}

// 清理资源
pjsip_endpt_destroy(endpt);
pj_shutdown();

return 0;

}

Log, call stack, etc

No errors were reported during implementation, and messages were sent normally
ljpmingyue commented 3 weeks ago

Can someone please help me check this issue? Thank you

ljpmingyue commented 3 weeks ago

Sorry, there is an issue with the picture provided. In fact, the Event and Expires fields were added later, but the result is still the same

sauwming commented 2 weeks ago

As the remote is the one deciding to reject it, you can check the remote log for the reason of such rejection.

Currently the issue page is for bug report or feature request only, not for asking enquiries.