blob: 7745dfd2c4529c55027e841dcf0a556085c2594e [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00004 *
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/string.h>
Benny Prijonodcc29522006-02-02 19:15:03 +000021#include <pj/assert.h>
Benny Prijono9033e312005-11-21 02:08:39 +000022
23/* Prototype for platform specific error message, which will be defined
24 * in separate file.
25 */
26extern int platform_strerror( pj_os_err_type code,
27 char *buf, pj_size_t bufsize );
28
Benny Prijonodcc29522006-02-02 19:15:03 +000029#define PJLIB_MAX_ERR_MSG_HANDLER 8
30
31/* Error message handler. */
32static unsigned err_msg_hnd_cnt;
33static struct err_msg_hnd
34{
35 pj_status_t begin;
36 pj_status_t end;
37 pj_str_t (*strerror)(pj_status_t, char*, pj_size_t);
38
39} err_msg_hnd[PJLIB_MAX_ERR_MSG_HANDLER];
40
Benny Prijono9033e312005-11-21 02:08:39 +000041/* PJLIB's own error codes/messages */
Benny Prijono3ba816e2006-03-18 12:26:55 +000042#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
Benny Prijono7eaa0fd2006-06-22 18:30:13 +000043
Benny Prijono9033e312005-11-21 02:08:39 +000044static const struct
45{
46 int code;
47 const char *msg;
48} err_str[] =
49{
Benny Prijono7eaa0fd2006-06-22 18:30:13 +000050 PJ_BUILD_ERR(PJ_EUNKNOWN, "Unknown Error" ),
51 PJ_BUILD_ERR(PJ_EPENDING, "Pending operation" ),
52 PJ_BUILD_ERR(PJ_ETOOMANYCONN, "Too many connecting sockets" ),
53 PJ_BUILD_ERR(PJ_EINVAL, "Invalid value or argument" ),
54 PJ_BUILD_ERR(PJ_ENAMETOOLONG, "Name too long" ),
55 PJ_BUILD_ERR(PJ_ENOTFOUND, "Not found" ),
56 PJ_BUILD_ERR(PJ_ENOMEM, "Not enough memory" ),
57 PJ_BUILD_ERR(PJ_EBUG, "BUG DETECTED!" ),
58 PJ_BUILD_ERR(PJ_ETIMEDOUT, "Operation timed out" ),
59 PJ_BUILD_ERR(PJ_ETOOMANY, "Too many objects of the specified type"),
60 PJ_BUILD_ERR(PJ_EBUSY, "Object is busy"),
61 PJ_BUILD_ERR(PJ_ENOTSUP, "Option/operation is not supported"),
62 PJ_BUILD_ERR(PJ_EINVALIDOP, "Invalid operation"),
63 PJ_BUILD_ERR(PJ_ECANCELLED, "Operation cancelled"),
64 PJ_BUILD_ERR(PJ_EEXISTS, "Object already exists" ),
65 PJ_BUILD_ERR(PJ_EEOF, "End of file" ),
66 PJ_BUILD_ERR(PJ_ETOOBIG, "Size is too big"),
Benny Prijonocca32812006-09-14 21:16:11 +000067 PJ_BUILD_ERR(PJ_ERESOLVE, "gethostbyname() has returned error"),
Benny Prijonod424f5b2006-09-30 11:39:17 +000068 PJ_BUILD_ERR(PJ_ETOOSMALL, "Size is too short"),
Benny Prijono9033e312005-11-21 02:08:39 +000069};
Benny Prijono3ba816e2006-03-18 12:26:55 +000070#endif /* PJ_HAS_ERROR_STRING */
71
Benny Prijono9033e312005-11-21 02:08:39 +000072
73/*
74 * pjlib_error()
75 *
76 * Retrieve message string for PJLIB's own error code.
77 */
78static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
79{
Benny Prijono3ba816e2006-03-18 12:26:55 +000080#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
Benny Prijono9033e312005-11-21 02:08:39 +000081 unsigned i;
82
83 for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
84 if (err_str[i].code == code) {
85 pj_size_t len = strlen(err_str[i].msg);
86 if (len >= size) len = size-1;
87 pj_memcpy(buf, err_str[i].msg, len);
88 buf[len] = '\0';
89 return len;
90 }
91 }
Benny Prijono3ba816e2006-03-18 12:26:55 +000092#endif
Benny Prijono9033e312005-11-21 02:08:39 +000093
Benny Prijono3ba816e2006-03-18 12:26:55 +000094 return pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
Benny Prijono9033e312005-11-21 02:08:39 +000095}
96
Benny Prijonodcc29522006-02-02 19:15:03 +000097#define IN_RANGE(val,start,end) ((val)>=(start) && (val)<(end))
98
99/* Register strerror handle. */
100PJ_DECL(pj_status_t) pj_register_strerror(pj_status_t start,
101 pj_status_t space,
102 pj_str_t (*f)(pj_status_t,char*,
103 pj_size_t))
104{
105 unsigned i;
106
107 /* Check arguments. */
108 PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
109
110 /* Check if there aren't too many handlers registered. */
111 PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
112 PJ_ETOOMANY);
113
114 /* Start error must be greater than PJ_ERRNO_START_USER */
115 PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
116
117 /* Check that no existing handler has covered the specified range. */
118 for (i=0; i<err_msg_hnd_cnt; ++i) {
119 if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
120 IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
121 {
122 return PJ_EEXISTS;
123 }
124 }
125
126 /* Register the handler. */
127 err_msg_hnd[err_msg_hnd_cnt].begin = start;
128 err_msg_hnd[err_msg_hnd_cnt].end = start + space;
129 err_msg_hnd[err_msg_hnd_cnt].strerror = f;
130
131 ++err_msg_hnd_cnt;
132
133 return PJ_SUCCESS;
134}
135
Benny Prijonof762ee72006-12-01 11:14:37 +0000136/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
137void pj_errno_clear_handlers(void)
138{
139 err_msg_hnd_cnt = 0;
140 pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
141}
142
143
Benny Prijono9033e312005-11-21 02:08:39 +0000144/*
145 * pj_strerror()
146 */
147PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
148 char *buf, pj_size_t bufsize )
149{
150 int len = -1;
151 pj_str_t errstr;
152
Benny Prijonodcc29522006-02-02 19:15:03 +0000153 pj_assert(buf && bufsize);
154
Benny Prijonod0a35852007-02-23 01:07:54 +0000155 if (statcode == PJ_SUCCESS) {
156 len = pj_ansi_snprintf( buf, bufsize, "Success");
157
158 } else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
Benny Prijonoed811d72006-03-10 12:57:12 +0000159 len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
Benny Prijono9033e312005-11-21 02:08:39 +0000160
161 } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
162 len = pjlib_error(statcode, buf, bufsize);
163
164 } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
165 len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
166
Benny Prijono9033e312005-11-21 02:08:39 +0000167 } else {
Benny Prijonodcc29522006-02-02 19:15:03 +0000168 unsigned i;
Benny Prijono9033e312005-11-21 02:08:39 +0000169
Benny Prijonodcc29522006-02-02 19:15:03 +0000170 /* Find user handler to get the error message. */
171 for (i=0; i<err_msg_hnd_cnt; ++i) {
172 if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
173 return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
174 }
175 }
Benny Prijonod424f5b2006-09-30 11:39:17 +0000176
177 /* Handler not found! */
178 len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
Benny Prijono9033e312005-11-21 02:08:39 +0000179 }
180
181 if (len < 1) {
182 *buf = '\0';
183 len = 0;
184 }
185
186 errstr.ptr = buf;
187 errstr.slen = len;
188
189 return errstr;
190}
191