Coverage Report

Created: 2026-09-01 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/src/rtpp_notify.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2010-2014 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
#if defined(HAVE_CONFIG_H)
33
#include "config_pp.h"
34
#endif
35
36
#include <sys/types.h>
37
#include <sys/socket.h>
38
#include <netinet/in.h>
39
#include <assert.h>
40
#include <errno.h>
41
#include <pthread.h>
42
#include <signal.h>
43
#include <stddef.h>
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <unistd.h>
48
49
#include "rtpp_log.h"
50
#include "rtpp_types.h"
51
#include "rtpp_codeptr.h"
52
#include "rtpp_refcnt.h"
53
#include "rtpp_log_obj.h"
54
#include "rtpp_network.h"
55
#include "rtpp_notify.h"
56
#include "rtpp_queue.h"
57
#include "rtpp_tnotify_tgt.h"
58
#include "rtpp_mallocs.h"
59
#include "rtpp_wi.h"
60
#include "rtpp_wi_data.h"
61
#include "rtpp_wi_sgnl.h"
62
63
struct rtpp_notify_wi
64
{
65
    int len;
66
    struct rtpp_tnotify_target *rttp;
67
    struct rtpp_log *glog;
68
    const char *ntype;
69
    char notify_buf[0];
70
};
71
72
struct rtpp_notify_priv {
73
    struct rtpp_notify pub;
74
    struct rtpp_queue *nqueue;
75
    struct rtpp_wi *sigterm;
76
    pthread_t thread_id;
77
    struct rtpp_log *glog;
78
};
79
80
static int rtpp_notify_schedule(struct rtpp_notify *,
81
  struct rtpp_tnotify_target *, const rtpp_str_t *, const char *);
82
static void rtpp_notify_dtor(struct rtpp_notify_priv *);
83
static void do_notification(struct rtpp_notify_wi *, int);
84
85
static void
86
rtpp_notify_queue_run(void *arg)
87
4
{
88
4
    struct rtpp_wi *wi;
89
4
    struct rtpp_notify_wi *wi_data;
90
4
    struct rtpp_notify_priv *pvt;
91
92
4
    pvt = (struct rtpp_notify_priv *)arg;
93
4
    for (;;) {
94
4
        wi = rtpp_queue_get_item(pvt->nqueue, 0);
95
4
        if (rtpp_wi_get_type(wi) == RTPP_WI_TYPE_SGNL) {
96
4
            RTPP_OBJ_DECREF(wi);
97
4
            break;
98
4
        }
99
0
        wi_data = rtpp_wi_data_get_ptr(wi, sizeof(struct rtpp_notify_wi), 0);
100
101
        /* main work here */
102
0
        do_notification(wi_data, 3);
103
104
        /* deallocate wi */
105
0
        RTPP_OBJ_DECREF(wi_data->glog);
106
0
        RTPP_OBJ_DECREF(wi);
107
0
    }
108
4
}
109
110
struct rtpp_notify *
111
rtpp_notify_ctor(struct rtpp_log *glog)
112
4
{
113
4
    struct rtpp_notify_priv *pvt;
114
115
4
    pvt = rtpp_rzmalloc(sizeof(struct rtpp_notify_priv), PVT_RCOFFS(pvt));
116
4
    if (pvt == NULL) {
117
0
        goto e0;
118
0
    }
119
4
    pvt->nqueue = rtpp_queue_init(RTPQ_SMALL_CB_LEN, "rtpp_notify");
120
4
    if (pvt->nqueue == NULL) {
121
0
        goto e1;
122
0
    }
123
124
    /* Pre-allocate sigterm, so that we don't have any malloc() in dtor() */
125
4
    pvt->sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0);
126
4
    if (pvt->sigterm == NULL) {
127
0
        goto e2;
128
0
    }
129
130
4
    if (pthread_create(&pvt->thread_id, NULL, (void *(*)(void *))&rtpp_notify_queue_run, pvt) != 0) {
131
0
        goto e3;
132
0
    }
133
4
#if HAVE_PTHREAD_SETNAME_NP
134
4
    (void)pthread_setname_np(pvt->thread_id, "rtpp_notify_queue");
135
4
#endif
136
137
4
    RTPP_OBJ_INCREF(glog);
138
4
    pvt->glog = glog;
139
4
    pvt->pub.schedule = &rtpp_notify_schedule;
140
141
4
    RTPP_OBJ_DTOR_ATTACH_s(&pvt->pub, (rtpp_refcnt_dtor_t)&rtpp_notify_dtor,
142
4
      pvt);
143
4
    return (&pvt->pub);
144
145
0
e3:
146
0
    RTPP_OBJ_DECREF(pvt->sigterm);
147
0
e2:
148
0
    rtpp_queue_destroy(pvt->nqueue);
149
0
e1:
150
0
    RTPP_OBJ_DECREF(&(pvt->pub));
151
0
e0:
152
0
    return (NULL);
153
0
}
154
155
static void
156
rtpp_notify_dtor(struct rtpp_notify_priv *pvt)
157
4
{
158
159
4
    rtpp_queue_put_item(pvt->sigterm, pvt->nqueue);
160
4
    pthread_join(pvt->thread_id, NULL);
161
4
    rtpp_queue_destroy(pvt->nqueue);
162
4
    RTPP_OBJ_DECREF(pvt->glog);
163
4
}
164
165
static int
166
rtpp_notify_schedule(struct rtpp_notify *pub,
167
  struct rtpp_tnotify_target *rttp, const rtpp_str_t *notify_tag,
168
  const char *notify_type)
169
0
{
170
0
    struct rtpp_notify_wi *wi_data;
171
0
    struct rtpp_wi *wi;
172
0
    int len;
173
0
    struct rtpp_notify_priv *pvt;
174
175
0
    PUB2PVT(pub, pvt);
176
177
    /* string, \0 and \n */
178
0
    len = notify_tag->len + 2;
179
180
0
    wi = rtpp_wi_malloc_udata((void **)&wi_data,
181
0
      sizeof(struct rtpp_notify_wi) + len);
182
0
    if (wi == NULL) {
183
0
        return (-1);
184
0
    }
185
0
    memset(wi_data, '\0', sizeof(struct rtpp_notify_wi));
186
187
0
    wi_data->rttp = rttp;
188
0
    wi_data->len = len;
189
0
    RTPP_OBJ_INCREF(pvt->glog);
190
0
    wi_data->glog = pvt->glog;
191
0
    wi_data->ntype = notify_type;
192
193
0
    memcpy(wi_data->notify_buf, notify_tag->s, notify_tag->len);
194
0
    wi_data->notify_buf[notify_tag->len] = '\n';
195
196
0
    rtpp_queue_put_item(wi, pvt->nqueue);
197
0
    return (0);
198
0
}
199
200
static void
201
reconnect_handler(const struct rtpp_notify_wi *wi)
202
0
{
203
204
0
    assert (wi->rttp->connected == 0);
205
0
    assert (wi->rttp->socket_type != RTPP_TNS_FD);
206
207
0
    if (wi->rttp->fd == -1) {
208
0
        RTPP_LOG(wi->glog, RTPP_LOG_DBUG, "connecting %s socket", wi->ntype);
209
0
    } else {
210
0
        RTPP_LOG(wi->glog, RTPP_LOG_DBUG, "reconnecting %s socket", wi->ntype);
211
0
        close(wi->rttp->fd);
212
0
    }
213
0
    wi->rttp->fd = socket(RTPP_TNT_STYPE(wi->rttp), SOCK_STREAM, 0);
214
0
    if (wi->rttp->fd == -1) {
215
0
        RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "can't create %s socket", wi->ntype);
216
0
        return;
217
0
    }
218
0
    if (wi->rttp->local != NULL) {
219
0
        if (bind(wi->rttp->fd, wi->rttp->local, SA_LEN(wi->rttp->local)) < 0) {
220
0
            RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "can't bind %s socket", wi->ntype);
221
0
            goto e0;
222
0
        }
223
0
    }
224
0
    if (connect(wi->rttp->fd, (struct sockaddr *)&(wi->rttp->remote), wi->rttp->remote_len) == -1) {
225
0
        RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "can't connect to %s socket", wi->ntype);
226
0
        goto e0;
227
0
    } else {
228
0
        wi->rttp->connected = 1;
229
0
    }
230
0
    return;
231
232
0
e0:
233
0
    close(wi->rttp->fd);
234
0
    wi->rttp->fd = -1;
235
0
    return;
236
0
}
237
238
static void
239
do_notification(struct rtpp_notify_wi *wi, int retries)
240
0
{
241
0
    int result;
242
243
0
    if (wi->rttp->connected == 0) {
244
0
        reconnect_handler(wi);
245
246
        /* If connect fails, no notification will be sent */
247
0
        if (wi->rttp->connected == 0) {
248
0
            RTPP_LOG(wi->glog, RTPP_LOG_ERR, "unable to send %s notification",
249
0
              wi->ntype);
250
0
            return;
251
0
        }
252
0
    }
253
254
0
    do {
255
0
        result = send(wi->rttp->fd, wi->notify_buf, wi->len - 1, 0);
256
0
    } while (result == -1 && errno == EINTR);
257
258
0
    if (result < 0) {
259
0
        wi->rttp->connected = 0;
260
0
        RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "failed to send %s notification",
261
0
          wi->ntype);
262
0
        if (retries > 0)
263
0
            do_notification(wi, retries - 1);
264
0
    }
265
0
}