1 /**********************************************************************************************************
2 * Software License Agreement(BSD License) *
3 * Author: Thomas Klausner <tk@giga.or.at> *
4 * *
5 * Copyright(c) 2019, Thomas Klausner *
6 * All rights reserved. *
7 * *
8 * Written under contract by Effortel Technologies SA, http://effortel.com/ *
9 * *
10 * Redistribution and use of this software in source and binary forms, with or without modification, are *
11 * permitted provided that the following conditions are met: *
12 * *
13 * * Redistributions of source code must retain the above *
14 * copyright notice, this list of conditions and the *
15 * following disclaimer. *
16 * *
17 * * Redistributions in binary form must reproduce the above *
18 * copyright notice, this list of conditions and the *
19 * following disclaimer in the documentation and/or other *
20 * materials provided with the distribution. *
21 * *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT *
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
28 * TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
30 **********************************************************************************************************/
31
32 /* This extension simply receives CCR and sends CCA after displaying the content, but does not store any data */
33
34 #include <freeDiameter/extension.h>
35
36 struct disp_hdl *ccr_handler_hdl;
37
38 struct dict_object * aai_avp_do; /* cache the Auth-Application-Id dictionary object */
39 struct dict_object * crn_avp_do; /* cache the CC-Request-Number dictionary object */
40 struct dict_object * crt_avp_do; /* cache the CC-Request-Type dictionary object */
41
42 #define MODULE_NAME "test_cc"
43
44 struct statistics {
45 uint64_t sent;
46 time_t first;
47 time_t last;
48 } statistics;
49
print_statistics(void)50 void print_statistics(void) {
51 if (statistics.first == 0 || statistics.last == 0 || statistics.last == statistics.first) {
52 return;
53 }
54
55 fd_log_error("%s: %lld CCA messages sent in %llds (%.2f messages/second)", fd_g_config->cnf_diamid,
56 (long long)statistics.sent, (long long)(statistics.last-statistics.first), (float)statistics.sent / (statistics.last-statistics.first));
57 }
58
ccr_handler(struct msg ** msg,struct avp * avp,struct session * sess,void * data,enum disp_action * act)59 static int ccr_handler(struct msg ** msg, struct avp * avp, struct session * sess, void * data, enum disp_action * act)
60 {
61 struct msg_hdr *hdr = NULL;
62 time_t now;
63
64 TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
65
66 if(msg == NULL)
67 return EINVAL;
68
69 CHECK_FCT(fd_msg_hdr(*msg, &hdr));
70 if(hdr->msg_flags & CMD_FLAG_REQUEST) {
71 /* Request received, answer it */
72 struct msg *answer;
73 os0_t s;
74 size_t sl;
75 struct avp *avp;
76 union avp_value val;
77 struct avp *avp_data;
78 struct avp_hdr *ahdr;
79 uint32_t crt, crn;
80
81 /* get some necessary information from request */
82 if (fd_msg_search_avp(*msg, crt_avp_do, &avp_data) < 0 || avp_data == NULL) {
83 fd_log_error("[%s] CC-Request-Type not found in CCR", MODULE_NAME);
84 return 0;
85 }
86 if (fd_msg_avp_hdr(avp_data, &ahdr) < 0) {
87 fd_log_error("[%s] error parsing CC-Request-Type in CCR", MODULE_NAME);
88 return 0;
89 }
90 crt = ahdr->avp_value->i32;
91 if (fd_msg_search_avp(*msg, crn_avp_do, &avp_data) < 0 || avp_data == NULL) {
92 fd_log_error("[%s] CC-Request-Number not found in CCR", MODULE_NAME);
93 return 0;
94 }
95 if (fd_msg_avp_hdr(avp_data, &ahdr) < 0) {
96 fd_log_error("[%s] error parsing CC-Request-Type in CCR", MODULE_NAME);
97 return 0;
98 }
99 crn = ahdr->avp_value->i32;
100
101 /* Create the answer message */
102 CHECK_FCT(fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0));
103 answer = *msg;
104
105 /* TODO copy/fill in more AVPs in the answer */
106
107 /* Auth-Application-Id */
108 fd_msg_avp_new(aai_avp_do, 0, &avp);
109 memset(&val, 0, sizeof(val));
110 val.i32 = 4;
111 if (fd_msg_avp_setvalue(avp, &val) != 0) {
112 fd_msg_free(answer);
113 fd_log_error("can't set value for 'Auth-Application-Id' for 'Credit-Control-Request' message");
114 return 0;
115 }
116 fd_msg_avp_add(answer, MSG_BRW_LAST_CHILD, avp);
117
118 /* CC-Request-Type */
119 fd_msg_avp_new(crt_avp_do, 0, &avp);
120 memset(&val, 0, sizeof(val));
121 val.i32 = crt;
122 if (fd_msg_avp_setvalue(avp, &val) != 0) {
123 fd_msg_free(answer);
124 fd_log_error("can't set value for 'CC-Request-Type' for 'Credit-Control-Request' message");
125 return 0;
126 }
127 fd_msg_avp_add(answer, MSG_BRW_LAST_CHILD, avp);
128
129 /* CC-Request-Number */
130 fd_msg_avp_new(crn_avp_do, 0, &avp);
131 memset(&val, 0, sizeof(val));
132 val.i32 = crn;
133 if (fd_msg_avp_setvalue(avp, &val) != 0) {
134 fd_msg_free(answer);
135 fd_log_error("can't set value for 'CC-Request-Number' for 'Credit-Control-Request' message");
136 return 0;
137 }
138 fd_msg_avp_add(answer, MSG_BRW_LAST_CHILD, avp);
139
140 /* TODO make result configurable (depending on an AVP?) */
141 CHECK_FCT(fd_msg_rescode_set(answer, "DIAMETER_SUCCESS", NULL, NULL, 1));
142
143 fd_log_debug("--------------Received the following Credit Control Request:--------------");
144
145 CHECK_FCT(fd_sess_getsid(sess, &s, &sl));
146 fd_log_debug("Session: %.*s",(int)sl, s);
147
148 fd_log_debug("----------------------------------------------------------------------");
149
150 /* Send the answer */
151 CHECK_FCT(fd_msg_send(msg, NULL, NULL));
152 now = time(NULL);
153 if (!statistics.first) {
154 statistics.first = now;
155 }
156 if (statistics.last != now) {
157 print_statistics();
158 }
159 statistics.last = now;
160 statistics.sent++;
161 fd_log_debug("reply sent");
162 } else {
163 /* We received an answer message, just discard it */
164 CHECK_FCT(fd_msg_free(*msg));
165 *msg = NULL;
166 }
167
168 return 0;
169 }
170
171 /* entry hook: register callback */
cc_entry(char * conffile)172 static int cc_entry(char * conffile)
173 {
174 struct disp_when data;
175
176 TRACE_ENTRY("%p", conffile);
177
178 CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &aai_avp_do, ENOENT),
179 { LOG_E("Unable to find 'Auth-Application-Id' AVP in the loaded dictionaries."); });
180 CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CC-Request-Number", &crn_avp_do, ENOENT),
181 { LOG_E("Unable to find 'CC-Request-Number' AVP in the loaded dictionaries."); });
182 CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "CC-Request-Type", &crt_avp_do, ENOENT),
183 { LOG_E("Unable to find 'CC-Request-Type' AVP in the loaded dictionaries."); });
184
185 memset(&data, 0, sizeof(data));
186
187 /* Advertise the support for the Diameter Credit Control application in the peer */
188 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Credit Control Application", &data.app, ENOENT) );
189 CHECK_FCT( fd_disp_app_support ( data.app, NULL, 1, 0 ) );
190
191 /* register handler for CCR */
192 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Credit-Control-Request", &data.command, ENOENT) );
193 CHECK_FCT( fd_disp_register( ccr_handler, DISP_HOW_CC, &data, NULL, &ccr_handler_hdl ) );
194
195 return 0;
196 }
197
198 /* And terminate it */
fd_ext_fini(void)199 void fd_ext_fini(void)
200 {
201 /* Unregister the callbacks */
202 if (ccr_handler_hdl) {
203 CHECK_FCT_DO( fd_disp_unregister(&ccr_handler_hdl, NULL), );
204 ccr_handler_hdl = NULL;
205 }
206
207 print_statistics();
208
209 return;
210 }
211
212
213 EXTENSION_ENTRY(MODULE_NAME, cc_entry);
214