blob: f7273a429eefcaaf839b1147f88e4d4ea2940437 [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 Prijonof260e462007-04-30 21:03:32 +000021#include <pj/compat/string.h>
Benny Prijonodcc29522006-02-02 19:15:03 +000022#include <pj/assert.h>
Benny Prijono9033e312005-11-21 02:08:39 +000023
24/* Prototype for platform specific error message, which will be defined
25 * in separate file.
26 */
Benny Prijonof260e462007-04-30 21:03:32 +000027PJ_BEGIN_DECL
28
29 PJ_DECL(int) platform_strerror(pj_os_err_type code,
30 char *buf, pj_size_t bufsize );
31PJ_END_DECL
Benny Prijono9033e312005-11-21 02:08:39 +000032
Benny Prijonodcc29522006-02-02 19:15:03 +000033#define PJLIB_MAX_ERR_MSG_HANDLER 8
34
35/* Error message handler. */
36static unsigned err_msg_hnd_cnt;
37static struct err_msg_hnd
38{
39 pj_status_t begin;
40 pj_status_t end;
41 pj_str_t (*strerror)(pj_status_t, char*, pj_size_t);
42
43} err_msg_hnd[PJLIB_MAX_ERR_MSG_HANDLER];
44
Benny Prijono9033e312005-11-21 02:08:39 +000045/* PJLIB's own error codes/messages */
Benny Prijono3ba816e2006-03-18 12:26:55 +000046#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
Benny Prijono7eaa0fd2006-06-22 18:30:13 +000047
Benny Prijono9033e312005-11-21 02:08:39 +000048static const struct
49{
50 int code;
51 const char *msg;
52} err_str[] =
53{
Benny Prijono7eaa0fd2006-06-22 18:30:13 +000054 PJ_BUILD_ERR(PJ_EUNKNOWN, "Unknown Error" ),
55 PJ_BUILD_ERR(PJ_EPENDING, "Pending operation" ),
56 PJ_BUILD_ERR(PJ_ETOOMANYCONN, "Too many connecting sockets" ),
57 PJ_BUILD_ERR(PJ_EINVAL, "Invalid value or argument" ),
58 PJ_BUILD_ERR(PJ_ENAMETOOLONG, "Name too long" ),
59 PJ_BUILD_ERR(PJ_ENOTFOUND, "Not found" ),
60 PJ_BUILD_ERR(PJ_ENOMEM, "Not enough memory" ),
61 PJ_BUILD_ERR(PJ_EBUG, "BUG DETECTED!" ),
62 PJ_BUILD_ERR(PJ_ETIMEDOUT, "Operation timed out" ),
63 PJ_BUILD_ERR(PJ_ETOOMANY, "Too many objects of the specified type"),
64 PJ_BUILD_ERR(PJ_EBUSY, "Object is busy"),
65 PJ_BUILD_ERR(PJ_ENOTSUP, "Option/operation is not supported"),
66 PJ_BUILD_ERR(PJ_EINVALIDOP, "Invalid operation"),
67 PJ_BUILD_ERR(PJ_ECANCELLED, "Operation cancelled"),
68 PJ_BUILD_ERR(PJ_EEXISTS, "Object already exists" ),
69 PJ_BUILD_ERR(PJ_EEOF, "End of file" ),
70 PJ_BUILD_ERR(PJ_ETOOBIG, "Size is too big"),
Benny Prijonocca32812006-09-14 21:16:11 +000071 PJ_BUILD_ERR(PJ_ERESOLVE, "gethostbyname() has returned error"),
Benny Prijonod424f5b2006-09-30 11:39:17 +000072 PJ_BUILD_ERR(PJ_ETOOSMALL, "Size is too short"),
Benny Prijono9033e312005-11-21 02:08:39 +000073};
Benny Prijono3ba816e2006-03-18 12:26:55 +000074#endif /* PJ_HAS_ERROR_STRING */
75
Benny Prijono9033e312005-11-21 02:08:39 +000076
77/*
78 * pjlib_error()
79 *
80 * Retrieve message string for PJLIB's own error code.
81 */
82static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
83{
Benny Prijono3ba816e2006-03-18 12:26:55 +000084#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
Benny Prijono9033e312005-11-21 02:08:39 +000085 unsigned i;
86
87 for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
88 if (err_str[i].code == code) {
89 pj_size_t len = strlen(err_str[i].msg);
90 if (len >= size) len = size-1;
91 pj_memcpy(buf, err_str[i].msg, len);
92 buf[len] = '\0';
93 return len;
94 }
95 }
Benny Prijono3ba816e2006-03-18 12:26:55 +000096#endif
Benny Prijono9033e312005-11-21 02:08:39 +000097
Benny Prijono3ba816e2006-03-18 12:26:55 +000098 return pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
Benny Prijono9033e312005-11-21 02:08:39 +000099}
100
Benny Prijonodcc29522006-02-02 19:15:03 +0000101#define IN_RANGE(val,start,end) ((val)>=(start) && (val)<(end))
102
103/* Register strerror handle. */
104PJ_DECL(pj_status_t) pj_register_strerror(pj_status_t start,
105 pj_status_t space,
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000106 pjsip_error_callback f)
Benny Prijonodcc29522006-02-02 19:15:03 +0000107{
108 unsigned i;
109
110 /* Check arguments. */
111 PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
112
113 /* Check if there aren't too many handlers registered. */
114 PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
115 PJ_ETOOMANY);
116
117 /* Start error must be greater than PJ_ERRNO_START_USER */
118 PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
119
120 /* Check that no existing handler has covered the specified range. */
121 for (i=0; i<err_msg_hnd_cnt; ++i) {
122 if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
123 IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
124 {
125 return PJ_EEXISTS;
126 }
127 }
128
129 /* Register the handler. */
130 err_msg_hnd[err_msg_hnd_cnt].begin = start;
131 err_msg_hnd[err_msg_hnd_cnt].end = start + space;
132 err_msg_hnd[err_msg_hnd_cnt].strerror = f;
133
134 ++err_msg_hnd_cnt;
135
136 return PJ_SUCCESS;
137}
138
Benny Prijonof762ee72006-12-01 11:14:37 +0000139/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
140void pj_errno_clear_handlers(void)
141{
142 err_msg_hnd_cnt = 0;
143 pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
144}
145
146
Benny Prijono9033e312005-11-21 02:08:39 +0000147/*
148 * pj_strerror()
149 */
150PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
151 char *buf, pj_size_t bufsize )
152{
153 int len = -1;
154 pj_str_t errstr;
155
Benny Prijonodcc29522006-02-02 19:15:03 +0000156 pj_assert(buf && bufsize);
157
Benny Prijonod0a35852007-02-23 01:07:54 +0000158 if (statcode == PJ_SUCCESS) {
159 len = pj_ansi_snprintf( buf, bufsize, "Success");
160
161 } else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
Benny Prijonoed811d72006-03-10 12:57:12 +0000162 len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
Benny Prijono9033e312005-11-21 02:08:39 +0000163
164 } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
165 len = pjlib_error(statcode, buf, bufsize);
166
167 } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
168 len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
169
Benny Prijono9033e312005-11-21 02:08:39 +0000170 } else {
Benny Prijonodcc29522006-02-02 19:15:03 +0000171 unsigned i;
Benny Prijono9033e312005-11-21 02:08:39 +0000172
Benny Prijonodcc29522006-02-02 19:15:03 +0000173 /* Find user handler to get the error message. */
174 for (i=0; i<err_msg_hnd_cnt; ++i) {
175 if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
176 return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
177 }
178 }
Benny Prijonod424f5b2006-09-30 11:39:17 +0000179
180 /* Handler not found! */
181 len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
Benny Prijono9033e312005-11-21 02:08:39 +0000182 }
183
184 if (len < 1) {
185 *buf = '\0';
186 len = 0;
187 }
188
189 errstr.ptr = buf;
190 errstr.slen = len;
191
192 return errstr;
193}
194