Let's also include aclocal.m4
[asterisk-bristuff.git] / cdr / cdr_radius.c
blob6d890e7646b6d9c3af9954b45fed6f65055a56c0
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief RADIUS CDR Support
22 * \author Philippe Sultan
24 * \arg See also \ref AstCDR
25 * \ingroup cdr_drivers
28 /*** MODULEINFO
29 <depend>radius</depend>
30 ***/
32 #include "asterisk.h"
34 ASTERISK_FILE_VERSION(__FILE__, "$Rev$")
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <time.h>
42 #include <sys/types.h>
43 #include <radiusclient-ng.h>
45 #include "asterisk/channel.h"
46 #include "asterisk/cdr.h"
47 #include "asterisk/module.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/options.h"
52 /*! ISO 8601 standard format */
53 #define DATE_FORMAT "%Y-%m-%d %T %z"
55 #define VENDOR_CODE 22736
57 enum {
58 PW_AST_ACCT_CODE = 101,
59 PW_AST_SRC = 102,
60 PW_AST_DST = 103,
61 PW_AST_DST_CTX = 104,
62 PW_AST_CLID = 105,
63 PW_AST_CHAN = 106,
64 PW_AST_DST_CHAN = 107,
65 PW_AST_LAST_APP = 108,
66 PW_AST_LAST_DATA = 109,
67 PW_AST_START_TIME = 110,
68 PW_AST_ANSWER_TIME = 111,
69 PW_AST_END_TIME = 112,
70 PW_AST_DURATION = 113,
71 PW_AST_BILL_SEC = 114,
72 PW_AST_DISPOSITION = 115,
73 PW_AST_AMA_FLAGS = 116,
74 PW_AST_UNIQUE_ID = 117,
75 PW_AST_USER_FIELD = 118
78 enum {
79 /*! Log dates and times in UTC */
80 RADIUS_FLAG_USEGMTIME = (1 << 0),
81 /*! Log Unique ID */
82 RADIUS_FLAG_LOGUNIQUEID = (1 << 1),
83 /*! Log User Field */
84 RADIUS_FLAG_LOGUSERFIELD = (1 << 2)
87 static char *desc = "RADIUS CDR Backend";
88 static char *name = "radius";
89 static char *cdr_config = "cdr.conf";
91 static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
93 static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
95 static rc_handle *rh = NULL;
97 static int build_radius_record(VALUE_PAIR **send, struct ast_cdr *cdr)
99 int recordtype = PW_STATUS_STOP;
100 struct tm tm;
101 char timestr[128];
102 char *tmp;
104 if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0))
105 return -1;
107 /* Account code */
108 if (!rc_avpair_add(rh, send, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE))
109 return -1;
111 /* Source */
112 if (!rc_avpair_add(rh, send, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE))
113 return -1;
115 /* Destination */
116 if (!rc_avpair_add(rh, send, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE))
117 return -1;
119 /* Destination context */
120 if (!rc_avpair_add(rh, send, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE))
121 return -1;
123 /* Caller ID */
124 if (!rc_avpair_add(rh, send, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE))
125 return -1;
127 /* Channel */
128 if (!rc_avpair_add(rh, send, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE))
129 return -1;
131 /* Destination Channel */
132 if (!rc_avpair_add(rh, send, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE))
133 return -1;
135 /* Last Application */
136 if (!rc_avpair_add(rh, send, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE))
137 return -1;
139 /* Last Data */
140 if (!rc_avpair_add(rh, send, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE))
141 return -1;
144 /* Start Time */
145 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
146 gmtime_r(&(cdr->start.tv_sec), &tm);
147 else
148 ast_localtime(&(cdr->start.tv_sec), &tm, NULL);
149 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
150 if (!rc_avpair_add(rh, send, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE))
151 return -1;
153 /* Answer Time */
154 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
155 gmtime_r(&(cdr->answer.tv_sec), &tm);
156 else
157 ast_localtime(&(cdr->answer.tv_sec), &tm, NULL);
158 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
159 if (!rc_avpair_add(rh, send, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE))
160 return -1;
162 /* End Time */
163 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
164 gmtime_r(&(cdr->end.tv_sec), &tm);
165 else
166 ast_localtime(&(cdr->end.tv_sec), &tm, NULL);
167 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
168 if (!rc_avpair_add(rh, send, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE))
169 return -1;
171 /* Duration */
172 if (!rc_avpair_add(rh, send, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE))
173 return -1;
175 /* Billable seconds */
176 if (!rc_avpair_add(rh, send, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE))
177 return -1;
179 /* Disposition */
180 tmp = ast_cdr_disp2str(cdr->disposition);
181 if (!rc_avpair_add(rh, send, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE))
182 return -1;
184 /* AMA Flags */
185 tmp = ast_cdr_flags2str(cdr->amaflags);
186 if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE))
187 return -1;
189 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
190 /* Unique ID */
191 if (!rc_avpair_add(rh, send, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE))
192 return -1;
195 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) {
196 /* append the user field */
197 if (!rc_avpair_add(rh, send, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE))
198 return -1;
201 /* Setting Acct-Session-Id & User-Name attributes for proper generation
202 of Acct-Unique-Session-Id on server side */
203 /* Channel */
204 if (!rc_avpair_add(rh, send, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0))
205 return -1;
207 /* Unique ID */
208 if (!rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0))
209 return -1;
211 return 0;
214 static int radius_log(struct ast_cdr *cdr)
216 int result = ERROR_RC;
217 VALUE_PAIR *send = NULL;
219 if (build_radius_record(&send, cdr)) {
220 if (option_debug)
221 ast_log(LOG_DEBUG, "Unable to create RADIUS record. CDR not recorded!\n");
222 return result;
225 result = rc_acct(rh, 0, send);
226 if (result != OK_RC)
227 ast_log(LOG_ERROR, "Failed to record Radius CDR record!\n");
229 return result;
232 static int unload_module(void)
234 ast_cdr_unregister(name);
235 return 0;
238 static int load_module(void)
240 struct ast_config *cfg;
241 int res;
242 const char *tmp;
244 if ((cfg = ast_config_load(cdr_config))) {
245 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
246 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID);
247 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD);
248 if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg")))
249 ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
250 ast_config_destroy(cfg);
251 } else
252 return AST_MODULE_LOAD_DECLINE;
254 /* start logging */
255 rc_openlog("asterisk");
257 /* read radiusclient-ng config file */
258 if (!(rh = rc_read_config(radiuscfg))) {
259 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
260 return AST_MODULE_LOAD_DECLINE;
263 /* read radiusclient-ng dictionaries */
264 if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
265 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
266 return AST_MODULE_LOAD_DECLINE;
269 res = ast_cdr_register(name, desc, radius_log);
270 return AST_MODULE_LOAD_SUCCESS;
273 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "RADIUS CDR Backend");