1
/* $Id: errno.c 3664 2011-07-19 03:42:28Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include <pj/string.h>
23
#include <pj/compat/string.h>
24
#include <pj/compat/stdarg.h>
25
#include <pj/assert.h>
27
/* Prototype for platform specific error message, which will be defined
32
PJ_DECL(int) platform_strerror(pj_os_err_type code,
33
char *buf, pj_size_t bufsize );
36
#ifndef PJLIB_MAX_ERR_MSG_HANDLER
37
# define PJLIB_MAX_ERR_MSG_HANDLER 10
40
/* Error message handler. */
41
static unsigned err_msg_hnd_cnt;
42
static struct err_msg_hnd
46
pj_str_t (*strerror)(pj_status_t, char*, pj_size_t);
48
} err_msg_hnd[PJLIB_MAX_ERR_MSG_HANDLER];
50
/* PJLIB's own error codes/messages */
51
#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
59
PJ_BUILD_ERR(PJ_EUNKNOWN, "Unknown Error" ),
60
PJ_BUILD_ERR(PJ_EPENDING, "Pending operation" ),
61
PJ_BUILD_ERR(PJ_ETOOMANYCONN, "Too many connecting sockets" ),
62
PJ_BUILD_ERR(PJ_EINVAL, "Invalid value or argument" ),
63
PJ_BUILD_ERR(PJ_ENAMETOOLONG, "Name too long" ),
64
PJ_BUILD_ERR(PJ_ENOTFOUND, "Not found" ),
65
PJ_BUILD_ERR(PJ_ENOMEM, "Not enough memory" ),
66
PJ_BUILD_ERR(PJ_EBUG, "BUG DETECTED!" ),
67
PJ_BUILD_ERR(PJ_ETIMEDOUT, "Operation timed out" ),
68
PJ_BUILD_ERR(PJ_ETOOMANY, "Too many objects of the specified type"),
69
PJ_BUILD_ERR(PJ_EBUSY, "Object is busy"),
70
PJ_BUILD_ERR(PJ_ENOTSUP, "Option/operation is not supported"),
71
PJ_BUILD_ERR(PJ_EINVALIDOP, "Invalid operation"),
72
PJ_BUILD_ERR(PJ_ECANCELLED, "Operation cancelled"),
73
PJ_BUILD_ERR(PJ_EEXISTS, "Object already exists" ),
74
PJ_BUILD_ERR(PJ_EEOF, "End of file" ),
75
PJ_BUILD_ERR(PJ_ETOOBIG, "Size is too big"),
76
PJ_BUILD_ERR(PJ_ERESOLVE, "gethostbyname() has returned error"),
77
PJ_BUILD_ERR(PJ_ETOOSMALL, "Size is too short"),
78
PJ_BUILD_ERR(PJ_EIGNORED, "Ignored"),
79
PJ_BUILD_ERR(PJ_EIPV6NOTSUP, "IPv6 is not supported"),
80
PJ_BUILD_ERR(PJ_EAFNOTSUP, "Unsupported address family")
82
#endif /* PJ_HAS_ERROR_STRING */
88
* Retrieve message string for PJLIB's own error code.
90
static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
92
#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
95
for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
96
if (err_str[i].code == code) {
97
pj_size_t len = strlen(err_str[i].msg);
98
if (len >= size) len = size-1;
99
pj_memcpy(buf, err_str[i].msg, len);
106
return pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
109
#define IN_RANGE(val,start,end) ((val)>=(start) && (val)<(end))
111
/* Register strerror handle. */
112
PJ_DEF(pj_status_t) pj_register_strerror( pj_status_t start,
118
/* Check arguments. */
119
PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
121
/* Check if there aren't too many handlers registered. */
122
PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
125
/* Start error must be greater than PJ_ERRNO_START_USER */
126
PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
128
/* Check that no existing handler has covered the specified range. */
129
for (i=0; i<err_msg_hnd_cnt; ++i) {
130
if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
131
IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
133
if (err_msg_hnd[i].begin == start &&
134
err_msg_hnd[i].end == (start+space) &&
135
err_msg_hnd[i].strerror == f)
137
/* The same range and handler has already been registered */
145
/* Register the handler. */
146
err_msg_hnd[err_msg_hnd_cnt].begin = start;
147
err_msg_hnd[err_msg_hnd_cnt].end = start + space;
148
err_msg_hnd[err_msg_hnd_cnt].strerror = f;
155
/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
156
void pj_errno_clear_handlers(void)
159
pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
166
PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
167
char *buf, pj_size_t bufsize )
172
pj_assert(buf && bufsize);
174
if (statcode == PJ_SUCCESS) {
175
len = pj_ansi_snprintf( buf, bufsize, "Success");
177
} else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
178
len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
180
} else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
181
len = pjlib_error(statcode, buf, bufsize);
183
} else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
184
len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
189
/* Find user handler to get the error message. */
190
for (i=0; i<err_msg_hnd_cnt; ++i) {
191
if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
192
return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
196
/* Handler not found! */
197
len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
211
#if PJ_LOG_MAX_LEVEL >= 1
212
static void invoke_log(const char *sender, int level, const char *format, ...)
215
va_start(arg, format);
216
pj_log(sender, level, format, arg);
220
static void pj_perror_imp(int log_level, const char *sender,
222
const char *title_fmt, va_list marker)
224
char titlebuf[PJ_PERROR_TITLE_BUF_SIZE];
225
char errmsg[PJ_ERR_MSG_SIZE];
228
/* Build the title */
229
len = pj_ansi_vsnprintf(titlebuf, sizeof(titlebuf), title_fmt, marker);
230
if (len < 0 || len >= (int)sizeof(titlebuf))
231
pj_ansi_strcpy(titlebuf, "Error");
234
pj_strerror(status, errmsg, sizeof(errmsg));
237
invoke_log(sender, log_level, "%s: %s", titlebuf, errmsg);
240
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
241
const char *title_fmt, ...)
244
va_start(marker, title_fmt);
245
pj_perror_imp(log_level, sender, status, title_fmt, marker);
249
PJ_DEF(void) pj_perror_1(const char *sender, pj_status_t status,
250
const char *title_fmt, ...)
253
va_start(marker, title_fmt);
254
pj_perror_imp(1, sender, status, title_fmt, marker);
258
#else /* #if PJ_LOG_MAX_LEVEL >= 1 */
259
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
260
const char *title_fmt, ...)
263
#endif /* #if PJ_LOG_MAX_LEVEL >= 1 */
266
#if PJ_LOG_MAX_LEVEL >= 2
267
PJ_DEF(void) pj_perror_2(const char *sender, pj_status_t status,
268
const char *title_fmt, ...)
271
va_start(marker, title_fmt);
272
pj_perror_imp(2, sender, status, title_fmt, marker);
277
#if PJ_LOG_MAX_LEVEL >= 3
278
PJ_DEF(void) pj_perror_3(const char *sender, pj_status_t status,
279
const char *title_fmt, ...)
282
va_start(marker, title_fmt);
283
pj_perror_imp(3, sender, status, title_fmt, marker);
288
#if PJ_LOG_MAX_LEVEL >= 4
289
PJ_DEF(void) pj_perror_4(const char *sender, pj_status_t status,
290
const char *title_fmt, ...)
293
va_start(marker, title_fmt);
294
pj_perror_imp(4, sender, status, title_fmt, marker);
299
#if PJ_LOG_MAX_LEVEL >= 5
300
PJ_DEF(void) pj_perror_5(const char *sender, pj_status_t status,
301
const char *title_fmt, ...)
304
va_start(marker, title_fmt);
305
pj_perror_imp(5, sender, status, title_fmt, marker);
310
#if PJ_LOG_MAX_LEVEL >= 6
311
PJ_DEF(void) pj_perror_6(const char *sender, pj_status_t status,
312
const char *title_fmt, ...)
315
va_start(marker, title_fmt);
316
pj_perror_imp(6, sender, status, title_fmt, marker);