Coverage Report

Created: 2026-02-03 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/src/rtpp_cfile.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018 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 <limits.h>
29
#include <fcntl.h>
30
#include <stdbool.h>
31
#include <stdint.h>
32
#include <unistd.h>
33
34
#include "config_pp.h"
35
36
#include "rtpp_cfg.h"
37
#include "rtpp_types.h"
38
#include "rtpp_cfile.h"
39
#include "rtpp_list.h"
40
#include "rtpp_log.h"
41
#include "rtpp_log_obj.h"
42
#include "rtpp_module_if.h"
43
#include "rtpp_modman.h"
44
#include "rtpp_codeptr.h"
45
#include "rtpp_refcnt.h"
46
#include "ucl.h"
47
#include "rtpp_ucl.h"
48
49
static int parse_modules(const struct rtpp_cfg *, const ucl_object_t *);
50
static bool conf_helper_mapper(struct rtpp_log *, const ucl_object_t *,
51
  const conf_helper_map *, void *, const conf_helper_map **);
52
53
static char *
54
rtpp_module_dsop_canonic(const char *mname, char *buf, size_t blen)
55
0
{
56
0
     const char *dbug;
57
58
#if defined(RTPP_DEBUG)
59
     dbug = "_debug";
60
#else
61
0
     dbug = "";
62
0
#endif
63
64
0
     snprintf(buf, blen, "%s/rtpp_%s%s.so", MDDIR_PATH, mname, dbug);
65
0
     return (buf);
66
0
}
67
68
int
69
rtpp_cfile_process(const struct rtpp_cfg *csp)
70
0
{
71
0
    struct ucl_parser *parser;
72
0
    ucl_object_t *conf_root;
73
0
    ucl_object_iter_t it_conf;
74
0
    const ucl_object_t *obj_file;
75
0
    const char *cf_key;
76
0
    int fd, ecode;
77
78
0
    ecode = 0;
79
80
0
    fd = open(csp->cfile, O_RDONLY);
81
0
    if (fd < 0) {
82
0
        RTPP_ELOG(csp->glog, RTPP_LOG_ERR, "open failed: %s", csp->cfile);
83
0
        ecode = -1;
84
0
        goto e0;
85
0
    }
86
87
0
    parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
88
0
    if (parser == NULL) {
89
0
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "ucl_parser_new() failed");
90
0
        ecode = -1;
91
0
        goto e1;
92
0
    }
93
94
0
    ucl_parser_add_fd(parser, fd);
95
0
    conf_root = ucl_parser_get_object(parser);
96
0
    if (conf_root == NULL) {
97
0
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "ucl_parser_get_object() failed");
98
0
        ecode = -1;
99
0
        goto e2;
100
0
    }
101
0
    if (ucl_parser_get_error(parser)) {
102
0
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Parse Error occured: %s", ucl_parser_get_error(parser));
103
0
        ecode = -1;
104
0
        goto e3;
105
0
    }
106
107
0
    it_conf = ucl_object_iterate_new(conf_root);
108
0
    if (it_conf == NULL) {
109
0
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "ucl_object_iterate_new() failed");
110
0
        ecode = -1;
111
0
        goto e3;
112
0
    }
113
0
    while ((obj_file = ucl_object_iterate_safe(it_conf, true)) != NULL) {
114
0
        cf_key = ucl_object_key(obj_file);
115
0
        RTPP_LOG(csp->glog, RTPP_LOG_DBUG, "Entry: %s", cf_key);
116
0
        if (strcasecmp(cf_key, "modules") == 0) {
117
0
#if ENABLE_MODULE_IF
118
0
            if (parse_modules(csp, obj_file) < 0) {
119
0
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "parse_modules() failed");
120
0
                ecode = -1;
121
0
                goto e4;
122
0
            }
123
#else
124
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Modules are disabled, but the configuration file contains a \"modules\" section");
125
            ecode = -1;
126
            goto e4;
127
#endif
128
0
        }
129
0
    }
130
0
    if (ucl_object_iter_chk_excpn(it_conf)) {
131
0
        ecode = -1;
132
0
    }
133
0
e4:
134
0
    ucl_object_iterate_free(it_conf);
135
0
e3:
136
0
    ucl_object_unref(conf_root);
137
0
e2:
138
0
    ucl_parser_free(parser);
139
0
e1:
140
0
    close(fd);
141
0
e0:
142
0
    return (ecode);
143
0
}
144
145
static const conf_helper_map default_module_map[] = {
146
    { "load", NULL }, /* The "load" is default */
147
    { NULL, (conf_helper_t) rtpp_ucl_set_unknown }
148
};
149
150
#if ENABLE_MODULE_IF
151
static int
152
parse_modules(const struct rtpp_cfg *csp, const ucl_object_t *wop)
153
0
{
154
0
    ucl_object_iter_t it_conf;
155
0
    const ucl_object_t *obj_file;
156
0
    const char *cf_key;
157
0
    const ucl_object_t *obj_key;
158
0
    int ecode, success;
159
0
    void *confp;
160
0
    const conf_helper_map *fent, *map;
161
0
    struct rtpp_module_conf *mcp;
162
0
    char mpath[PATH_MAX + 1];
163
0
    const char *cp, *mp;
164
0
    struct rtpp_module_if *mif;
165
166
0
    it_conf = ucl_object_iterate_new(wop);
167
0
    if (it_conf == NULL)
168
0
        return (-1);
169
0
    ecode = 0;
170
0
    while ((obj_file = ucl_object_iterate_safe(it_conf, true)) != NULL) {
171
0
        cf_key = ucl_object_key(obj_file);
172
0
        RTPP_LOG(csp->glog, RTPP_LOG_DBUG, "\tmodule: %s", cf_key);
173
0
        obj_key = ucl_object_find_key(obj_file, "load");
174
0
        if (obj_key == NULL) {
175
0
            cp = rtpp_module_dsop_canonic(cf_key, mpath, sizeof(mpath));
176
0
            if (cp == NULL) {
177
0
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Error: Unable to find load parameter in module: %s", cf_key);
178
0
                ecode = -1;
179
0
                goto e0;
180
0
            }
181
0
        } else {
182
0
            if (obj_key->type != UCL_STRING) {
183
0
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Error: \"load\" parameter in %s has a wrong type, string is expected", cf_key);
184
0
                ecode = -1;
185
0
                goto e0;
186
0
            }
187
0
            mp = ucl_object_tostring(obj_key);
188
0
            cp = realpath(mp, mpath);
189
0
            if (cp == NULL) {
190
0
                RTPP_ELOG(csp->glog, RTPP_LOG_ERR, "realpath() failed: %s", mp);
191
0
                ecode = -1;
192
0
                goto e0;
193
0
            }
194
0
        }
195
0
        mif = rtpp_module_if_ctor(cp);
196
0
        if (mif == NULL) {
197
0
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "dymanic module constructor has failed: %s", cp);
198
0
            ecode = -1;
199
0
            goto e0;
200
0
        }
201
0
        if (CALL_METHOD(mif, load, csp, csp->glog) != 0) {
202
0
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "%p->load() method has failed: %s", mif, cp);
203
0
            goto e1;
204
0
        }
205
0
        if (CALL_METHOD(mif, get_mconf, &mcp) < 0) {
206
0
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "%p->get_mconf() method has failed: %s", mif, cp);
207
0
            goto e1;
208
0
        }
209
0
        fent = NULL;
210
0
        if (mcp != NULL) {
211
0
            map = mcp->conf_map;
212
0
            confp = mcp->conf_data;
213
0
            RTPP_OBJ_DECREF(mcp);
214
0
        } else {
215
0
            map = default_module_map;
216
0
            confp = NULL;
217
0
        }
218
0
        success = conf_helper_mapper(csp->glog, obj_file, map, confp, &fent);
219
0
        if (!success) {
220
0
            RTPP_LOG(csp->glog, RTPP_LOG_ERR, "Config parsing issue in section %s",
221
0
              cf_key);
222
0
            if (fent != NULL && fent->conf_key != NULL) {
223
0
                RTPP_LOG(csp->glog, RTPP_LOG_ERR, "\tparameter %s", fent->conf_key);
224
0
            }
225
0
            goto e1;
226
0
        }
227
0
        CALL_METHOD(csp->modules_cf, insert, mif);
228
0
        continue;
229
0
e1:
230
0
        ecode = -1;
231
0
        RTPP_OBJ_DECREF(mif);
232
0
        CALL_METHOD(mif, kaput);
233
0
        goto e0;
234
0
    }
235
0
e0:
236
0
    if (ucl_object_iter_chk_excpn(it_conf)) {
237
0
        RTPP_LOG(csp->glog, RTPP_LOG_ERR, "UCL has failed with an internal error");
238
0
        ecode = -1;
239
0
    }
240
0
    ucl_object_iterate_free(it_conf);
241
0
    return (ecode);
242
0
}
243
#endif
244
245
static bool
246
conf_helper_mapper(struct rtpp_log *log, const ucl_object_t *obj, const conf_helper_map *map,
247
  void *target, const conf_helper_map **fentrpp)
248
0
{
249
0
    ucl_object_iter_t it;
250
0
    const ucl_object_t *cur;
251
0
    const char *key = NULL;
252
0
    int i;
253
0
    bool ret = true, found = false;
254
255
0
    it = ucl_object_iterate_new(obj);
256
0
    if (it == NULL)
257
0
        return (false);
258
0
    while ((cur = ucl_object_iterate_safe(it, true)) != NULL && ret) {
259
0
        key = ucl_object_key(cur);
260
0
        found = false;
261
0
        for (i = 0; map[i].conf_key; i++) {
262
0
            if (strcasecmp(map[i].conf_key, key) != 0)
263
0
                continue;
264
0
            found = true;
265
0
            if (map[i].callback != NULL) {
266
0
                ret = map[i].callback(log, obj, cur, target);
267
0
                if (!ret && fentrpp != NULL)
268
0
                    *fentrpp = &map[i];
269
0
            }
270
0
            break;
271
0
        }
272
0
        if (!found && map[i].callback != NULL) {
273
            /* Call default handler if there is one */
274
0
            ret = map[i].callback(log, obj, cur, target);
275
0
            if (!ret && fentrpp != NULL)
276
0
                *fentrpp = &map[i];
277
0
        }
278
0
    }
279
0
    if (cur == NULL && ucl_object_iter_chk_excpn(it))
280
0
        ret = false;
281
0
    ucl_object_iterate_free(it);
282
0
    return (ret);
283
0
}