acc_syslog.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  1. /*
  2. * Accounting module
  3. *
  4. * $Id$
  5. *
  6. * Copyright (C) 2001-2003 FhG FOKUS
  7. * Copyright (C) 2005 iptelorg GmbH
  8. *
  9. * This file is part of ser, a free SIP server.
  10. *
  11. * ser is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version
  15. *
  16. * For a license to use the ser software under conditions
  17. * other than those described here, or to purchase support for this
  18. * software, please contact iptel.org by e-mail at the following addresses:
  19. * [email protected]
  20. *
  21. * ser is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  29. *
  30. */
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <time.h>
  34. #include "../../sr_module.h"
  35. #include "../../dprint.h"
  36. #include "../../mem/mem.h"
  37. #include "../../modules/tm/t_hooks.h"
  38. #include "../../modules/tm/tm_load.h"
  39. #include "../../modules/tm/h_table.h"
  40. #include "../../parser/msg_parser.h"
  41. #include "../../parser/parse_from.h"
  42. #include "../../parser/digest/digest.h"
  43. #include "../../usr_avp.h"
  44. #include "../../id.h"
  45. #include "attrs.h"
  46. #include "../../modules/tm/tm_load.h"
  47. /*
  48. * TODO:
  49. * - Quote attribute values properly
  50. * - Save request timestamp
  51. * - Save response timestamp
  52. */
  53. /*
  54. * a: attr
  55. * c: sip_callid
  56. * d: to_tag
  57. * f: sip_from
  58. * g: flags
  59. * i: inbound_ruri
  60. * m: sip_method
  61. * n: sip_cseq
  62. * o: outbound_ruri
  63. * p: source_ip
  64. * r: from_tag
  65. * s: server_id
  66. * t: sip_to
  67. * u: digest_username
  68. * x: request_timestamp
  69. * D: to_did
  70. * F: from_uri
  71. * I: from_uid
  72. * M: from_did
  73. * R: digest_realm
  74. * P: source_port
  75. * S: sip_status
  76. * T: to_uri
  77. * U: to_uid
  78. * X: response_timestamp
  79. */
  80. #define ALL_LOG_FMT "acdfgimnoprstuxDFIMPRSTUX"
  81. #define ALL_LOG_FMT_LEN (sizeof(ALL_LOG_FMT) - 1)
  82. #define A_SEPARATOR ", " /* must be shorter than ACC! */
  83. #define A_SEPARATOR_LEN (sizeof(A_SEPARATOR) - 1)
  84. #define A_EQ "="
  85. #define A_EQ_LEN (sizeof(A_EQ) - 1)
  86. #define A_EOL "\n\0"
  87. #define A_EOL_LEN (sizeof(A_EOL) - 1)
  88. #define ACC "ACC: " /* Prefix of accounting messages in syslog */
  89. #define ACC_LEN (sizeof(ACC) - 1)
  90. #define ACC_REQUEST "request accounted: "
  91. #define ACC_MISSED "call missed: "
  92. #define ACC_ANSWERED "transaction answered: "
  93. #define ACC_ACKED "request acknowledged: "
  94. #define NA "n/a"
  95. #define ATR(atr) atr_arr[cnt].s = A_##atr; atr_arr[cnt].len = sizeof(A_##atr) - 1;
  96. #define A_ATTRS "attrs"
  97. #define A_CALLID "callid"
  98. #define A_TOTAG "to_tag"
  99. #define A_FROM "from"
  100. #define A_FLAGS "flags"
  101. #define A_IURI "in_ruri"
  102. #define A_METHOD "sip_method"
  103. #define A_CSEQ "cseq"
  104. #define A_OURI "out_ruri"
  105. #define A_FROMTAG "from_tag"
  106. #define A_TO "to"
  107. #define A_DIGUSER "digest_username"
  108. #define A_REQTIMESTAMP "request_timestamp"
  109. #define A_TODID "to_did"
  110. #define A_FROMURI "from_uri"
  111. #define A_FROMUID "from_uid"
  112. #define A_FROMDID "from_did"
  113. #define A_DIGREALM "digest_realm"
  114. #define A_STATUS "sip_status"
  115. #define A_TOURI "to_uri"
  116. #define A_TOUID "to_uid"
  117. #define A_RESTIMESTAMP "response_timestamp"
  118. #define A_SRCIP "src_ip"
  119. #define A_SRCPORT "src_port"
  120. #define A_SERVERID "server_id"
  121. MODULE_VERSION
  122. struct tm_binds tmb;
  123. static int mod_init( void );
  124. static int fix_log_flag( modparam_t type, void* val);
  125. static int fix_log_missed_flag( modparam_t type, void* val);
  126. static int log_level = L_NOTICE; /* noisiness level logging facilities are used */
  127. static int early_media = 0; /* Enable/disable early media (183) accounting */
  128. static int failed_transactions = 0; /* Enable/disable accounting of failed (>= 300) transactions */
  129. static int report_cancels = 0; /* Enable/disable CANCEL reporting */
  130. static int report_ack = 0; /* Enable/disable end-to-end ACK reports */
  131. static int log_flag = 0; /* Flag that marks transactions to be accounted */
  132. static int log_missed_flag = 0; /* Transaction having this flag set will be accounted in missed calls when fails */
  133. static char* log_fmt = ALL_LOG_FMT; /* Formating string that controls what information will be collected and accounted */
  134. /* Attribute-value pairs */
  135. static char* attrs = "";
  136. avp_ident_t* avps;
  137. int avps_n;
  138. static int acc_log_request0(struct sip_msg *rq, char *p1, char *p2);
  139. static int acc_log_missed0(struct sip_msg *rq, char *p1, char *p2);
  140. static int acc_log_request1(struct sip_msg *rq, char *p1, char *p2);
  141. static int acc_log_missed1(struct sip_msg *rq, char *p1, char *p2);
  142. static str na = STR_STATIC_INIT(NA);
  143. static cmd_export_t cmds[] = {
  144. {"acc_syslog_log", acc_log_request0, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
  145. {"acc_syslog_missed", acc_log_missed0, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
  146. {"acc_syslog_log", acc_log_request1, 1, fixup_var_str_1, REQUEST_ROUTE | FAILURE_ROUTE},
  147. {"acc_syslog_missed", acc_log_missed1, 1, fixup_var_str_1, REQUEST_ROUTE | FAILURE_ROUTE},
  148. {0, 0, 0, 0, 0}
  149. };
  150. static param_export_t params[] = {
  151. {"early_media", PARAM_INT, &early_media },
  152. {"failed_transactions", PARAM_INT, &failed_transactions },
  153. {"report_ack", PARAM_INT, &report_ack },
  154. {"report_cancels", PARAM_INT, &report_cancels },
  155. {"log_flag", PARAM_INT, &log_flag },
  156. {"log_flag", PARAM_STRING|PARAM_USE_FUNC, fix_log_flag},
  157. {"log_missed_flag", PARAM_INT, &log_missed_flag },
  158. {"log_missed_flag", PARAM_STRING|PARAM_USE_FUNC, fix_log_missed_flag},
  159. {"log_level", PARAM_INT, &log_level },
  160. {"log_fmt", PARAM_STRING, &log_fmt },
  161. {"attrs", PARAM_STRING, &attrs },
  162. {0, 0, 0}
  163. };
  164. struct module_exports exports= {
  165. "acc_syslog",
  166. cmds, /* exported functions */
  167. 0, /* RPC methods */
  168. params, /* exported params */
  169. mod_init, /* initialization module */
  170. 0, /* response function */
  171. 0, /* destroy function */
  172. 0, /* oncancel function */
  173. 0 /* per-child init function */
  174. };
  175. /* fixes log_flag param (resolves possible named flags) */
  176. static int fix_log_flag( modparam_t type, void* val)
  177. {
  178. return fix_flag(type, val, "acc_syslog", "log_flag", &log_flag);
  179. }
  180. /* fixes log_missed_flag param (resolves possible named flags) */
  181. static int fix_log_missed_flag( modparam_t type, void* val)
  182. {
  183. return fix_flag(type, val, "acc_syslog", "log_missed_flag", &log_missed_flag);
  184. }
  185. #define TM_BUF_LEN sizeof("10000-12-31 23:59:59")
  186. static inline int convert_time(str* buf, time_t time)
  187. {
  188. struct tm* tm;
  189. if (!buf->s || buf->len < TM_BUF_LEN) {
  190. LOG(L_ERR, "ERROR:acc:convert_time: Buffer too short\n");
  191. return -1;
  192. }
  193. tm = gmtime(&time);
  194. buf->len = strftime(buf->s, buf->len, "%Y-%m-%d %H:%M:%S", tm);
  195. return 0;
  196. }
  197. static inline int skip_cancel(struct sip_msg *msg)
  198. {
  199. return (msg->REQ_METHOD == METHOD_CANCEL) && report_cancels == 0;
  200. }
  201. /*
  202. * Append a constant string, uses sizeof to figure the length
  203. * of the string
  204. */
  205. #define append(buf, ptr) \
  206. do { \
  207. memcpy((buf).s, (ptr), sizeof(ptr) - 1); \
  208. (buf).s += sizeof(ptr) - 1; \
  209. (buf).len -= sizeof(ptr) - 1; \
  210. } while(0);
  211. #define str_append_str(buf, str) \
  212. do { \
  213. memcpy((buf).s, (str).s, (str).len); \
  214. (buf).s += (str).len; \
  215. (buf).len -= (str).len; \
  216. } while(0);
  217. int verify_fmt(char *fmt) {
  218. if (!fmt) {
  219. LOG(L_ERR, "ERROR:acc:verify_fmt: formatting string zero\n");
  220. return -1;
  221. }
  222. if (!(*fmt)) {
  223. LOG(L_ERR, "ERROR:acc:verify_fmt: formatting string empty\n");
  224. return -1;
  225. }
  226. if (strlen(fmt) > ALL_LOG_FMT_LEN) {
  227. LOG(L_ERR, "ERROR:acc:verify_fmt: formatting string too long\n");
  228. return -1;
  229. }
  230. while(*fmt) {
  231. if (!strchr(ALL_LOG_FMT, *fmt)) {
  232. LOG(L_ERR, "ERROR:acc:verify_fmt: char in log_fmt invalid: %c\n", *fmt);
  233. return -1;
  234. }
  235. fmt++;
  236. }
  237. return 1;
  238. }
  239. /*
  240. * Return true if accounting is enabled and the
  241. * transaction is marked for accounting
  242. */
  243. static inline int is_acc_on(struct sip_msg *rq)
  244. {
  245. return log_flag && isflagset(rq, log_flag) == 1;
  246. }
  247. /*
  248. * Return true if missed_call accounting is enabled
  249. * and the transaction has the flag set
  250. */
  251. static inline int is_mc_on(struct sip_msg *rq)
  252. {
  253. return log_missed_flag && isflagset(rq, log_missed_flag) == 1;
  254. }
  255. static inline void preparse_req(struct sip_msg *rq)
  256. {
  257. /* try to parse from for From-tag for accounted transactions;
  258. * don't be worried about parsing outcome -- if it failed,
  259. * we will report N/A. There is no need to parse digest credentials
  260. * here even if we account them, because the authentication function
  261. * will do it before us and if not then we will account n/a.
  262. */
  263. parse_headers(rq, HDR_CALLID_F | HDR_FROM_F | HDR_TO_F | HDR_CSEQ_F, 0 );
  264. parse_from_header(rq);
  265. }
  266. /* is this reply of interest for accounting ? */
  267. static inline int should_acc_reply(struct cell* t, int code)
  268. {
  269. struct sip_msg *r;
  270. r = t->uas.request;
  271. /* validation */
  272. if (r == 0) {
  273. LOG(L_ERR, "ERROR:acc:should_acc_reply: 0 request\n");
  274. return 0;
  275. }
  276. /* negative transactions reported otherwise only if explicitly
  277. * demanded */
  278. if (!failed_transactions && code >= 300) return 0;
  279. if (!is_acc_on(r)) return 0;
  280. if (skip_cancel(r)) return 0;
  281. if (code < 200 && ! (early_media && code == 183)) return 0;
  282. return 1; /* seed is through, we will account this reply */
  283. }
  284. /* Extract username attribute from authorized credentials */
  285. static inline str* cred_user(struct sip_msg* rq)
  286. {
  287. struct hdr_field* h;
  288. auth_body_t* cred;
  289. get_authorized_cred(rq->proxy_auth, &h);
  290. if (!h) get_authorized_cred(rq->authorization, &h);
  291. if (!h) return 0;
  292. cred = (auth_body_t*)(h->parsed);
  293. if (!cred || !cred->digest.username.user.len)
  294. return 0;
  295. return &cred->digest.username.user;
  296. }
  297. /* Extract realm attribute from authorized credentials */
  298. static inline str* cred_realm(struct sip_msg* rq)
  299. {
  300. str* realm;
  301. struct hdr_field* h;
  302. auth_body_t* cred;
  303. get_authorized_cred(rq->proxy_auth, &h);
  304. if (!h) get_authorized_cred(rq->authorization, &h);
  305. if (!h) return 0;
  306. cred = (auth_body_t*)(h->parsed);
  307. if (!cred) return 0;
  308. realm = GET_REALM(&cred->digest);
  309. if (!realm->len || !realm->s) {
  310. return 0;
  311. }
  312. return realm;
  313. }
  314. /* Return To header field from the request in case of faked reply or
  315. * missing To header field in the reply
  316. */
  317. static inline struct hdr_field* valid_to(struct cell* t, struct sip_msg* reply)
  318. {
  319. if (reply == FAKED_REPLY || !reply || !reply->to) {
  320. return t->uas.request->to;
  321. } else {
  322. return reply->to;
  323. }
  324. }
  325. /* create an array of str's for accounting using a formatting string;
  326. * this is the heart of the accounting module -- it prints whatever
  327. * requested in a way, that can be used for syslog, radius,
  328. * sql, whatsoever
  329. * tm sip_msg_clones does not clone (shmmem-zed) parsed fields, other then Via1,2. Such fields clone now or use from rq_rp
  330. */
  331. static int fmt2strar(char *fmt, /* what would you like to account ? */
  332. struct sip_msg *rq, /* accounted message */
  333. str* ouri, /* Outbound Request-URI */
  334. struct hdr_field *to, /* To header field (used to extract tag) */
  335. str *phrase,
  336. int *total_len, /* total length of accounted values */
  337. int *attr_len, /* total length of accounted attribute names */
  338. str **val_arr, /* that's the output -- must have MAX_ACC_COLUMNS */
  339. str *atr_arr,
  340. time_t req_time) /* Timestamp of the request */
  341. {
  342. static char flags_buf[INT2STR_MAX_LEN], tm_buf[TM_BUF_LEN],
  343. rqtm_buf[TM_BUF_LEN], srcip_buf[IP_ADDR_MAX_STR_SIZE],
  344. srcport_buf[INT2STR_MAX_LEN], serverid_buf[INT2STR_MAX_LEN];
  345. int cnt, tl, al;
  346. struct to_body* from, *pto;
  347. static str mycode, flags, tm_s, rqtm_s, src_ip, src_port, from_uid, to_uid, server_id_str;
  348. str *cr, *at;
  349. struct cseq_body *cseq;
  350. char* p;
  351. cnt = tl = al = 0;
  352. /* we don't care about parsing here; either the function
  353. * was called from script, in which case the wrapping function
  354. * is supposed to parse, or from reply processing in which case
  355. * TM should have preparsed from REQUEST_IN callback; what's not
  356. * here is replaced with NA
  357. */
  358. while(*fmt) {
  359. if (cnt == ALL_LOG_FMT_LEN) {
  360. LOG(L_ERR, "ERROR:acc:fmt2strar: Formatting string is too long\n");
  361. return 0;
  362. }
  363. switch(*fmt) {
  364. case 'a': /* attr */
  365. at = print_attrs(avps, avps_n, 1);
  366. if (!at) {
  367. val_arr[cnt] = &na;
  368. } else {
  369. val_arr[cnt] = at;
  370. }
  371. ATR(ATTRS);
  372. break;
  373. case 'c': /* sip_callid */
  374. val_arr[cnt] = (rq->callid && rq->callid->body.len) ? &rq->callid->body : &na;
  375. ATR(CALLID);
  376. break;
  377. case 'd': /* to_tag */
  378. val_arr[cnt] = (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) ? & pto->tag_value : &na;
  379. ATR(TOTAG);
  380. break;
  381. case 'f': /* sip_from */
  382. val_arr[cnt] = (rq->from && rq->from->body.len) ? &rq->from->body : &na;
  383. ATR(FROM);
  384. break;
  385. case 'g': /* flags */
  386. p = int2str(rq->flags, &flags.len);
  387. memcpy(flags_buf, p, flags.len);
  388. flags.s = flags_buf;
  389. val_arr[cnt] = &flags;
  390. ATR(FLAGS);
  391. break;
  392. case 'i': /* inbound_ruri */
  393. val_arr[cnt] = &rq->first_line.u.request.uri;
  394. ATR(IURI);
  395. break;
  396. case 'm': /* sip_method */
  397. val_arr[cnt] = &rq->first_line.u.request.method;
  398. ATR(METHOD);
  399. break;
  400. case 'n': /* sip_cseq */
  401. if (rq->cseq && (cseq = get_cseq(rq)) && cseq->number.len) val_arr[cnt] = &cseq->number;
  402. else val_arr[cnt]=&na;
  403. ATR(CSEQ);
  404. break;
  405. case 'o': /* outbound_ruri */
  406. val_arr[cnt] = ouri;
  407. ATR(OURI);
  408. break;
  409. case 'p': /* source_ip */
  410. /* We need to make a copy of the string here because ip_addr2a uses static
  411. * buffer and subseqent calls to the function would destroy the result
  412. */
  413. src_ip.s = srcip_buf;
  414. p = ip_addr2a(&rq->rcv.src_ip);
  415. src_ip.len = strlen(p);
  416. memcpy(src_ip.s, p, src_ip.len);
  417. val_arr[cnt] = &src_ip;
  418. ATR(SRCIP);
  419. break;
  420. case 'r': /* from_tag */
  421. if (rq->from && (from = get_from(rq)) && from->tag_value.len) {
  422. val_arr[cnt] = &from->tag_value;
  423. } else {
  424. val_arr[cnt] = &na;
  425. }
  426. ATR(FROMTAG);
  427. break;
  428. case 's': /* server_id */
  429. p = int2str(server_id, &server_id_str.len);
  430. memcpy(serverid_buf, p, server_id_str.len);
  431. server_id_str.s = serverid_buf;
  432. val_arr[cnt] = &server_id_str;
  433. ATR(SERVERID);
  434. break;
  435. case 't': /* sip_to */
  436. val_arr[cnt] = (to && to->body.len) ? &to->body : &na;
  437. ATR(TO);
  438. break;
  439. case 'u': /* digest_username */
  440. cr = cred_user(rq);
  441. if (cr) val_arr[cnt] = cr;
  442. else val_arr[cnt] = &na;
  443. ATR(DIGUSER);
  444. break;
  445. case 'x': /* request_timestamp */
  446. rqtm_s.s = rqtm_buf;
  447. rqtm_s.len = TM_BUF_LEN;
  448. convert_time(&rqtm_s, req_time);
  449. val_arr[cnt] = &rqtm_s;
  450. ATR(REQTIMESTAMP);
  451. break;
  452. case 'D': /* to_did */
  453. val_arr[cnt] = &na;
  454. ATR(TODID);
  455. break;
  456. case 'F': /* from_uri */
  457. if (rq->from && (from = get_from(rq)) && from->uri.len) {
  458. val_arr[cnt] = &from->uri;
  459. } else val_arr[cnt] = &na;
  460. ATR(FROMURI);
  461. break;
  462. case 'I': /* from_uid */
  463. if (get_from_uid(&from_uid, rq) < 0) {
  464. val_arr[cnt] = &na;
  465. } else {
  466. val_arr[cnt] = &from_uid;
  467. }
  468. ATR(FROMUID);
  469. break;
  470. case 'M': /* from_did */
  471. val_arr[cnt] = &na;
  472. ATR(FROMDID);
  473. break;
  474. case 'P': /* source_port */
  475. p = int2str(rq->rcv.src_port, &src_port.len);
  476. memcpy(srcport_buf, p, src_port.len);
  477. src_port.s = srcport_buf;
  478. val_arr[cnt] = &src_port;
  479. ATR(SRCPORT);
  480. break;
  481. case 'R': /* digest_realm */
  482. cr = cred_realm(rq);
  483. if (cr) val_arr[cnt] = cr;
  484. else val_arr[cnt] = &na;
  485. ATR(DIGREALM);
  486. break;
  487. case 'S': /* sip_status */
  488. if (phrase->len >= 3) {
  489. mycode.s = phrase->s;
  490. mycode.len = 3;
  491. val_arr[cnt] = &mycode;
  492. } else val_arr[cnt] = &na;
  493. ATR(STATUS);
  494. break;
  495. case 'T': /* to_uri */
  496. if (rq->to && (pto = get_to(rq)) && pto->uri.len) val_arr[cnt] = &pto->uri;
  497. else val_arr[cnt] = &na;
  498. ATR(TOURI);
  499. break;
  500. case 'U': /* to_uid */
  501. if (get_to_uid(&to_uid, rq) < 0) {
  502. val_arr[cnt] = &na;
  503. } else {
  504. val_arr[cnt] = &to_uid;
  505. }
  506. ATR(TOUID);
  507. break;
  508. case 'X': /* response_timestamp */
  509. tm_s.s = tm_buf;
  510. tm_s.len = TM_BUF_LEN;
  511. convert_time(&tm_s, time(0));
  512. val_arr[cnt] = &tm_s;
  513. ATR(RESTIMESTAMP);
  514. break;
  515. default:
  516. LOG(L_CRIT, "BUG:acc:fmt2strar: unknown char: %c\n", *fmt);
  517. return 0;
  518. } /* switch (*fmt) */
  519. tl += val_arr[cnt]->len;
  520. al += atr_arr[cnt].len;
  521. fmt++;
  522. cnt++;
  523. } /* while (*fmt) */
  524. *total_len = tl;
  525. *attr_len = al;
  526. return cnt;
  527. }
  528. static int log_request(struct sip_msg* rq, str* ouri, struct hdr_field* to, str* txt, str* phrase, time_t req_time)
  529. {
  530. static str* val_arr[ALL_LOG_FMT_LEN];
  531. static str atr_arr[ALL_LOG_FMT_LEN];
  532. int len, attr_cnt, attr_len, i;
  533. char *log_msg;
  534. str buf;
  535. if (skip_cancel(rq)) return 1;
  536. attr_cnt = fmt2strar(log_fmt, rq, ouri, to, phrase, &len, &attr_len, val_arr, atr_arr, req_time);
  537. if (!attr_cnt) {
  538. LOG(L_ERR, "ERROR:acc:log_request: fmt2strar failed\n");
  539. return -1;
  540. }
  541. len += attr_len + ACC_LEN + txt->len + A_EOL_LEN + attr_cnt * (A_SEPARATOR_LEN + A_EQ_LEN) - A_SEPARATOR_LEN;
  542. log_msg = pkg_malloc(len);
  543. if (!log_msg) {
  544. LOG(L_ERR, "ERROR:acc:log_request: No memory left for %d bytes\n", len);
  545. return -1;
  546. }
  547. /* skip leading text and begin with first item's
  548. * separator ", " which will be overwritten by the
  549. * leading text later
  550. * */
  551. buf.s = log_msg + ACC_LEN + txt->len - A_SEPARATOR_LEN;
  552. buf.len = len - ACC_LEN - txt->len + A_SEPARATOR_LEN;
  553. for (i = 0; i < attr_cnt; i++) {
  554. append(buf, A_SEPARATOR);
  555. str_append_str(buf, atr_arr[i]);
  556. append(buf, A_EQ);
  557. str_append_str(buf, *(val_arr[i]))
  558. }
  559. /* terminating text */
  560. append(buf, A_EOL);
  561. /* leading text */
  562. buf.s = log_msg;
  563. buf.len = len;
  564. append(buf, ACC);
  565. str_append_str(buf, *txt);
  566. LOG(log_level, "%s", log_msg);
  567. pkg_free(log_msg);
  568. return 1;
  569. }
  570. static void log_reply(struct cell* t , struct sip_msg* reply, unsigned int code, time_t req_time)
  571. {
  572. str code_str, *ouri;
  573. static str lead = STR_STATIC_INIT(ACC_ANSWERED);
  574. static char code_buf[INT2STR_MAX_LEN];
  575. char* p;
  576. p = int2str(code, &code_str.len);
  577. memcpy(code_buf, p, code_str.len);
  578. code_str.s = code_buf;
  579. if (t->relayed_reply_branch >= 0) {
  580. ouri = &t->uac[t->relayed_reply_branch].uri;
  581. } else {
  582. ouri = GET_NEXT_HOP(t->uas.request);
  583. }
  584. log_request(t->uas.request, ouri, valid_to(t,reply), &lead, &code_str, req_time);
  585. }
  586. static void log_ack(struct cell* t , struct sip_msg *ack, time_t req_time)
  587. {
  588. struct sip_msg *rq;
  589. struct hdr_field *to;
  590. static str lead = STR_STATIC_INIT(ACC_ACKED);
  591. static char code_buf[INT2STR_MAX_LEN];
  592. str code_str;
  593. char* p;
  594. rq = t->uas.request;
  595. if (ack->to) to = ack->to;
  596. else to = rq->to;
  597. p = int2str(t->uas.status, &code_str.len);
  598. memcpy(code_buf, p, code_str.len);
  599. code_str.s = code_buf;
  600. log_request(ack, GET_RURI(ack), to, &lead, &code_str, req_time);
  601. }
  602. static void log_missed(struct cell* t, struct sip_msg* reply, unsigned int code, time_t req_time)
  603. {
  604. str acc_text, *ouri;
  605. static str leading_text = STR_STATIC_INIT(ACC_MISSED);
  606. get_reply_status(&acc_text, reply, code);
  607. if (acc_text.s == 0) {
  608. LOG(L_ERR, "ERROR:acc:log_missed: get_reply_status failed\n" );
  609. return;
  610. }
  611. if (t->relayed_reply_branch >= 0) {
  612. ouri = &t->uac[t->relayed_reply_branch].uri;
  613. } else {
  614. ouri = GET_NEXT_HOP(t->uas.request);
  615. }
  616. log_request(t->uas.request, ouri, valid_to(t, reply), &leading_text, &acc_text, req_time);
  617. pkg_free(acc_text.s);
  618. }
  619. /* these wrappers parse all what may be needed; they don't care about
  620. * the result -- accounting functions just display "unavailable" if there
  621. * is nothing meaningful
  622. */
  623. static int acc_log_request1(struct sip_msg *rq, char* p1, char* p2)
  624. {
  625. str phrase;
  626. str txt = STR_STATIC_INIT(ACC_REQUEST);
  627. if (get_str_fparam(&phrase, rq, (fparam_t*)p1) < 0) {
  628. phrase.s = 0;
  629. phrase.len = 0;
  630. }
  631. preparse_req(rq);
  632. return log_request(rq, GET_RURI(rq), rq->to, &txt, &phrase, time(0));
  633. }
  634. /* these wrappers parse all what may be needed; they don't care about
  635. * the result -- accounting functions just display "unavailable" if there
  636. * is nothing meaningful
  637. */
  638. static int acc_log_missed1(struct sip_msg *rq, char* p1, char* p2)
  639. {
  640. str phrase;
  641. str txt = STR_STATIC_INIT(ACC_MISSED);
  642. if (get_str_fparam(&phrase, rq, (fparam_t*)p1) < 0) {
  643. phrase.s = 0;
  644. phrase.len = 0;
  645. }
  646. preparse_req(rq);
  647. return log_request(rq, GET_RURI(rq), rq->to, &txt, &phrase, time(0));
  648. }
  649. /* these wrappers parse all what may be needed; they don't care about
  650. * the result -- accounting functions just display "unavailable" if there
  651. * is nothing meaningful
  652. */
  653. static int acc_log_request0(struct sip_msg *rq, char* p1, char* p2)
  654. {
  655. static str phrase = STR_NULL;
  656. str txt = STR_STATIC_INIT(ACC_REQUEST);
  657. return log_request(rq, GET_RURI(rq), rq->to, &txt, &phrase, time(0));
  658. }
  659. /* these wrappers parse all what may be needed; they don't care about
  660. * the result -- accounting functions just display "unavailable" if there
  661. * is nothing meaningful
  662. */
  663. static int acc_log_missed0(struct sip_msg *rq, char* p1, char* p2)
  664. {
  665. static str phrase = STR_NULL;
  666. str txt = STR_STATIC_INIT(ACC_MISSED);
  667. preparse_req(rq);
  668. return log_request(rq, GET_RURI(rq), rq->to, &txt, &phrase, time(0));
  669. }
  670. static void ack_handler(struct cell* t, int type, struct tmcb_params* ps)
  671. {
  672. if (is_acc_on(t->uas.request)) {
  673. preparse_req(ps->req);
  674. log_ack(t, ps->req, (time_t)*(ps->param));
  675. }
  676. }
  677. /* initiate a report if we previously enabled MC accounting for this t */
  678. static void failure_handler(struct cell *t, int type, struct tmcb_params* ps)
  679. {
  680. /* validation */
  681. if (t->uas.request == 0) {
  682. DBG("DBG:acc:failure_handler: No uas.request, skipping local transaction\n");
  683. return;
  684. }
  685. if (is_invite(t) && ps->code >= 300) {
  686. if (is_mc_on(t->uas.request)) {
  687. log_missed(t, ps->rpl, ps->code, (time_t)*(ps->param));
  688. resetflag(t->uas.request, log_missed_flag);
  689. }
  690. }
  691. }
  692. /* initiate a report if we previously enabled accounting for this t */
  693. static void replyout_handler(struct cell* t, int type, struct tmcb_params* ps)
  694. {
  695. if (t->uas.request == 0) {
  696. DBG("DBG:acc:replyout_handler: No uas.request, local transaction, skipping\n");
  697. return;
  698. }
  699. /* acc_onreply is bound to TMCB_REPLY which may be called
  700. * from _reply, like when FR hits; we should not miss this
  701. * event for missed calls either
  702. */
  703. failure_handler(t, type, ps);
  704. if (!should_acc_reply(t, ps->code)) return;
  705. if (is_acc_on(t->uas.request)) log_reply(t, ps->rpl, ps->code, (time_t)*(ps->param));
  706. }
  707. /* parse incoming replies before cloning */
  708. static void replyin_handler(struct cell *t, int type, struct tmcb_params* ps)
  709. {
  710. /* validation */
  711. if (t->uas.request == 0) {
  712. LOG(L_ERR, "ERROR:acc:replyin_handler:replyin_handler: 0 request\n");
  713. return;
  714. }
  715. /* don't parse replies in which we are not interested */
  716. /* missed calls enabled ? */
  717. if (((is_invite(t) && ps->code >= 300 && is_mc_on(t->uas.request))
  718. || should_acc_reply(t, ps->code))
  719. && (ps->rpl && ps->rpl != FAKED_REPLY)) {
  720. parse_headers(ps->rpl, HDR_TO_F, 0);
  721. }
  722. }
  723. /* prepare message and transaction context for later accounting */
  724. void on_req(struct cell* t, int type, struct tmcb_params *ps)
  725. {
  726. time_t req_time;
  727. /* Pass the timestamp of the request as a parameter to callbacks */
  728. req_time = time(0);
  729. if (is_acc_on(ps->req) || is_mc_on(ps->req)) {
  730. if (tmb.register_tmcb(0, t, TMCB_RESPONSE_OUT, replyout_handler,
  731. (void*)req_time, 0) <= 0) {
  732. LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_RESPONSE_OUT callback\n");
  733. return;
  734. }
  735. if (report_ack) {
  736. if (tmb.register_tmcb(0, t, TMCB_E2EACK_IN, ack_handler,
  737. (void*)req_time, 0) <= 0) {
  738. LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_E2EACK_IN callback\n");
  739. return;
  740. }
  741. }
  742. if (tmb.register_tmcb(0, t, TMCB_ON_FAILURE_RO, failure_handler,
  743. (void*)req_time, 0) <= 0) {
  744. LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_ON_FAILURE_RO callback\n");
  745. return;
  746. }
  747. if (tmb.register_tmcb(0, t, TMCB_RESPONSE_IN, replyin_handler,
  748. (void*)req_time, 0) <= 0) {
  749. LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_RESPONSE_IN callback\n");
  750. return;
  751. }
  752. /* do some parsing in advance */
  753. preparse_req(ps->req);
  754. /* also, if that is INVITE, disallow silent t-drop */
  755. if (ps->req->REQ_METHOD == METHOD_INVITE) {
  756. DBG("DEBUG: noisy_timer set for accounting\n");
  757. t->flags |= T_NOISY_CTIMER_FLAG;
  758. }
  759. }
  760. }
  761. static int mod_init(void)
  762. {
  763. load_tm_f load_tm;
  764. /* import the TM auto-loading function */
  765. if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) {
  766. LOG(L_ERR, "ERROR:acc:mod_init: can't import load_tm\n");
  767. return -1;
  768. }
  769. /* let the auto-loading function load all TM stuff */
  770. if (load_tm( &tmb )==-1) return -1;
  771. if (verify_fmt(log_fmt)==-1) return -1;
  772. /* register callbacks*/
  773. /* listen for all incoming requests */
  774. if (tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, on_req, 0, 0) <= 0) {
  775. LOG(L_ERR,"ERROR:acc:mod_init: cannot register TMCB_REQUEST_IN "
  776. "callback\n");
  777. return -1;
  778. }
  779. if (parse_attrs(&avps, &avps_n, attrs) < 0) {
  780. ERR("Error while parsing 'attrs' module parameter\n");
  781. return -1;
  782. }
  783. return 0;
  784. }