Coverage Report

Created: 2026-01-25 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pjsip/pjlib/src/pj/errno.c
Line
Count
Source
1
/* 
2
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
3
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
18
 */
19
#include <pj/errno.h>
20
#include <pj/log.h>
21
#include <pj/string.h>
22
#include <pj/compat/string.h>
23
#include <pj/compat/stdarg.h>
24
#include <pj/assert.h>
25
26
/* Prototype for platform specific error message, which will be defined 
27
 * in separate file.
28
 */
29
PJ_BEGIN_DECL
30
31
    PJ_DECL(int) platform_strerror(pj_os_err_type code, 
32
                                   char *buf, pj_size_t bufsize );
33
PJ_END_DECL
34
35
#ifndef PJLIB_MAX_ERR_MSG_HANDLER
36
#       define PJLIB_MAX_ERR_MSG_HANDLER   10
37
#endif
38
39
/* Error message handler. */
40
static unsigned err_msg_hnd_cnt;
41
static struct err_msg_hnd
42
{
43
    pj_status_t     begin;
44
    pj_status_t     end;
45
    pj_str_t      (*strerror)(pj_status_t, char*, pj_size_t);
46
47
} err_msg_hnd[PJLIB_MAX_ERR_MSG_HANDLER];
48
49
/* PJLIB's own error codes/messages */
50
#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
51
52
static const struct 
53
{
54
    int code;
55
    const char *msg;
56
} err_str[] = 
57
{
58
    PJ_BUILD_ERR(PJ_EUNKNOWN,      "Unknown Error" ),
59
    PJ_BUILD_ERR(PJ_EPENDING,      "Pending operation" ),
60
    PJ_BUILD_ERR(PJ_ETOOMANYCONN,  "Too many connecting sockets" ),
61
    PJ_BUILD_ERR(PJ_EINVAL,        "Invalid value or argument" ),
62
    PJ_BUILD_ERR(PJ_ENAMETOOLONG,  "Name too long" ),
63
    PJ_BUILD_ERR(PJ_ENOTFOUND,     "Not found" ),
64
    PJ_BUILD_ERR(PJ_ENOMEM,        "Not enough memory" ),
65
    PJ_BUILD_ERR(PJ_EBUG,          "BUG DETECTED!" ),
66
    PJ_BUILD_ERR(PJ_ETIMEDOUT,     "Operation timed out" ),
67
    PJ_BUILD_ERR(PJ_ETOOMANY,      "Too many objects of the specified type"),
68
    PJ_BUILD_ERR(PJ_EBUSY,         "Object is busy"),
69
    PJ_BUILD_ERR(PJ_ENOTSUP,       "Option/operation is not supported"),
70
    PJ_BUILD_ERR(PJ_EINVALIDOP,    "Invalid operation"),
71
    PJ_BUILD_ERR(PJ_ECANCELLED,    "Operation cancelled"),
72
    PJ_BUILD_ERR(PJ_EEXISTS,       "Object already exists" ),
73
    PJ_BUILD_ERR(PJ_EEOF,          "End of file" ),
74
    PJ_BUILD_ERR(PJ_ETOOBIG,       "Size is too big"),
75
    PJ_BUILD_ERR(PJ_ERESOLVE,      "gethostbyname() has returned error"),
76
    PJ_BUILD_ERR(PJ_ETOOSMALL,     "Size is too short"),
77
    PJ_BUILD_ERR(PJ_EIGNORED,      "Ignored"),
78
    PJ_BUILD_ERR(PJ_EIPV6NOTSUP,   "IPv6 is not supported"),
79
    PJ_BUILD_ERR(PJ_EAFNOTSUP,     "Unsupported address family"),
80
    PJ_BUILD_ERR(PJ_EGONE,         "Object no longer exists"),
81
    PJ_BUILD_ERR(PJ_ESOCKETSTOP,   "Socket is in bad state"),
82
    PJ_BUILD_ERR(PJ_ETRYAGAIN,     "Try again")
83
};
84
#endif  /* PJ_HAS_ERROR_STRING */
85
86
87
/*
88
 * pjlib_error()
89
 *
90
 * Retrieve message string for PJLIB's own error code.
91
 */
92
static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
93
0
{
94
0
    int len;
95
96
0
#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
97
0
    unsigned i;
98
99
0
    for (i=0; i<PJ_ARRAY_SIZE(err_str); ++i) {
100
0
        if (err_str[i].code == code) {
101
0
            pj_size_t len2 = pj_ansi_strlen(err_str[i].msg);
102
0
            if (len2 >= size) len2 = size-1;
103
0
            pj_memcpy(buf, err_str[i].msg, len2);
104
0
            buf[len2] = '\0';
105
0
            return (int)len2;
106
0
        }
107
0
    }
108
0
#endif
109
110
0
    len = pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
111
0
    if (len < 1 || len >= (int)size)
112
0
        len = (int)(size - 1);
113
0
    return len;
114
0
}
115
116
0
#define IN_RANGE(val,start,end)     ((val)>=(start) && (val)<(end))
117
118
/* Register strerror handle. */
119
PJ_DEF(pj_status_t) pj_register_strerror( pj_status_t start,
120
                                          pj_status_t space,
121
                                          pj_error_callback f)
122
0
{
123
0
    unsigned i;
124
125
    /* Check arguments. */
126
0
    PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
127
128
    /* Check if there aren't too many handlers registered. */
129
0
    PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
130
0
                     PJ_ETOOMANY);
131
132
    /* Start error must be greater than PJ_ERRNO_START_USER */
133
0
    PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
134
135
    /* Check that no existing handler has covered the specified range. */
136
0
    for (i=0; i<err_msg_hnd_cnt; ++i) {
137
0
        if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
138
0
            IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
139
0
        {
140
0
            if (err_msg_hnd[i].begin == start && 
141
0
                err_msg_hnd[i].end == (start+space) &&
142
0
                err_msg_hnd[i].strerror == f)
143
0
            {
144
                /* The same range and handler has already been registered */
145
0
                return PJ_SUCCESS;
146
0
            }
147
148
0
            return PJ_EEXISTS;
149
0
        }
150
0
    }
151
152
    /* Register the handler. */
153
0
    err_msg_hnd[err_msg_hnd_cnt].begin = start;
154
0
    err_msg_hnd[err_msg_hnd_cnt].end = start + space;
155
0
    err_msg_hnd[err_msg_hnd_cnt].strerror = f;
156
157
0
    ++err_msg_hnd_cnt;
158
159
0
    return PJ_SUCCESS;
160
0
}
161
162
/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
163
void pj_errno_clear_handlers(void)
164
0
{
165
0
    err_msg_hnd_cnt = 0;
166
0
    pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
167
0
}
168
169
170
/*
171
 * pj_strerror()
172
 */
173
PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, 
174
                              char *buf, pj_size_t bufsize )
175
0
{
176
0
    int len = -1;
177
0
    pj_str_t errstr;
178
179
0
    pj_assert(buf && bufsize);
180
181
0
    if (statcode == PJ_SUCCESS) {
182
0
        len = pj_ansi_snprintf( buf, bufsize, "Success");
183
184
0
    } else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
185
0
        len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
186
187
0
    } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
188
0
        len = pjlib_error(statcode, buf, bufsize);
189
190
0
    } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
191
0
        len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
192
193
0
    } else {
194
0
        unsigned i;
195
196
        /* Find user handler to get the error message. */
197
0
        for (i=0; i<err_msg_hnd_cnt; ++i) {
198
0
            if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
199
0
                return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
200
0
            }
201
0
        }
202
203
        /* Handler not found! */
204
0
        len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
205
0
    }
206
207
0
    if (len < 1 || len >= (int)bufsize) {
208
0
        len = (int)(bufsize - 1);
209
0
        buf[len] = '\0';
210
0
    }
211
212
0
    errstr.ptr = buf;
213
0
    errstr.slen = len;
214
215
0
    return errstr;
216
0
}
217
218
#if PJ_LOG_MAX_LEVEL >= 1
219
static void invoke_log(const char *sender, int level, 
220
                       PJ_PRINT_PARAM_DECOR const char *format, ...)
221
0
{
222
0
    va_list arg;
223
0
    va_start(arg, format);
224
0
    pj_log(sender, level, format, arg);
225
0
    va_end(arg);
226
0
}
227
228
static void pj_perror_imp(int log_level, const char *sender, 
229
                          pj_status_t status,
230
                          PJ_PRINT_PARAM_DECOR const char *title_fmt, 
231
                          va_list marker)
232
0
{
233
0
    char titlebuf[PJ_PERROR_TITLE_BUF_SIZE];
234
0
    char errmsg[PJ_ERR_MSG_SIZE];
235
0
    int len;
236
237
    /* Build the title */
238
0
    len = pj_ansi_vsnprintf(titlebuf, sizeof(titlebuf), title_fmt, marker);
239
0
    if (len < 0) {
240
      /* if you see this message in your log, please increase or set
241
         PJ_PERROR_TITLE_BUF_SIZE in your config_site.h */
242
0
        len = pj_ansi_snprintf(titlebuf, sizeof(titlebuf),
243
0
                               "<pj_perror_imp error: msg too long>");
244
0
    }
245
0
    if (len < 0 || len >= (int)sizeof(titlebuf))
246
0
        pj_ansi_strxcpy(titlebuf, "Error", sizeof(titlebuf));
247
248
    /* Get the error */
249
0
    pj_strerror(status, errmsg, sizeof(errmsg));
250
251
    /* Send to log */
252
0
    invoke_log(sender, log_level, "%s: %s", titlebuf, errmsg);
253
0
}
254
255
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
256
                       PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
257
0
{
258
0
    va_list marker;
259
0
    va_start(marker, title_fmt);
260
0
    pj_perror_imp(log_level, sender, status, title_fmt, marker);
261
0
    va_end(marker);
262
0
}
263
264
PJ_DEF(void) pj_perror_1(const char *sender, pj_status_t status,
265
                         PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
266
0
{
267
0
    va_list marker;
268
0
    va_start(marker, title_fmt);
269
0
    pj_perror_imp(1, sender, status, title_fmt, marker);
270
0
    va_end(marker);
271
0
}
272
273
#else /* #if PJ_LOG_MAX_LEVEL >= 1 */
274
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
275
                       PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
276
{
277
}
278
#endif  /* #if PJ_LOG_MAX_LEVEL >= 1 */
279
280
281
#if PJ_LOG_MAX_LEVEL >= 2
282
PJ_DEF(void) pj_perror_2(const char *sender, pj_status_t status,
283
                         PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
284
0
{
285
0
    va_list marker;
286
0
    va_start(marker, title_fmt);
287
0
    pj_perror_imp(2, sender, status, title_fmt, marker);
288
0
    va_end(marker);
289
0
}
290
#endif
291
292
#if PJ_LOG_MAX_LEVEL >= 3
293
PJ_DEF(void) pj_perror_3(const char *sender, pj_status_t status,
294
                         PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
295
0
{
296
0
    va_list marker;
297
0
    va_start(marker, title_fmt);
298
0
    pj_perror_imp(3, sender, status, title_fmt, marker);
299
0
    va_end(marker);
300
0
}
301
#endif
302
303
#if PJ_LOG_MAX_LEVEL >= 4
304
PJ_DEF(void) pj_perror_4(const char *sender, pj_status_t status,
305
                         PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
306
0
{
307
0
    va_list marker;
308
0
    va_start(marker, title_fmt);
309
0
    pj_perror_imp(4, sender, status, title_fmt, marker);
310
0
    va_end(marker);
311
0
}
312
#endif
313
314
#if PJ_LOG_MAX_LEVEL >= 5
315
PJ_DEF(void) pj_perror_5(const char *sender, pj_status_t status,
316
                         PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
317
0
{
318
0
    va_list marker;
319
0
    va_start(marker, title_fmt);
320
0
    pj_perror_imp(5, sender, status, title_fmt, marker);
321
    va_end(marker);
322
0
}
323
#endif
324
325
#if PJ_LOG_MAX_LEVEL >= 6
326
PJ_DEF(void) pj_perror_6(const char *sender, pj_status_t status,
327
                         PJ_PRINT_PARAM_DECOR const char *title_fmt, ...)
328
{
329
    va_list marker;
330
    va_start(marker, title_fmt);
331
    pj_perror_imp(6, sender, status, title_fmt, marker);
332
    va_end(marker);
333
}
334
#endif
335