/src/rtpproxy/modules/acct_csv/rtpp_acct_csv.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2006-2016 Sippy Software, Inc., http://www.sippysoft.com |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
15 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
17 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
18 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
19 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
20 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
21 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
22 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
23 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
24 | | * SUCH DAMAGE. |
25 | | * |
26 | | */ |
27 | | |
28 | | #include <sys/param.h> |
29 | | #include <sys/socket.h> |
30 | | #include <sys/stat.h> |
31 | | #include <sys/types.h> |
32 | | #include <errno.h> |
33 | | #include <inttypes.h> |
34 | | #include <fcntl.h> |
35 | | #include <limits.h> |
36 | | #include <stdbool.h> |
37 | | #include <stdint.h> |
38 | | #include <stdio.h> |
39 | | #include <stdlib.h> |
40 | | #include <string.h> |
41 | | #include <unistd.h> |
42 | | |
43 | | #include "config_pp.h" |
44 | | |
45 | | #include "rtpp_ssrc.h" |
46 | | #include "rtpa_stats.h" |
47 | | #include "rtpp_types.h" |
48 | | #include "rtpp_analyzer.h" |
49 | | #include "rtpp_pcount.h" |
50 | | #include "rtpp_time.h" |
51 | | #include "rtpp_pcnt_strm.h" |
52 | | #include "rtpp_pcnts_strm.h" |
53 | | #include "rtpp_acct_pipe.h" |
54 | | #include "rtpp_acct.h" |
55 | | #include "rtpp_module.h" |
56 | | #include "rtpp_module_acct.h" |
57 | | #include "rtpp_netaddr.h" |
58 | | #include "rtpp_network.h" |
59 | | #include "rtpp_util.h" |
60 | | #include "rtpp_cfg.h" |
61 | | #include "rtpp_log.h" |
62 | | #include "rtpp_log_obj.h" |
63 | | #include "rtpp_linker_set.h" |
64 | | #include "rtpp_str.h" |
65 | | #include "rtpp_sbuf.h" |
66 | | #include "ucl.h" |
67 | | #include "rtpp_ucl.h" |
68 | | #include "rtpp_refcnt.h" |
69 | | |
70 | | #define SSRC_STRLEN 11 |
71 | | |
72 | | struct rtpp_mod_acct_face { |
73 | | char rtp_adr[MAX_AP_STRBUF]; |
74 | | char rtcp_adr[MAX_AP_STRBUF]; |
75 | | char ssrc[SSRC_STRLEN]; |
76 | | }; |
77 | | |
78 | | struct rtpp_module_priv { |
79 | | int fd; |
80 | | pid_t pid; |
81 | | struct stat stt; |
82 | | const char *cwd_orig; |
83 | | char fname[MAXPATHLEN + 1]; |
84 | | double next_hupd_ts; |
85 | | char node_id[_POSIX_HOST_NAME_MAX + 1]; |
86 | | struct rtpp_mod_acct_face o; |
87 | | struct rtpp_mod_acct_face a; |
88 | | struct rtpp_sbuf *sbuf; |
89 | | struct rtpp_minfo *mself; |
90 | | }; |
91 | | |
92 | | /* Bump this when some changes are made */ |
93 | 66.5k | #define RTPP_METRICS_VERSION "1.2" |
94 | | |
95 | 15 | #define HNAME_REFRESH_IVAL 1.0 |
96 | | |
97 | 4 | #define DEFAULT_FNAME "rtpproxy_acct.csv" |
98 | | |
99 | | struct acct_csv_conf { |
100 | | char *logfile; |
101 | | }; |
102 | | |
103 | | struct rtpp_module_conf_pvt { |
104 | | struct acct_csv_conf conf; |
105 | | struct rtpp_module_conf pub; |
106 | | }; |
107 | | |
108 | | static struct rtpp_module_priv *rtpp_acct_csv_ctor(const struct rtpp_cfg *, |
109 | | struct rtpp_minfo *); |
110 | | static void rtpp_acct_csv_dtor(struct rtpp_module_priv *); |
111 | | static void rtpp_acct_csv_do(struct rtpp_module_priv *, struct rtpp_acct *); |
112 | | static struct rtpp_module_conf *rtpp_acct_csv_get_mconf(void); |
113 | | static int rtpp_acct_csv_config(struct rtpp_module_priv *, |
114 | | struct rtpp_module_conf *); |
115 | | static off_t rtpp_acct_csv_lockf(int); |
116 | | static void rtpp_acct_csv_unlockf(int, off_t); |
117 | | |
118 | | #ifdef RTPP_CHECK_LEAKS |
119 | | #include "rtpp_memdeb_internal.h" |
120 | | |
121 | | RTPP_MEMDEB_APP_STATIC; |
122 | | #endif |
123 | | |
124 | | static const struct rtpp_acct_handlers acct_csv_aapi = { |
125 | | .on_session_end = AAPI_FUNC(rtpp_acct_csv_do, rtpp_acct_OSIZE()) |
126 | | }; |
127 | | |
128 | | const struct rtpp_minfo RTPP_MOD_SELF = { |
129 | | .descr.name = "acct_csv", |
130 | | .descr.ver = MI_VER_INIT(), |
131 | | .descr.module_id = 1, |
132 | | .proc.ctor = rtpp_acct_csv_ctor, |
133 | | .proc.dtor = rtpp_acct_csv_dtor, |
134 | | .proc.get_mconf = rtpp_acct_csv_get_mconf, |
135 | | .proc.config = rtpp_acct_csv_config, |
136 | | #ifdef RTPP_CHECK_LEAKS |
137 | | .memdeb_p = &MEMDEB_SYM, |
138 | | #endif |
139 | | .aapi = &acct_csv_aapi, |
140 | | .fn = &(struct rtpp_minfo_fset){0}, |
141 | | }; |
142 | | #if defined(LIBRTPPROXY) |
143 | | DATA_SET(rtpp_modules, RTPP_MOD_SELF); |
144 | | #endif |
145 | | |
146 | | static const char * |
147 | | rtpp_acct_get_nid(struct rtpp_module_priv *pvt, struct rtpp_acct *ap) |
148 | 66.5k | { |
149 | | |
150 | 66.5k | if (pvt->next_hupd_ts == 0.0 || pvt->next_hupd_ts < ap->destroy_ts->mono) { |
151 | 15 | if (gethostname(pvt->node_id, sizeof(pvt->node_id)) == 0) { |
152 | 15 | pvt->next_hupd_ts = ap->destroy_ts->mono + HNAME_REFRESH_IVAL; |
153 | 15 | } |
154 | 15 | } |
155 | 66.5k | return (pvt->node_id); |
156 | 66.5k | } |
157 | | |
158 | | #define SFX_INO "_ino" |
159 | | #define SFX_INA "_ina" |
160 | | |
161 | | #define SFX_O "_o" |
162 | | #define SFX_A "_a" |
163 | | |
164 | | #define PFX_GEN "rtpp_" |
165 | | |
166 | | |
167 | | #define RVER_NM "rec_ver" |
168 | | #define NID_NM PFX_GEN "node_id" |
169 | | #define PID_NM PFX_GEN "pid" |
170 | | #define SID_NM "sess_uid" |
171 | | #define CID_NM "call_id" |
172 | | #define PT_NAME "rtpa_pt_last" |
173 | | #define PT_NM_O PT_NAME SFX_INO |
174 | | #define PT_NM_A PT_NAME SFX_INA |
175 | | #define PFX_RTP "rtp_" |
176 | | #define PFX_RTCP "rtcp_" |
177 | | #define RM_IP_NM "rmt_ip" |
178 | | #define RM_PT_NM "rmt_pt" |
179 | | #define R_RM_NM_O PFX_GEN PFX_RTP RM_IP_NM SFX_O |
180 | | #define R_RM_NM_A PFX_GEN PFX_RTP RM_IP_NM SFX_A |
181 | | #define C_RM_NM_O PFX_GEN PFX_RTCP RM_IP_NM SFX_O |
182 | | #define C_RM_NM_A PFX_GEN PFX_RTCP RM_IP_NM SFX_A |
183 | | #define R_RM_PT_NM_O PFX_GEN PFX_RTP RM_PT_NM SFX_O |
184 | | #define R_RM_PT_NM_A PFX_GEN PFX_RTP RM_PT_NM SFX_A |
185 | | #define C_RM_PT_NM_O PFX_GEN PFX_RTCP RM_PT_NM SFX_O |
186 | | #define C_RM_PT_NM_A PFX_GEN PFX_RTCP RM_PT_NM SFX_A |
187 | | |
188 | | #define HLD_CNT_NM "hld_cnt" |
189 | | #define HLD_STS_NM "hld_sts" |
190 | | #define HLD_CNT_NM_O PFX_GEN HLD_CNT_NM SFX_O |
191 | | #define HLD_CNT_NM_A PFX_GEN HLD_CNT_NM SFX_A |
192 | | #define HLD_STS_NM_O PFX_GEN HLD_STS_NM SFX_O |
193 | | #define HLD_STS_NM_A PFX_GEN HLD_STS_NM SFX_A |
194 | | |
195 | 66.5k | #define RVER_FMT "%s" |
196 | | #define NID_FMT "%s" |
197 | | #define PID_FMT "%d" |
198 | | #define SID_FMT "%" PRId64 |
199 | | #define PT_FMT "%d" |
200 | | #define LSSRC_FMT "%s" |
201 | | #define SNCHG_FMT "%lu" |
202 | | #define RM_FMT "%s" |
203 | | #define SEP "," |
204 | | #define HLD_STS_FMT "%s" |
205 | | #define HLD_CNT_FMT "%d" |
206 | | |
207 | | #define STR_INIT(str) ((const struct rtpp_str_fixed){.s = (str), .len = sizeof(str) - 1}) |
208 | | |
209 | | static const struct rtpp_str_fixed head = STR_INIT(RVER_NM SEP NID_NM SEP PID_NM SEP SID_NM |
210 | | SEP CID_NM SEP |
211 | | "from_tag,setup_ts,teardown_ts,first_rtp_ts_ino,last_rtp_ts_ino," |
212 | | "first_rtp_ts_ina,last_rtp_ts_ina,rtp_npkts_ina,rtp_npkts_ino," |
213 | | "rtp_nrelayed,rtp_ndropped,rtcp_npkts_ina,rtcp_npkts_ino," |
214 | | "rtcp_nrelayed,rtcp_ndropped,rtpa_nsent_ino,rtpa_nrcvd_ino," |
215 | | "rtpa_ndups_ino,rtpa_nlost_ino,rtpa_perrs_ino," |
216 | | "rtpa_ssrc_last_ino,rtpa_ssrc_cnt_ino" SEP PT_NM_O SEP |
217 | | "rtpa_nsent_ina,rtpa_nrcvd_ina,rtpa_ndups_ina,rtpa_nlost_ina," |
218 | | "rtpa_perrs_ina,rtpa_ssrc_last_ina,rtpa_ssrc_cnt_ina" SEP PT_NM_A SEP |
219 | | "rtpa_jitter_last_ino,rtpa_jitter_max_ino,rtpa_jitter_avg_ino," |
220 | | "rtpa_jitter_last_ina,rtpa_jitter_max_ina,rtpa_jitter_avg_ina" SEP |
221 | | R_RM_NM_O SEP R_RM_PT_NM_O SEP R_RM_NM_A SEP R_RM_PT_NM_A SEP |
222 | | C_RM_NM_O SEP C_RM_PT_NM_O SEP C_RM_NM_A SEP C_RM_PT_NM_A SEP |
223 | | HLD_STS_NM_O SEP HLD_STS_NM_A SEP HLD_CNT_NM_O SEP HLD_CNT_NM_A "\n"); |
224 | | |
225 | | static int |
226 | | rtpp_acct_csv_open(struct rtpp_module_priv *pvt) |
227 | 4 | { |
228 | 4 | int pos; |
229 | 4 | int r = 0; |
230 | | |
231 | 4 | if (pvt->fd != -1) { |
232 | 0 | close(pvt->fd); |
233 | 0 | } |
234 | 4 | pvt->fd = open(pvt->fname, O_WRONLY | O_APPEND | O_CREAT, DEFFILEMODE); |
235 | 4 | if (pvt->fd == -1) { |
236 | 0 | RTPP_ELOG(pvt->mself->log, RTPP_LOG_ERR, "can't open '%s' for writing", |
237 | 0 | pvt->fname); |
238 | 0 | goto e0; |
239 | 0 | } |
240 | 4 | pos = rtpp_acct_csv_lockf(pvt->fd); |
241 | 4 | if (pos < 0) { |
242 | 0 | RTPP_ELOG(pvt->mself->log, RTPP_LOG_ERR, "can't lock '%s'", pvt->fname); |
243 | 0 | goto e1; |
244 | 0 | } |
245 | 4 | if (fstat(pvt->fd, &pvt->stt) < 0) { |
246 | 0 | RTPP_ELOG(pvt->mself->log, RTPP_LOG_ERR, "can't get stats for '%s'", |
247 | 0 | pvt->fname); |
248 | 0 | goto e2; |
249 | 0 | } |
250 | 4 | if (pvt->stt.st_size == 0) { |
251 | 1 | do { |
252 | 1 | r = write(pvt->fd, head.s, head.len); |
253 | 1 | } while (r < 0 && errno == EINTR); |
254 | 1 | if (r > 0 && r < head.len) |
255 | 0 | r = -1; |
256 | 1 | } |
257 | 4 | rtpp_acct_csv_unlockf(pvt->fd, pos); |
258 | 4 | return (r); |
259 | | |
260 | 0 | e2: |
261 | 0 | rtpp_acct_csv_unlockf(pvt->fd, pos); |
262 | 0 | e1: |
263 | 0 | close(pvt->fd); |
264 | 0 | e0: |
265 | 0 | return (-1); |
266 | 0 | } |
267 | | |
268 | | static struct rtpp_module_priv * |
269 | | rtpp_acct_csv_ctor(const struct rtpp_cfg *cfsp, struct rtpp_minfo *mself) |
270 | 4 | { |
271 | 4 | struct rtpp_module_priv *pvt; |
272 | | |
273 | 4 | pvt = mod_zmalloc(sizeof(struct rtpp_module_priv)); |
274 | 4 | if (pvt == NULL) { |
275 | 0 | goto e0; |
276 | 0 | } |
277 | 4 | pvt->sbuf = rtpp_sbuf_ctor(head.len * 2); |
278 | 4 | if (pvt->sbuf == NULL) { |
279 | 0 | goto e1; |
280 | 0 | } |
281 | 4 | pvt->pid = getpid(); |
282 | 4 | pvt->cwd_orig = cfsp->cwd_orig; |
283 | 4 | if (gethostname(pvt->node_id, sizeof(pvt->node_id)) != 0) { |
284 | 0 | strcpy(pvt->node_id, "UNKNOWN"); |
285 | 0 | } |
286 | 4 | pvt->fd = -1; |
287 | 4 | pvt->mself = mself; |
288 | 4 | return (pvt); |
289 | | |
290 | 0 | e1: |
291 | 0 | mod_free(pvt); |
292 | 0 | e0: |
293 | 0 | return (NULL); |
294 | 0 | } |
295 | | |
296 | | static int |
297 | | rtpp_acct_csv_config(struct rtpp_module_priv *pvt, |
298 | | struct rtpp_module_conf *mcpub) |
299 | 4 | { |
300 | 4 | const char *fname = DEFAULT_FNAME; |
301 | 4 | int len; |
302 | | |
303 | 4 | if (mcpub != NULL) { |
304 | 4 | struct rtpp_module_conf_pvt *mcpvt; |
305 | | |
306 | 4 | PUB2PVT(mcpub, mcpvt); |
307 | 4 | if (mcpvt->conf.logfile != NULL) |
308 | 0 | fname = mcpvt->conf.logfile; |
309 | 4 | } |
310 | | /* Relative names are relative to the directory we have been started in */ |
311 | 4 | if (fname[0] == '/' || pvt->cwd_orig == NULL) { |
312 | 4 | len = snprintf(pvt->fname, sizeof(pvt->fname), "%s", fname); |
313 | 4 | } else { |
314 | 0 | len = snprintf(pvt->fname, sizeof(pvt->fname), "%s/%s", |
315 | 0 | pvt->cwd_orig, fname); |
316 | 0 | } |
317 | 4 | if (len < 0 || len >= (int)sizeof(pvt->fname)) { |
318 | 0 | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "logfile name is too long: %s", |
319 | 0 | fname); |
320 | 0 | return (-1); |
321 | 0 | } |
322 | 4 | if (rtpp_acct_csv_open(pvt) == -1) { |
323 | 0 | return (-1); |
324 | 0 | } |
325 | 4 | return (0); |
326 | 4 | } |
327 | | |
328 | | static bool |
329 | | conf_set_logfile(struct rtpp_log *log, const ucl_object_t *top, |
330 | | const ucl_object_t *obj, struct acct_csv_conf *target) |
331 | 0 | { |
332 | 0 | const char *val; |
333 | |
|
334 | 0 | val = ucl_object_tostring_forced(obj); |
335 | 0 | if (val == NULL || val[0] == '\0') { |
336 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, "error in config file; empty value for " |
337 | 0 | "'%s' in section '%s'", ucl_object_key(obj), ucl_object_key(top)); |
338 | 0 | return (false); |
339 | 0 | } |
340 | 0 | if (target->logfile != NULL) |
341 | 0 | mod_free(target->logfile); |
342 | 0 | target->logfile = mod_strdup(val); |
343 | 0 | if (target->logfile == NULL) |
344 | 0 | return (false); |
345 | 0 | return (true); |
346 | 0 | } |
347 | | |
348 | | static const conf_helper_map acct_csv_conf_map[] = { |
349 | | { "load", NULL }, |
350 | | { "logfile", (conf_helper_t)conf_set_logfile }, |
351 | | { NULL, (conf_helper_t)rtpp_ucl_set_unknown }, |
352 | | { NULL, NULL } |
353 | | }; |
354 | | |
355 | | static void |
356 | | mconf_dtor(struct acct_csv_conf *confp) |
357 | 4 | { |
358 | | |
359 | 4 | if (confp->logfile != NULL) |
360 | 4 | mod_free(confp->logfile); |
361 | 4 | } |
362 | | |
363 | | static struct rtpp_module_conf * |
364 | | rtpp_acct_csv_get_mconf(void) |
365 | 4 | { |
366 | 4 | struct rtpp_module_conf_pvt *cp; |
367 | | |
368 | 4 | cp = mod_rzmalloc(sizeof(*cp), PVT_RCOFFS(cp)); |
369 | 4 | if (cp == NULL) |
370 | 0 | return (NULL); |
371 | 4 | cp->pub.conf_data = &cp->conf; |
372 | 4 | cp->pub.conf_map = acct_csv_conf_map; |
373 | 4 | cp->pub.allow_noconf = 1; |
374 | 4 | RTPP_OBJ_DTOR_ATTACH_s(&(cp->pub), mconf_dtor, &cp->conf); |
375 | 4 | return (&cp->pub); |
376 | 4 | } |
377 | | |
378 | | static void |
379 | | rtpp_acct_csv_dtor(struct rtpp_module_priv *pvt) |
380 | 4 | { |
381 | | |
382 | 4 | if (pvt->fd != -1) |
383 | 4 | close(pvt->fd); |
384 | 4 | rtpp_sbuf_dtor(pvt->sbuf); |
385 | 4 | mod_free(pvt); |
386 | 4 | return; |
387 | 4 | } |
388 | | |
389 | 133k | #define ES_IF_NULL(s) ((s) == NULL ? "" : s) |
390 | 399k | #define TS2RT(ts) ((ts).wall) |
391 | | |
392 | | static void |
393 | | format_ssrc(struct rtpp_ssrc *sp, char *sbuf, size_t sblen) |
394 | 133k | { |
395 | | |
396 | 133k | if (sp->inited) { |
397 | 4.09k | snprintf(sbuf, sblen, SSRC_FMT, sp->val); |
398 | 128k | } else { |
399 | 128k | sbuf[0] = '\0'; |
400 | 128k | } |
401 | 133k | } |
402 | | |
403 | | static void |
404 | | format_netaddr(struct rtpp_netaddr *nap_rtp, struct rtpp_netaddr *nap_rtcp, |
405 | | struct rtpp_mod_acct_face *afp) |
406 | 133k | { |
407 | | |
408 | 133k | if (CALL_SMETHOD(nap_rtp, isempty)) { |
409 | 89.0k | sprintf(afp->rtp_adr, ","); |
410 | 89.0k | } else { |
411 | 43.9k | CALL_SMETHOD(nap_rtp, sip_print, afp->rtp_adr, sizeof(afp->rtp_adr), |
412 | 43.9k | ','); |
413 | 43.9k | } |
414 | 133k | if (CALL_SMETHOD(nap_rtcp, isempty)) { |
415 | 89.0k | sprintf(afp->rtcp_adr, ","); |
416 | 89.0k | } else { |
417 | 43.9k | CALL_SMETHOD(nap_rtcp, sip_print, afp->rtcp_adr, sizeof(afp->rtcp_adr), |
418 | 43.9k | ','); |
419 | 43.9k | } |
420 | 133k | } |
421 | | |
422 | 133k | #define FMT_BOOL(x) ((x == 0) ? "f" : "t") |
423 | | |
424 | | static void |
425 | | rtpp_acct_csv_do(struct rtpp_module_priv *pvt, struct rtpp_acct *acct) |
426 | 66.5k | { |
427 | 66.5k | int pos, rval; |
428 | 66.5k | struct stat stt; |
429 | | |
430 | 66.5k | rval = stat(pvt->fname, &stt); |
431 | 66.5k | if (rval != -1) { |
432 | 66.5k | if (stt.st_dev != pvt->stt.st_dev || stt.st_ino != pvt->stt.st_ino) { |
433 | 0 | if (rtpp_acct_csv_open(pvt) < 0) |
434 | 0 | return; |
435 | 0 | } |
436 | 66.5k | } else if (rval == -1 && errno == ENOENT) { |
437 | 0 | if (rtpp_acct_csv_open(pvt) < 0) |
438 | 0 | return; |
439 | 0 | } |
440 | 66.5k | pos = rtpp_acct_csv_lockf(pvt->fd); |
441 | 66.5k | if (pos < 0) { |
442 | 0 | return; |
443 | 0 | } |
444 | | |
445 | 66.5k | format_ssrc(&acct->rasta->last_ssrc, pvt->a.ssrc, sizeof(pvt->a.ssrc)); |
446 | 66.5k | format_ssrc(&acct->rasto->last_ssrc, pvt->o.ssrc, sizeof(pvt->o.ssrc)); |
447 | 66.5k | format_netaddr(acct->rtp.a.rem_addr, acct->rtcp.a.rem_addr, &pvt->a); |
448 | 66.5k | format_netaddr(acct->rtp.o.rem_addr, acct->rtcp.o.rem_addr, &pvt->o); |
449 | 66.5k | do { |
450 | 66.5k | int res = rtpp_sbuf_write(pvt->sbuf, RVER_FMT SEP NID_FMT SEP PID_FMT SEP SID_FMT SEP |
451 | 66.5k | "%s,%s,%f,%f,%f,%f,%f,%f,%lu,%lu," |
452 | 66.5k | "%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu" SEP LSSRC_FMT SEP SNCHG_FMT SEP |
453 | 66.5k | PT_FMT SEP "%lu,%lu,%lu,%lu,%lu" SEP LSSRC_FMT SEP SNCHG_FMT SEP PT_FMT SEP |
454 | 66.5k | "%f,%f,%f,%f,%f,%f" SEP RM_FMT SEP RM_FMT SEP RM_FMT SEP RM_FMT SEP |
455 | 66.5k | HLD_STS_FMT SEP HLD_STS_FMT SEP HLD_CNT_FMT SEP HLD_CNT_FMT "\n", |
456 | 66.5k | RTPP_METRICS_VERSION, rtpp_acct_get_nid(pvt, acct), |
457 | 66.5k | pvt->pid, acct->seuid, ES_IF_NULL(acct->call_id), ES_IF_NULL(acct->from_tag), |
458 | 66.5k | TS2RT(*acct->init_ts), TS2RT(*acct->destroy_ts), TS2RT(acct->rtp.o.ps->first_pkt_rcv), |
459 | 66.5k | TS2RT(acct->rtp.o.ps->last_pkt_rcv), TS2RT(acct->rtp.a.ps->first_pkt_rcv), |
460 | 66.5k | TS2RT(acct->rtp.a.ps->last_pkt_rcv), acct->rtp.a.ps->npkts_in, acct->rtp.o.ps->npkts_in, |
461 | 66.5k | acct->rtp.pcnts->nrelayed, acct->rtp.pcnts->ndropped, acct->rtcp.a.ps->npkts_in, |
462 | 66.5k | acct->rtcp.o.ps->npkts_in, acct->rtcp.pcnts->nrelayed, acct->rtcp.pcnts->ndropped, |
463 | 66.5k | acct->rasto->psent, acct->rasto->precvd, acct->rasto->pdups, acct->rasto->plost, |
464 | 66.5k | acct->rasto->pecount, pvt->o.ssrc, acct->rasto->ssrc_changes, acct->rasto->last_pt, |
465 | 66.5k | acct->rasta->psent, acct->rasta->precvd, acct->rasta->pdups, acct->rasta->plost, |
466 | 66.5k | acct->rasta->pecount, pvt->a.ssrc, acct->rasta->ssrc_changes, acct->rasta->last_pt, |
467 | 66.5k | acct->jrasto->jlast, acct->jrasto->jmax, acct->jrasto->javg, |
468 | 66.5k | acct->jrasta->jlast, acct->jrasta->jmax, acct->jrasta->javg, |
469 | 66.5k | pvt->o.rtp_adr, pvt->a.rtp_adr, pvt->o.rtcp_adr, pvt->a.rtcp_adr, |
470 | 66.5k | FMT_BOOL(acct->rtp.o.hld_stat.status), FMT_BOOL(acct->rtp.a.hld_stat.status), |
471 | 66.5k | acct->rtp.o.hld_stat.cnt, acct->rtp.a.hld_stat.cnt); |
472 | 66.5k | if (res == SBW_OK) |
473 | 66.5k | break; |
474 | 2 | if (res == SBW_SHRT) { |
475 | 2 | if (rtpp_sbuf_extend(pvt->sbuf, pvt->sbuf->alen * 2) != 0) |
476 | 0 | goto out; |
477 | 2 | continue; |
478 | 2 | } |
479 | 0 | goto out; |
480 | 2 | } while (1); |
481 | 66.5k | write(pvt->fd, pvt->sbuf->bp, RS_ULEN(pvt->sbuf)); |
482 | 66.5k | rtpp_sbuf_reset(pvt->sbuf); |
483 | 66.5k | out: |
484 | 66.5k | rtpp_acct_csv_unlockf(pvt->fd, pos); |
485 | 66.5k | } |
486 | | |
487 | | static off_t |
488 | | rtpp_acct_csv_lockf(int fd) |
489 | 66.5k | { |
490 | 66.5k | struct flock l; |
491 | 66.5k | int rval; |
492 | | |
493 | 66.5k | memset(&l, '\0', sizeof(l)); |
494 | 66.5k | l.l_whence = SEEK_CUR; |
495 | 66.5k | l.l_type = F_WRLCK; |
496 | 66.5k | do { |
497 | 66.5k | rval = fcntl(fd, F_SETLKW, &l); |
498 | 66.5k | } while (rval == -1 && errno == EINTR); |
499 | 66.5k | if (rval == -1) { |
500 | 0 | return (-1); |
501 | 0 | } |
502 | 66.5k | return lseek(fd, 0, SEEK_CUR); |
503 | 66.5k | } |
504 | | |
505 | | static void |
506 | | rtpp_acct_csv_unlockf(int fd, off_t offset) |
507 | 66.5k | { |
508 | 66.5k | struct flock l; |
509 | 66.5k | int rval; |
510 | | |
511 | 66.5k | memset(&l, '\0', sizeof(l)); |
512 | 66.5k | l.l_whence = SEEK_SET; |
513 | 66.5k | l.l_start = offset; |
514 | 66.5k | l.l_type = F_UNLCK; |
515 | 66.5k | do { |
516 | 66.5k | rval = fcntl(fd, F_SETLKW, &l); |
517 | 66.5k | } while (rval == -1 && errno == EINTR); |
518 | 66.5k | } |