2
0
Эх сурвалжийг харах

modules/pua_rpc: added pua_rpc module
- this is work in progress:
- failure message is not produced when callback is not executed due to
an error
- readme file is missing

Juha Heinanen 8 жил өмнө
parent
commit
4360021cce

+ 17 - 0
src/modules/pua_rpc/Makefile

@@ -0,0 +1,17 @@
+#
+# pua_rpc module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=pua_rpc.so
+LIBS=
+DEFS+= -DSER_MOD_INTERFACE
+
+ifeq ($(INSTALL_FLAVOUR),kamailio)
+DEFS+= -DWITH_EVENT_LOCAL_REQUEST
+endif # INSTALL_FLAVOUR
+
+include ../../Makefile.modules

+ 334 - 0
src/modules/pua_rpc/pua_rpc.c

@@ -0,0 +1,334 @@
+/*
+ * pua_rpc module - RPC pua module
+ *
+ * Copyright (C) 2014-2016 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
+ */
+
+/*!
+ * \file
+ * \brief Kamailio pua_rpc :: rpc API interface for pua implementing pua.publish rpc command
+ * Module: \ref pua_rpc
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "../../core/sr_module.h"
+#include "../../core/parser/parse_expires.h"
+#include "../../core/dprint.h"
+#include "../../core/mem/shm_mem.h"
+#include "../../core/parser/msg_parser.h"
+#include "../../core/str.h"
+#include "../../core/mem/mem.h"
+#include "../../core/pt.h"
+#include "../../core/rpc_lookup.h"
+#include "../../core/strutils.h"
+/* #include "../tm/tm_load.h" */
+#include "../pua/pua_bind.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};
+
+	LM_DBG("running callback\n");
+
+	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 = NULL;
+	if (dctx == 0){
+		BUG("null delayed reply ctx\n");
+		return -1;
+	}
+	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);
+
+	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");
+			rpc->delayed_ctx_close(dctx);
+			return -1;
+		}
+		etag = hdr->body;
+		LM_DBG("SIP-Etag = %.*s\n", etag.len, etag.s);
+		rpc->add(c, "Sd", &etag, expires);
+	}	
+
+	rpc->delayed_ctx_close(dctx);
+
+	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("rpc 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;
+	}
+	publ.cb_param = dctx;
+	publ.source_flag = MI_ASYN_PUBLISH;
+
+	ret = pua_send_publish(&publ);
+	LM_DBG("pua_send_publish returned %d\n", ret);
+
+	if (dctx->reply_ctx != 0) {
+		/* callback was not executed or its execution failed */
+		rpc = &dctx->rpc;
+		c = dctx->reply_ctx;
+	} else {
+		return;
+	}
+
+	if (ret < 0) {
+		LM_ERR("pua_send_publish failed\n");
+		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);
+	}
+
+	if (ret == 418) {
+		rpc->fault(c, 500, "Wrong ETag");
+		rpc->delayed_ctx_close(dctx);
+	}
+
+
+	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;
+
+	LM_DBG("initializing\n");
+	
+	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;
+}