Coverage Report

Created: 2025-10-13 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/src/rtpp_syslog_async.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2009 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
#if defined(LINUX_XXX) && !defined(_GNU_SOURCE)
29
#define _GNU_SOURCE /* pthread_setname_np() */
30
#endif
31
32
#include <pthread.h>
33
#include <syslog.h>
34
#include <stdarg.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
39
#include "config.h"
40
41
#ifndef HAVE_STRLCPY
42
#include "rtpp_types.h"
43
#include "rtpp_util.h"
44
#endif
45
46
#include "rtpp_debug.h"
47
#include "rtpp_syslog_async.h"
48
49
0
#define SYSLOG_WI_POOL_SIZE     64
50
#define SYSLOG_WI_DATA_LEN      2048
51
52
typedef enum {
53
    SYSLOG_ITEM_ASYNC_WRITE,
54
    SYSLOG_ITEM_ASYNC_EXIT
55
} item_types;
56
57
struct syslog_wi
58
{
59
    item_types item_type;
60
    char data[SYSLOG_WI_DATA_LEN];
61
    int len;
62
    int priority;
63
    struct syslog_wi *next;
64
};
65
66
0
#define SYSLOG_WI_NOWAIT        0
67
0
#define SYSLOG_WI_WAIT          1
68
69
static pthread_mutex_t syslog_init_mutex = PTHREAD_MUTEX_INITIALIZER;
70
static int syslog_queue_inited = 0;
71
static pthread_t syslog_queue;
72
static pthread_cond_t syslog_queue_cond;
73
static pthread_mutex_t syslog_queue_mutex;
74
static pthread_cond_t syslog_wi_free_cond;
75
static pthread_mutex_t syslog_wi_free_mutex;
76
77
static int syslog_dropped_items;
78
79
static struct syslog_wi syslog_wi_pool[SYSLOG_WI_POOL_SIZE];
80
static struct syslog_wi *syslog_wi_free;
81
static struct syslog_wi *syslog_wi_queue, *syslog_wi_queue_tail;
82
83
static void
84
syslog_queue_run(void)
85
0
{
86
0
    struct syslog_wi *wi;
87
88
0
    for (;;) {
89
0
        pthread_mutex_lock(&syslog_queue_mutex);
90
0
        while (syslog_wi_queue == NULL) {
91
0
            pthread_cond_wait(&syslog_queue_cond, &syslog_queue_mutex);
92
0
        }
93
0
        wi = syslog_wi_queue;
94
0
        syslog_wi_queue = wi->next;
95
0
        pthread_mutex_unlock(&syslog_queue_mutex);
96
97
        /* main work here */
98
0
        switch (wi->item_type) {
99
0
            case SYSLOG_ITEM_ASYNC_WRITE:
100
0
                syslog(wi->priority, "%s", wi->data);
101
0
                break;
102
103
0
            case SYSLOG_ITEM_ASYNC_EXIT:
104
0
                return;
105
106
0
            default:
107
0
                break;
108
0
        }
109
110
        /* put wi into syslog_wi_free' tail */
111
0
        pthread_mutex_lock(&syslog_wi_free_mutex);
112
113
0
        wi->next = syslog_wi_free;
114
0
        syslog_wi_free = wi;
115
116
0
        pthread_cond_signal(&syslog_wi_free_cond);
117
0
        pthread_mutex_unlock(&syslog_wi_free_mutex);
118
0
    }
119
0
}
120
121
static int
122
syslog_queue_init(void)
123
0
{
124
0
    int i;
125
126
0
    memset(syslog_wi_pool, 0, sizeof(syslog_wi_pool));
127
0
    for (i = 0; i < SYSLOG_WI_POOL_SIZE - 1; i++) {
128
0
        syslog_wi_pool[i].next = &syslog_wi_pool[i + 1];
129
0
    }
130
0
    syslog_wi_pool[SYSLOG_WI_POOL_SIZE - 1].next = NULL;
131
132
0
    syslog_wi_free = syslog_wi_pool;
133
0
    syslog_wi_queue = NULL;
134
0
    syslog_wi_queue_tail = NULL;
135
136
0
    syslog_dropped_items = 0;
137
138
0
    if (pthread_cond_init(&syslog_queue_cond, NULL) != 0)
139
0
        goto e0;
140
0
    if (pthread_mutex_init(&syslog_queue_mutex, NULL) != 0)
141
0
        goto e1;
142
0
    if (pthread_cond_init(&syslog_wi_free_cond, NULL)  != 0)
143
0
        goto e2;
144
0
    if (pthread_mutex_init(&syslog_wi_free_mutex, NULL)  != 0)
145
0
        goto e3;
146
0
    if (pthread_create(&syslog_queue, NULL, (void *(*)(void *))&syslog_queue_run, NULL) != 0)
147
0
        goto e4;
148
0
#if HAVE_PTHREAD_SETNAME_NP
149
0
    (void)pthread_setname_np(syslog_queue, "syslog_queue");
150
0
#endif
151
152
0
    return 0;
153
0
e4:
154
0
    pthread_mutex_destroy(&syslog_wi_free_mutex);
155
0
e3:
156
0
    pthread_cond_destroy(&syslog_wi_free_cond);
157
0
e2:
158
0
    pthread_mutex_destroy(&syslog_queue_mutex);
159
0
e1:
160
0
    pthread_cond_destroy(&syslog_queue_cond);
161
0
e0:
162
0
    return -1;
163
0
}
164
165
static struct syslog_wi *
166
syslog_queue_get_free_item(int wait)
167
0
{
168
0
    struct syslog_wi *wi;
169
170
0
    pthread_mutex_lock(&syslog_wi_free_mutex);
171
0
    while (syslog_wi_free == NULL) {
172
        /* no free work items, return if no wait is requested */
173
0
        if (wait == 0) {
174
0
            syslog_dropped_items++;
175
0
            pthread_mutex_unlock(&syslog_wi_free_mutex);
176
0
            return NULL;
177
0
        }
178
0
        pthread_cond_wait(&syslog_wi_free_cond, &syslog_wi_free_mutex);
179
0
    }
180
181
0
    wi = syslog_wi_free;
182
183
    /* move up syslog_wi_free */
184
0
    syslog_wi_free = syslog_wi_free->next;
185
0
    pthread_mutex_unlock(&syslog_wi_free_mutex);
186
187
0
    return wi;
188
0
}
189
190
static void
191
syslog_queue_put_item(struct syslog_wi *wi)
192
0
{
193
194
0
    pthread_mutex_lock(&syslog_queue_mutex);
195
196
0
    wi->next = NULL;
197
0
    if (syslog_wi_queue == NULL) {
198
0
        syslog_wi_queue = wi;
199
0
        syslog_wi_queue_tail = wi;
200
0
    } else {
201
0
        syslog_wi_queue_tail->next = wi;
202
0
        syslog_wi_queue_tail = wi;
203
0
    }
204
205
    /* notify worker thread */
206
0
    pthread_cond_signal(&syslog_queue_cond);
207
208
0
    pthread_mutex_unlock(&syslog_queue_mutex);
209
0
}
210
211
static void
212
syslog_async_atexit(void)
213
0
{
214
0
    struct syslog_wi *wi;
215
216
0
    if (syslog_queue_inited == 0)
217
0
        return;
218
219
    /* Wait for the worker thread to exit */
220
0
    wi = syslog_queue_get_free_item(SYSLOG_WI_WAIT);
221
0
    wi->item_type = SYSLOG_ITEM_ASYNC_EXIT;
222
0
    syslog_queue_put_item(wi);
223
0
    pthread_join(syslog_queue, NULL);
224
0
}
225
226
int
227
syslog_async_init(const char *app, int facility)
228
0
{
229
230
0
    pthread_mutex_lock(&syslog_init_mutex);
231
0
    if (syslog_queue_inited == 0) {
232
0
        if (syslog_queue_init() != 0) {
233
0
            pthread_mutex_unlock(&syslog_init_mutex);
234
0
            return -1;
235
0
        }
236
0
    }
237
0
    syslog_queue_inited = 1;
238
0
    pthread_mutex_unlock(&syslog_init_mutex);
239
240
0
    openlog(app, LOG_PID | LOG_CONS, facility);
241
0
    atexit(syslog_async_atexit);
242
243
0
    return 0;
244
0
}
245
246
void
247
vsyslog_async(int priority, const char *pre, const char *post,
248
  const char *user_fmt, va_list ap)
249
0
{
250
0
    struct syslog_wi *wi;
251
0
    char *p;
252
0
    int s1, s2, s3, l, m;
253
254
0
    wi = syslog_queue_get_free_item(SYSLOG_WI_NOWAIT);
255
0
    if (wi == NULL)
256
0
        return;
257
258
0
    m = l = sizeof(wi->data);
259
0
    s1 = strlcpy(wi->data, pre, l);
260
0
    if (s1 >= l) {
261
0
        s1 = l - 1;
262
0
    }
263
0
    p = wi->data + s1;
264
0
    l -= s1;
265
0
    if (l <= 1)
266
0
        goto truncate;
267
0
    s2 = vsnprintf(p, l, user_fmt, ap);
268
0
    if (s2 >= l) {
269
        /* message was truncated */
270
0
        s2 = l - 1;
271
0
        p[s2] = '\0';
272
0
    }
273
0
    p += s2;
274
0
    l -= s2;
275
0
    if (l <= 1 || post == NULL)
276
0
        goto truncate;
277
0
    s3 = strlcpy(p, post, l);
278
0
    if (s3 >= l) {
279
        /* message was truncated */
280
0
        s3 = l - 1;
281
0
    }
282
0
    l -= s3;
283
0
truncate:
284
0
    RTPP_DBG_ASSERT(l >= 0 && l <= m);
285
0
    wi->len = m - l;
286
0
    RTPP_DBG_ASSERT(wi->data[wi->len] == '\0' && strlen(wi->data) == wi->len);
287
0
    wi->priority = priority;
288
0
    wi->item_type = SYSLOG_ITEM_ASYNC_WRITE;
289
0
    syslog_queue_put_item(wi);
290
0
}