Coverage Report

Created: 2025-07-11 06:15

/src/pjsip/pjlib/src/pj/errno.c
Line
Count
Source (jump to first uncovered line)
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
};
83
#endif  /* PJ_HAS_ERROR_STRING */
84
85
86
/*
87
 * pjlib_error()
88
 *
89
 * Retrieve message string for PJLIB's own error code.
90
 */
91
static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
92
0
{
93
0
    int len;
94
95
0
#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
96
0
    unsigned i;
97
98
0
    for (i=0; i<PJ_ARRAY_SIZE(err_str); ++i) {
99
0
        if (err_str[i].code == code) {
100
0
            pj_size_t len2 = pj_ansi_strlen(err_str[i].msg);
101
0
            if (len2 >= size) len2 = size-1;
102
0
            pj_memcpy(buf, err_str[i].msg, len2);
103
0
            buf[len2] = '\0';
104
0
            return (int)len2;
105
0
        }
106
0
    }
107
0
#endif
108
109
0
    len = pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
110
0
    if (len < 1 || len >= (int)size)
111
0
        len = (int)(size - 1);
112
0
    return len;
113
0
}
114
115
0
#define IN_RANGE(val,start,end)     ((val)>=(start) && (val)<(end))
116
117
/* Register strerror handle. */
118
PJ_DEF(pj_status_t) pj_register_strerror( pj_status_t start,
119
                                          pj_status_t space,
120
                                          pj_error_callback f)
121
0
{
122
0
    unsigned i;
123
124
    /* Check arguments. */
125
0
    PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
126
127
    /* Check if there aren't too many handlers registered. */
128
0
    PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
129
0
                     PJ_ETOOMANY);
130
131
    /* Start error must be greater than PJ_ERRNO_START_USER */
132
0
    PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
133
134
    /* Check that no existing handler has covered the specified range. */
135
0
    for (i=0; i<err_msg_hnd_cnt; ++i) {
136
0
        if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
137
0
            IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
138
0
        {
139
0
            if (err_msg_hnd[i].begin == start && 
140
0
                err_msg_hnd[i].end == (start+space) &&
141
0
                err_msg_hnd[i].strerror == f)
142
0
            {
143
                /* The same range and handler has already been registered */
144
0
                return PJ_SUCCESS;
145
0
            }
146
147
0
            return PJ_EEXISTS;
148
0
        }
149
0
    }
150
151
    /* Register the handler. */
152
0
    err_msg_hnd[err_msg_hnd_cnt].begin = start;
153
0
    err_msg_hnd[err_msg_hnd_cnt].end = start + space;
154
0
    err_msg_hnd[err_msg_hnd_cnt].strerror = f;
155
156
0
    ++err_msg_hnd_cnt;
157
158
0
    return PJ_SUCCESS;
159
0
}
160
161
/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
162
void pj_errno_clear_handlers(void)
163
0
{
164
0
    err_msg_hnd_cnt = 0;
165
0
    pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
166
0
}
167
168
169
/*
170
 * pj_strerror()
171
 */
172
PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, 
173
                              char *buf, pj_size_t bufsize )
174
0
{
175
0
    int len = -1;
176
0
    pj_str_t errstr;
177
178
0
    pj_assert(buf && bufsize);
179
180
0
    if (statcode == PJ_SUCCESS) {
181
0
        len = pj_ansi_snprintf( buf, bufsize, "Success");
182
183
0
    } else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
184
0
        len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
185
186
0
    } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
187
0
        len = pjlib_error(statcode, buf, bufsize);
188
189
0
    } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
190
0
        len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
191
192
0
    } else {
193
0
        unsigned i;
194
195
        /* Find user handler to get the error message. */
196
0
        for (i=0; i<err_msg_hnd_cnt; ++i) {
197
0
            if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
198
0
                return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
199
0
            }
200
0
        }
201
202
        /* Handler not found! */
203
0
        len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
204
0
    }
205
206
0
    if (len < 1 || len >= (int)bufsize) {
207
0
        len = (int)(bufsize - 1);
208
0
        buf[len] = '\0';
209
0
    }
210
211
0
    errstr.ptr = buf;
212
0
    errstr.slen = len;
213
214
0
    return errstr;
215
0
}
216
217
#if PJ_LOG_MAX_LEVEL >= 1
218
static void invoke_log(const char *sender, int level, const char *format, ...)
219
0
{
220
0
    va_list arg;
221
0
    va_start(arg, format);
222
0
    pj_log(sender, level, format, arg);
223
0
    va_end(arg);
224
0
}
225
226
static void pj_perror_imp(int log_level, const char *sender, 
227
                          pj_status_t status,
228
                          const char *title_fmt, va_list marker)
229
0
{
230
0
    char titlebuf[PJ_PERROR_TITLE_BUF_SIZE];
231
0
    char errmsg[PJ_ERR_MSG_SIZE];
232
0
    int len;
233
234
    /* Build the title */
235
0
    len = pj_ansi_vsnprintf(titlebuf, sizeof(titlebuf), title_fmt, marker);
236
0
    if (len < 0 || len >= (int)sizeof(titlebuf))
237
0
        pj_ansi_strxcpy(titlebuf, "Error", sizeof(titlebuf));
238
239
    /* Get the error */
240
0
    pj_strerror(status, errmsg, sizeof(errmsg));
241
242
    /* Send to log */
243
0
    invoke_log(sender, log_level, "%s: %s", titlebuf, errmsg);
244
0
}
245
246
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
247
                       const char *title_fmt, ...)
248
0
{
249
0
    va_list marker;
250
0
    va_start(marker, title_fmt);
251
0
    pj_perror_imp(log_level, sender, status, title_fmt, marker);
252
0
    va_end(marker);
253
0
}
254
255
PJ_DEF(void) pj_perror_1(const char *sender, pj_status_t status,
256
                         const char *title_fmt, ...)
257
0
{
258
0
    va_list marker;
259
0
    va_start(marker, title_fmt);
260
0
    pj_perror_imp(1, sender, status, title_fmt, marker);
261
0
    va_end(marker);
262
0
}
263
264
#else /* #if PJ_LOG_MAX_LEVEL >= 1 */
265
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
266
                       const char *title_fmt, ...)
267
{
268
}
269
#endif  /* #if PJ_LOG_MAX_LEVEL >= 1 */
270
271
272
#if PJ_LOG_MAX_LEVEL >= 2
273
PJ_DEF(void) pj_perror_2(const char *sender, pj_status_t status,
274
                         const char *title_fmt, ...)
275
0
{
276
0
    va_list marker;
277
0
    va_start(marker, title_fmt);
278
0
    pj_perror_imp(2, sender, status, title_fmt, marker);
279
0
    va_end(marker);
280
0
}
281
#endif
282
283
#if PJ_LOG_MAX_LEVEL >= 3
284
PJ_DEF(void) pj_perror_3(const char *sender, pj_status_t status,
285
                         const char *title_fmt, ...)
286
0
{
287
0
    va_list marker;
288
0
    va_start(marker, title_fmt);
289
0
    pj_perror_imp(3, sender, status, title_fmt, marker);
290
0
    va_end(marker);
291
0
}
292
#endif
293
294
#if PJ_LOG_MAX_LEVEL >= 4
295
PJ_DEF(void) pj_perror_4(const char *sender, pj_status_t status,
296
                         const char *title_fmt, ...)
297
0
{
298
0
    va_list marker;
299
0
    va_start(marker, title_fmt);
300
0
    pj_perror_imp(4, sender, status, title_fmt, marker);
301
0
    va_end(marker);
302
0
}
303
#endif
304
305
#if PJ_LOG_MAX_LEVEL >= 5
306
PJ_DEF(void) pj_perror_5(const char *sender, pj_status_t status,
307
                         const char *title_fmt, ...)
308
0
{
309
0
    va_list marker;
310
0
    va_start(marker, title_fmt);
311
0
    pj_perror_imp(5, sender, status, title_fmt, marker);
312
0
    va_end(marker);
313
0
}
314
#endif
315
316
#if PJ_LOG_MAX_LEVEL >= 6
317
PJ_DEF(void) pj_perror_6(const char *sender, pj_status_t status,
318
                         const char *title_fmt, ...)
319
{
320
    va_list marker;
321
    va_start(marker, title_fmt);
322
    pj_perror_imp(6, sender, status, title_fmt, marker);
323
    va_end(marker);
324
}
325
#endif
326