i have tried to implement pua_rpc module in order to get rid of pua_mi
module. unfortunately pua.publish crashes when it executes the callback
function. i have not been able to figure out why. rpc callback system
is heavily using void typed variables and parameters with casts, which
means that compiler cannot help in finding the bug.
my current code of the module is enclosed. pua.publish causes this kind
of crash during callback execution:
(gdb) where
#0 0xb3e9a513 in fix_delayed_reply_ctx (ctx=0x0) at xmlrpc.c:664
#1 0xb3e9c3ff in rpc_add (ctx=0x0, fmt=0xb3944868 "dS") at xmlrpc.c:1095
#2 0xb393c6ce in publish_callback (hentity=0xb48e0db8, reply=0xffffffff) at pua_rpc.c:98
#3 0xb397fc82 in run_pua_callbacks (hentity=0xb48e0db8, msg=0xffffffff) at
pua_callback.h:72
#4 0xb3984074 in publ_cback_func (t=0xb48e0fb4, type=1024, ps=0xbfbaa85c) at
send_publish.c:436
#5 0xb69cfc09 in run_trans_callbacks_internal (cb_lst=0xb48e0ff4, type=1024,
trans=0xb48e0fb4,
params=0xbfbaa85c) at t_hooks.c:290
#6 0xb69cfd1a in run_trans_callbacks (type=1024, trans=0xb48e0fb4, req=0x0,
rpl=0xffffffff,
code=408) at t_hooks.c:317
#7 0xb6a0815e in local_reply (t=0xb48e0fb4, p_msg=0xffffffff, branch=0, msg_status=408,
cancel_data=0xbfbaa958) at t_reply.c:2120
#8 0xb6a1ca05 in fake_reply (t=0xb48e0fb4, branch=0, code=408) at timer.c:350
#9 0xb6a1ce61 in final_response_handler (r_buf=0xb48e1110, t=0xb48e0fb4) at timer.c:527
#10 0xb6a1cefa in retr_buf_handler (ticks=98494515, tl=0xb48e1124, p=0x1f40) at
timer.c:585
#11 0x08216c78 in slow_timer_main () at timer.c:1145
#12 0x080df91b in main_loop () at main.c:1687
#13 0x080e4956 in main (argc=17, argv=0xbfbaae14) at main.c:2568
what should i do with the code? commit it to git in case someone would
later be able to figure out where the bug is or just through it to
waste bin?
-- juha
/*
* $Id$
*
* pua_rpc module - RPC pua module
*
* Copyright (C) 2014 Juha Heinanen
*
* This file is part of Kamailio, a free SIP server.
*
* Kamailio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* Kamailio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* History:
* --------
* 2014-11-16 initial version (jh)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../../sr_module.h"
#include "../../parser/parse_expires.h"
#include "../../dprint.h"
#include "../../mem/shm_mem.h"
#include "../../parser/msg_parser.h"
#include "../../str.h"
#include "../../mem/mem.h"
#include "../../pt.h"
#include "../../rpc_lookup.h"
#include "../../modules/tm/tm_load.h"
#include "../../lib/kcore/cmpapi.h"
#include "../pua/pua_bind.h"
#include "rpc_func.h"
MODULE_VERSION
static int mod_init(void);
send_publish_t pua_send_publish;
static const char* publish_doc[2] = {
"sends publish request and waits for the final reply, using a list "
"of string parameters: presentity uri, expires, event package, "
"content type, id, etag, outbound proxy, extra headers, "
" and body (optional)",
0
};
static int publish_callback(ua_pres_t* hentity, struct sip_msg* reply)
{
rpc_delayed_ctx_t* dctx;
void* c;
rpc_t* rpc;
struct hdr_field* hdr= NULL;
int statuscode;
int expires;
int found;
str etag;
str reason = {0, 0};
if (reply == NULL || hentity == NULL || hentity->cb_param == NULL) {
LM_ERR("NULL reply or hentity parameter\n");
return -1;
}
dctx = (rpc_delayed_ctx_t *)(hentity->cb_param);
hentity->cb_param = 0;
if (dctx == 0){
BUG("null delayed reply ctx\n");
return -1;
}
LM_INFO("dctx %u\n", (unsigned int)dctx);
rpc = &dctx->rpc;
c = dctx->reply_ctx;
if (reply == FAKED_REPLY) {
statuscode = 408;
reason.s = "Request Timeout";
reason.len = strlen(reason.s);
} else {
statuscode = reply->first_line.u.reply.statuscode;
reason = reply->first_line.u.reply.reason;
}
rpc->add(c, "dS", statuscode, &reason);
rpc->delayed_ctx_close(dctx);
if (statuscode == 200) {
expires = ((exp_body_t*)reply->expires->parsed)->val;
LM_DBG("expires = %d\n", expires);
hdr = reply->headers;
found = 0;
while (hdr != NULL) {
if(cmp_hdrname_strzn(&hdr->name, "SIP-ETag",8) == 0) {
found = 1;
break;
}
hdr = hdr->next;
}
if (found == 0) {
LM_ERR("SIP-ETag header field not found\n");
return -1;
}
etag= hdr->body;
rpc->add(c, "Sd", &etag, expires);
}
return 0;
}
static void publish(rpc_t* rpc, void* c)
{
str pres_uri, expires, event, content_type, id, etag,
outbound_proxy, extra_headers, body;
rpc_delayed_ctx_t* dctx;
int exp, sign, ret, err_ret, sip_error;
char err_buf[MAX_REASON_LEN];
struct sip_uri uri;
publ_info_t publ;
body.s = 0;
body.len = 0;
dctx = 0;
LM_DBG("publishing ...\n");
if ((rpc->capabilities == 0) ||
!(rpc->capabilities(c) & RPC_DELAYED_REPLY)) {
rpc->fault(c, 600, "Reply wait/async mode not supported"
" by this rpc transport");
return;
}
ret = rpc->scan(c, "SSSSSSSS*S", &pres_uri, &expires, &event,
&content_type, &id, &etag, &outbound_proxy,
&extra_headers, &body);
if (ret < 8) {
rpc->fault(c, 400, "too few parameters (%d)", ret);
return;
}
if (parse_uri(pres_uri.s, pres_uri.len, &uri) <0) {
LM_ERR("bad resentity uri\n");
rpc->fault(c, 400, "Invalid presentity uri '%s'", pres_uri.s);
return;
}
LM_DBG("presentity uri '%.*s'\n", pres_uri.len, pres_uri.s);
if (expires.s[0]== '-') {
sign= -1;
expires.s++;
expires.len--;
} else {
sign = 1;
}
if (str2int(&expires, (unsigned int*)&exp) < 0) {
LM_ERR("invalid expires parameter\n" );
rpc->fault(c, 400, "Invalid expires '%s'", expires.s);
return;
}
exp= exp * sign;
LM_DBG("expires '%d'\n", exp);
LM_DBG("event '%.*s'\n", event.len, event.s);
LM_DBG("content type '%.*s'\n", content_type.len, content_type.s);
LM_DBG("id '%.*s'\n", id.len, id.s);
LM_DBG("ETag '%.*s'\n", etag.len, etag.s);
LM_DBG("outbound_proxy '%.*s'\n", outbound_proxy.len,
outbound_proxy.s);
LM_DBG("extra headers '%.*s'\n", extra_headers.len, extra_headers.s);
if (body.len > 0) LM_DBG("body '%.*s'\n", body.len, body.s);
if ((body.s == 0) &&
(content_type.len != 1 || content_type.s[0] != '.')) {
LM_ERR("body is missing, but content type is not .\n");
rpc->fault(c, 400, "Body is missing");
return;
}
memset(&publ, 0, sizeof(publ_info_t));
publ.pres_uri= &pres_uri;
publ.expires= exp;
publ.event= get_event_flag(&event);
if (publ.event < 0) {
LM_ERR("unknown event '%.*s'\n", event.len, event.s);
rpc->fault(c, 400, "Unknown event");
return;
}
if (content_type.len != 1) {
publ.content_type= content_type;
}
if (!((id.len == 1) && (id.s[0]== '.'))) {
publ.id= id;
}
if (!((etag.len== 1) && (etag.s[0]== '.'))) {
publ.etag= &etag;
}
if (!((outbound_proxy.len == 1) && (outbound_proxy.s[0] == '.'))) {
publ.outbound_proxy = &outbound_proxy;
}
if (!((extra_headers.len == 1) && (extra_headers.s[0] == '.'))) {
publ.extra_headers = &extra_headers;
}
if (body.s != 0) {
publ.body= &body;
}
dctx = rpc->delayed_ctx_new(c);
if (dctx == 0) {
LM_ERR("internal error: failed to create context\n");
rpc->fault(c, 500, "internal error: failed to create context");
return;
}
LM_INFO("dctx %u\n", (unsigned int)dctx);
publ.source_flag = MI_ASYN_PUBLISH;
publ.cb_param = dctx;
rpc = &dctx->rpc;
c = dctx->reply_ctx;
LM_DBG("sending publish\n");
ret = pua_send_publish(&publ);
if (ret <= 0) {
err_ret = err2reason_phrase(ret, &sip_error, err_buf,
sizeof(err_buf), "RPC/PUBLISH") ;
if (err_ret > 0 ) {
rpc->fault(c, sip_error, "%s", err_buf);
} else {
rpc->fault(c, 500, "RPC/PUBLISH error");
}
rpc->delayed_ctx_close(dctx);
return;
}
if (ret == 418) {
rpc->fault(c, 500, "Wrong ETag");
return;
}
return;
}
rpc_export_t pua_rpc[] = {
{"pua.publish", publish, publish_doc, 0},
{0, 0, 0, 0}
};
/** module exports */
struct module_exports exports= {
"pua_rpc",
0,
pua_rpc,
0,
mod_init,
0,
0,
0,
0
};
/**
* init module function
*/
static int mod_init(void)
{
bind_pua_t bind_pua;
pua_api_t pua;
bind_pua= (bind_pua_t)find_export("bind_pua", 1,0);
if (!bind_pua) {
LM_ERR("can't find pua\n");
return -1;
}
if (bind_pua(&pua) < 0) {
LM_ERR("can't bind pua\n");
return -1;
}
if (pua.send_publish == NULL) {
LM_ERR("could not import send_publish\n");
return -1;
}
pua_send_publish = pua.send_publish;
if (pua.register_puacb(MI_ASYN_PUBLISH, publish_callback, NULL) < 0) {
LM_ERR("could not register callback\n");
return -1;
}
return 0;
}