构建自定义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
相关产品推荐
相关产品推荐

