Coverage Report

Created: 2026-10-28 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}