2 * Copyright (C) 2016-2017 ng-voice GmbH, carsten@ng-voice.com
4 * This file is part of Kamailio, a free SIP server.
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "../../core/sr_module.h"
23 #include "../../core/route.h"
24 #include "../cdp/cdp_load.h"
25 #include "../cdp_avp/cdp_avp_mod.h"
26 #include "ims_diameter_server.h"
27 #include "avp_helper.h"
28 #include "../../core/fmsg.h"
32 extern gen_lock_t* process_lock; /* lock on the process table */
34 struct cdp_binds cdpb;
35 cdp_avp_bind_t *cdp_avp;
41 struct cdp_binds cdpb;
43 cdp_avp_bind_t *cdp_avp;
45 /** module functions */
46 static int mod_init(void);
47 static int mod_child_init(int);
48 static void mod_destroy(void);
50 int * callback_singleton; /*< Callback singleton */
52 int event_route_diameter = 0;
53 int event_route_diameter_response = 0;
55 static int diameter_request(struct sip_msg * msg, char* peer, char* appid, char* commandcode, char* message, int async);
56 static int w_diameter_request(struct sip_msg * msg, char* appid, char* commandcode, char* message);
57 static int w_diameter_request_peer(struct sip_msg *msg, char* peer, char* appid, char* commandcode, char* message);
58 static int w_diameter_request_async(struct sip_msg * msg, char* appid, char* commandcode, char* message);
59 static int w_diameter_request_peer_async(struct sip_msg *msg, char* peer, char* appid, char* commandcode, char* message);
62 static cmd_export_t cmds[] = {
63 {"diameter_request", (cmd_function)w_diameter_request, 3, fixup_var_pve_str_12, 0, ANY_ROUTE},
64 {"diameter_request", (cmd_function)w_diameter_request_peer, 4, fixup_var_pve_str_12, 0, ANY_ROUTE},
65 {"diameter_request_async", (cmd_function)w_diameter_request_async, 3, fixup_var_pve_str_12, 0, ANY_ROUTE},
66 {"diameter_request_async", (cmd_function)w_diameter_request_peer_async, 4, fixup_var_pve_str_12, 0, ANY_ROUTE},
70 static param_export_t params[] = {
74 static pv_export_t mod_pvs[] = {
75 { {"diameter_command", sizeof("diameter_command")-1}, PVT_OTHER, pv_get_command, 0, 0, 0, 0, 0 },
76 { {"diameter_application", sizeof("diameter_application")-1}, PVT_OTHER, pv_get_application, 0, 0, 0, 0, 0 },
77 { {"diameter_request", sizeof("diameter_request")-1}, PVT_OTHER, pv_get_request, 0, 0, 0, 0, 0 },
78 { {"diameter_response", sizeof("diameter_response")-1}, PVT_OTHER, pv_get_response, pv_set_response, 0, 0, 0, 0 },
79 { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
83 struct module_exports exports = {
84 "ims_diameter_server",
85 DEFAULT_DLFLAGS, /* dlopen flags */
86 cmds, /* Exported functions */
87 params, /* exported statistics */
88 0, /* exported RPC methods */
89 mod_pvs, /* exported pseudo-variables */
90 0, /* response handling function */
91 mod_init, /* module initialization function */
92 mod_child_init, /* per-child init function */
97 * init module function
99 static int mod_init(void) {
100 LM_DBG("Loading...\n");
104 responsejson.len = 0;
108 callback_singleton = shm_malloc(sizeof (int));
109 *callback_singleton = 0;
112 /* load the CDP API */
113 if (load_cdp_api(&cdpb) != 0) {
114 LM_ERR("can't load CDP API\n");
118 cdp_avp = load_cdp_avp();
120 LM_ERR("can't load CDP_AVP API\n");
124 event_route_diameter = route_get(&event_rt, "diameter:request");
125 if (event_route_diameter < 0) {
126 LM_ERR("No diameter:request event route found\n");
129 LM_DBG("Found Route diameter:request: %i\n", event_route_diameter);
131 event_route_diameter_response = route_get(&event_rt, "diameter:response");
132 if (event_route_diameter_response < 0) {
133 LM_WARN("No diameter:response event route found, asynchronous operations disabled.\n");
135 LM_DBG("Found Route diameter:response: %i\n", event_route_diameter_response);
140 LM_ERR("Failed to initialise ims_diameter_server module\n");
145 * Initializes the module in child.
147 static int mod_child_init(int rank) {
148 LM_DBG("Initialization of module in child [%d] \n", rank);
150 /* don't do anything for main process and TCP manager process */
151 if (rank == PROC_MAIN || rank == PROC_TCP_MAIN) {
155 lock_get(process_lock);
156 if ((*callback_singleton) == 0) {
157 *callback_singleton = 1;
158 cdpb.AAAAddRequestHandler(callback_cdp_request, NULL);
160 lock_release(process_lock);
166 static void mod_destroy(void) {
171 * Handler for incoming Diameter requests.
172 * @param request - the received request
173 * @param param - generic pointer
174 * @returns the answer to this request
176 AAAMessage* callback_cdp_request(AAAMessage *request_in, void *param) {
177 struct sip_msg *fmsg;
179 struct run_act_ctx ctx;
180 AAAMessage *response;
182 LM_DBG("Got DIAMETER-Request!\n");
184 if (is_req(request_in)) {
185 LM_DBG("is request!\n");
186 LM_DBG("Found Route diameter:request: %i\n", event_route_diameter);
188 request = request_in;
189 response = cdpb.AAACreateResponse(request_in);
190 if (!response) return 0;
192 backup_rt = get_route_type();
193 set_route_type(REQUEST_ROUTE);
194 init_run_actions_ctx(&ctx);
195 fmsg = faked_msg_next();
197 responsejson.len = 0;
199 run_top_route(event_rt.rlist[event_route_diameter], fmsg, &ctx);
201 set_route_type(backup_rt);
202 LM_DBG("Processed Event-Route!\n");
204 if (addAVPsfromJSON(response, NULL)) {
213 int w_diameter_request(struct sip_msg * msg, char* appid, char* commandcode, char* message) {
214 return diameter_request(msg, 0, appid, commandcode, message, 0);
217 static int w_diameter_request_peer(struct sip_msg *msg, char* peer, char* appid, char* commandcode, char* message) {
218 return diameter_request(msg, peer, appid, commandcode, message, 0);
221 static int w_diameter_request_async(struct sip_msg * msg, char* appid, char* commandcode, char* message) {
222 return diameter_request(msg, 0, appid, commandcode, message, 1);
225 static int w_diameter_request_peer_async(struct sip_msg *msg, char* peer, char* appid, char* commandcode, char* message) {
226 return diameter_request(msg, peer, appid, commandcode, message, 1);
229 void async_cdp_diameter_callback(int is_timeout, void *request, AAAMessage *response, long elapsed_msecs) {
230 struct sip_msg *fmsg;
232 struct run_act_ctx ctx;
234 if (is_timeout != 0) {
235 LM_ERR("Error timeout when sending message via CDP\n");
240 LM_ERR("Error sending message via CDP\n");
243 if (AAAmsg2json(response, &responsejson) != 1) {
244 LM_ERR("Failed to convert response to JSON\n");
246 request = (AAAMessage*)request;
248 backup_rt = get_route_type();
249 set_route_type(REQUEST_ROUTE);
250 init_run_actions_ctx(&ctx);
251 fmsg = faked_msg_next();
253 run_top_route(event_rt.rlist[event_route_diameter_response], fmsg, &ctx);
255 set_route_type(backup_rt);
256 LM_DBG("Processed Event-Route!\n");
259 if (response) cdpb.AAAFreeMessage(&response);
263 int diameter_request(struct sip_msg * msg, char* peer, char* appid, char* commandcode, char* message, int async) {
264 str s_appid, s_commandcode, s_peer, s_message;
266 AAASession *session = 0;
267 AAAMessage *resp = 0;
269 unsigned int i_appid, i_commandcode;
271 if (async && (event_route_diameter_response < 0)) {
272 LM_ERR("Asynchronous operations disabled\n");
277 if (get_str_fparam(&s_peer, msg, (fparam_t*)peer) < 0) {
278 LM_ERR("failed to get Peer\n");
281 LM_DBG("Peer %.*s\n", s_peer.len, s_peer.s);
283 if (get_str_fparam(&s_message, msg, (fparam_t*)message) < 0) {
284 LM_ERR("failed to get Message\n");
287 if (get_str_fparam(&s_appid, msg, (fparam_t*)appid) < 0) {
288 LM_ERR("failed to get App-ID\n");
291 if (str2int(&s_appid, &i_appid) != 0) {
292 LM_ERR("Invalid App-ID (%.*s)\n", s_appid.len, s_appid.s);
295 LM_DBG("App-ID %i\n", i_appid);
296 if (get_str_fparam(&s_commandcode, msg, (fparam_t*)commandcode) < 0) {
297 LM_ERR("failed to get Command-Code\n");
300 if (str2int(&s_commandcode, &i_commandcode) != 0) {
301 LM_ERR("Invalid Command-Code (%.*s)\n", s_commandcode.len, s_commandcode.s);
304 LM_DBG("Command-Code %i\n", i_commandcode);
305 if (get_str_fparam(&s_commandcode, msg, (fparam_t*)commandcode) < 0) {
306 LM_ERR("failed to get Command-Code\n");
310 session = cdpb.AAACreateSession(0);
312 req = cdpb.AAACreateRequest(i_appid, i_commandcode, Flag_Proxyable, session);
314 cdpb.AAADropSession(session);
318 if (!req) goto error1;
320 if (addAVPsfromJSON(req, &s_message)) {
321 LM_ERR("Failed to parse JSON Request\n");
326 if (peer && (s_peer.len > 0)) {
328 cdpb.AAASendMessageToPeer(req, &s_peer, (void*) async_cdp_diameter_callback, req);
329 LM_DBG("Successfully sent async diameter\n");
332 resp = cdpb.AAASendRecvMessageToPeer(req, &s_peer);
333 LM_DBG("Successfully sent diameter\n");
334 if (resp && AAAmsg2json(resp, &responsejson) == 1) {
337 LM_ERR("Failed to convert response to JSON\n");
343 cdpb.AAASendMessage(req, (void*) async_cdp_diameter_callback, req);
344 LM_DBG("Successfully sent async diameter\n");
347 resp = cdpb.AAASendRecvMessage(req);
348 LM_DBG("Successfully sent diameter\n");
349 if (resp && AAAmsg2json(resp, &responsejson) == 1) {
352 LM_ERR("Failed to convert response to JSON\n");
358 //Only free UAR IFF it has not been passed to CDP
359 if (req) cdpb.AAAFreeMessage(&req);
360 LM_ERR("Error occurred trying to send request\n");