1
/* $Id: errno.c 4761 2014-02-24 09:02:44Z 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"),
81
PJ_BUILD_ERR(PJ_EGONE, "Object no longer exists"),
82
PJ_BUILD_ERR(PJ_ESOCKETSTOP, "Socket is in bad state")
84
#endif /* PJ_HAS_ERROR_STRING */
90
* Retrieve message string for PJLIB's own error code.
92
static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
96
#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
99
for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
100
if (err_str[i].code == code) {
101
pj_size_t len = strlen(err_str[i].msg);
102
if (len >= size) len = size-1;
103
pj_memcpy(buf, err_str[i].msg, len);
110
len = pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
111
if (len < 1 || len >= (int)size)
112
len = (int)(size - 1);
116
#define IN_RANGE(val,start,end) ((val)>=(start) && (val)<(end))
118
/* Register strerror handle. */
119
PJ_DEF(pj_status_t) pj_register_strerror( pj_status_t start,
125
/* Check arguments. */
126
PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
128
/* Check if there aren't too many handlers registered. */
129
PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
132
/* Start error must be greater than PJ_ERRNO_START_USER */
133
PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
135
/* Check that no existing handler has covered the specified range. */
136
for (i=0; i<err_msg_hnd_cnt; ++i) {
137
if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
138
IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
140
if (err_msg_hnd[i].begin == start &&
141
err_msg_hnd[i].end == (start+space) &&
142
err_msg_hnd[i].strerror == f)
144
/* The same range and handler has already been registered */
152
/* Register the handler. */
153
err_msg_hnd[err_msg_hnd_cnt].begin = start;
154
err_msg_hnd[err_msg_hnd_cnt].end = start + space;
155
err_msg_hnd[err_msg_hnd_cnt].strerror = f;
162
/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
163
void pj_errno_clear_handlers(void)
166
pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
173
PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
174
char *buf, pj_size_t bufsize )
179
pj_assert(buf && bufsize);
181
if (statcode == PJ_SUCCESS) {
182
len = pj_ansi_snprintf( buf, bufsize, "Success");
184
} else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
185
len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
187
} else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
188
len = pjlib_error(statcode, buf, bufsize);
190
} else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
191
len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
196
/* Find user handler to get the error message. */
197
for (i=0; i<err_msg_hnd_cnt; ++i) {
198
if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
199
return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
203
/* Handler not found! */
204
len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
207
if (len < 1 || len >= (int)bufsize) {
208
len = (int)(bufsize - 1);
218
#if PJ_LOG_MAX_LEVEL >= 1
219
static void invoke_log(const char *sender, int level, const char *format, ...)
222
va_start(arg, format);
223
pj_log(sender, level, format, arg);
227
static void pj_perror_imp(int log_level, const char *sender,
229
const char *title_fmt, va_list marker)
231
char titlebuf[PJ_PERROR_TITLE_BUF_SIZE];
232
char errmsg[PJ_ERR_MSG_SIZE];
235
/* Build the title */
236
len = pj_ansi_vsnprintf(titlebuf, sizeof(titlebuf), title_fmt, marker);
237
if (len < 0 || len >= (int)sizeof(titlebuf))
238
pj_ansi_strcpy(titlebuf, "Error");
241
pj_strerror(status, errmsg, sizeof(errmsg));
244
invoke_log(sender, log_level, "%s: %s", titlebuf, errmsg);
247
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
248
const char *title_fmt, ...)
251
va_start(marker, title_fmt);
252
pj_perror_imp(log_level, sender, status, title_fmt, marker);
256
PJ_DEF(void) pj_perror_1(const char *sender, pj_status_t status,
257
const char *title_fmt, ...)
260
va_start(marker, title_fmt);
261
pj_perror_imp(1, sender, status, title_fmt, marker);
265
#else /* #if PJ_LOG_MAX_LEVEL >= 1 */
266
PJ_DEF(void) pj_perror(int log_level, const char *sender, pj_status_t status,
267
const char *title_fmt, ...)
270
#endif /* #if PJ_LOG_MAX_LEVEL >= 1 */
273
#if PJ_LOG_MAX_LEVEL >= 2
274
PJ_DEF(void) pj_perror_2(const char *sender, pj_status_t status,
275
const char *title_fmt, ...)
278
va_start(marker, title_fmt);
279
pj_perror_imp(2, sender, status, title_fmt, marker);
284
#if PJ_LOG_MAX_LEVEL >= 3
285
PJ_DEF(void) pj_perror_3(const char *sender, pj_status_t status,
286
const char *title_fmt, ...)
289
va_start(marker, title_fmt);
290
pj_perror_imp(3, sender, status, title_fmt, marker);
295
#if PJ_LOG_MAX_LEVEL >= 4
296
PJ_DEF(void) pj_perror_4(const char *sender, pj_status_t status,
297
const char *title_fmt, ...)
300
va_start(marker, title_fmt);
301
pj_perror_imp(4, sender, status, title_fmt, marker);
306
#if PJ_LOG_MAX_LEVEL >= 5
307
PJ_DEF(void) pj_perror_5(const char *sender, pj_status_t status,
308
const char *title_fmt, ...)
311
va_start(marker, title_fmt);
312
pj_perror_imp(5, sender, status, title_fmt, marker);
317
#if PJ_LOG_MAX_LEVEL >= 6
318
PJ_DEF(void) pj_perror_6(const char *sender, pj_status_t status,
319
const char *title_fmt, ...)
322
va_start(marker, title_fmt);
323
pj_perror_imp(6, sender, status, title_fmt, marker);