You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建自定义Asterisk PJSIP模块失败:分析SIP消息并打印头信息

解决Asterisk PJSIP自定义模块构建失败及功能实现问题

我来帮你排查这个自定义Asterisk PJSIP模块的问题,先看看你代码里的几个关键问题,再给你修正后的完整示例:

你的代码中存在的核心问题

  • 函数缺少返回值:logging_on_rx_msg声明为pj_bool_t类型,但函数体没有返回值,这会直接导致编译错误。PJSIP的回调函数必须返回PJ_TRUE(允许后续处理)或PJ_FALSE(终止消息处理)。
  • SIP方法获取方式错误:rdata->pkt_info.packet是整个SIP数据包的原始字节指针,无法直接拿到请求方法。正确的方式是通过PJSIP的消息结构体获取方法字符串。
  • 必要头文件缺失:你注释了依赖库,但实际需要包含Asterisk和PJSIP的核心头文件才能编译。
  • 模块注册与回调挂载缺失:代码没有完成Asterisk模块的注册流程,也没有把消息处理回调挂载到PJSIP的消息处理链中,导致模块无法被加载和触发。

修正后的完整模块代码

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjlib.h>

ASTERISK_REGISTER_FILE()

#ifndef AST_MODULE
#define AST_MODULE "res_sip_logger"
#endif

// 处理入站SIP消息的回调函数
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) {
    // 仅处理请求消息(如果需要处理响应,可判断rdata->msg_info.msg->type为PJSIP_RESPONSE_MSG)
    if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
        const pj_str_t *method = &rdata->msg_info.msg->line.req.method.name;
        ast_log(LOG_NOTICE, "Received SIP Request Method: %.*s\n", (int)method->slen, method->ptr);
        
        // 遍历并打印所有SIP头信息
        pjsip_hdr *hdr;
        for (hdr = rdata->msg_info.msg->hdr.next; hdr != &rdata->msg_info.msg->hdr; hdr = hdr->next) {
            char hdr_buf[512];
            pjsip_hdr_print_on(hdr, hdr_buf, sizeof(hdr_buf));
            ast_log(LOG_NOTICE, "SIP Header: %s\n", hdr_buf);
        }
    }
    
    // 返回PJ_TRUE,让Asterisk继续处理这条消息
    return PJ_TRUE;
}

// 定义PJSIP模块结构体
static pjsip_module sip_logger_module = {
    .name = { "sip-logger", 10 },
    // 设置优先级,确保回调能在合适的时机触发(比传输层优先级高一级)
    .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER - 1,
    .on_rx_request = logging_on_rx_msg, // 挂载请求消息回调
    .on_rx_response = NULL, // 如需处理响应,可在这里设置对应的回调函数
};

// 模块加载函数
static int load_module(void) {
    pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
    if (!endpt) {
        ast_log(LOG_ERROR, "Failed to retrieve PJSIP endpoint\n");
        return AST_MODULE_LOAD_DECLINE;
    }
    
    // 注册PJSIP模块到Asterisk的PJSIP端点
    pj_status_t status = pjsip_endpt_register_module(endpt, &sip_logger_module);
    if (status != PJ_SUCCESS) {
        ast_log(LOG_ERROR, "Failed to register SIP logger module: %s\n", pj_strerror(status));
        return AST_MODULE_LOAD_DECLINE;
    }
    
    ast_log(LOG_NOTICE, "Custom SIP logger module loaded successfully\n");
    return AST_MODULE_LOAD_SUCCESS;
}

// 模块卸载函数
static int unload_module(void) {
    pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
    if (endpt) {
        pjsip_endpt_unregister_module(endpt, &sip_logger_module);
    }
    ast_log(LOG_NOTICE, "Custom SIP logger module unloaded\n");
    return 0;
}

// 模块信息注册,必须要有这个宏才能被Asterisk识别
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Custom SIP Message Logger Module");

构建与加载注意事项

  • Makefile配置:确保你的模块Makefile正确链接Asterisk和PJSIP库,典型的Makefile片段:
ASTCFLAGS += -D_REENTRANT
ASTLDFLAGS += -lpjsip -lpjsip_ua -lpjlib -lpjlib-util

include $(ASTERISK_BUILD_DIR)/Makefile.moddir_rules
  • 编译与加载:将模块文件命名为res_sip_logger.c,放到Asterisk源码的res/目录下,使用menuselect工具将其添加到编译列表,重新编译Asterisk。编译完成后,通过module load res_sip_logger命令加载模块。
  • 查看日志:加载模块后,使用asterisk -rvvv进入Asterisk控制台,当有入站SIP消息时,就能在日志中看到打印的方法和头信息了。

内容的提问来源于stack exchange,提问作者raz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:40:16