blob: 1b86d4c6995f726f4b12cedcf15b2a3355c1f0ff [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 Prijono1f7767b2007-10-03 18:28:49 +000073 PJ_BUILD_ERR(PJ_EIGNORED, "Ignored"),
Benny Prijono62b86eb2007-12-01 08:52:57 +000074 PJ_BUILD_ERR(PJ_EIPV6NOTSUP, "IPv6 is not supported"),
75 PJ_BUILD_ERR(PJ_EAFNOTSUP, "Unsupported address family")
Benny Prijono9033e312005-11-21 02:08:39 +000076};
Benny Prijono3ba816e2006-03-18 12:26:55 +000077#endif /* PJ_HAS_ERROR_STRING */
78
Benny Prijono9033e312005-11-21 02:08:39 +000079
80/*
81 * pjlib_error()
82 *
83 * Retrieve message string for PJLIB's own error code.
84 */
85static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
86{
Benny Prijono3ba816e2006-03-18 12:26:55 +000087#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
Benny Prijono9033e312005-11-21 02:08:39 +000088 unsigned i;
89
90 for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
91 if (err_str[i].code == code) {
92 pj_size_t len = strlen(err_str[i].msg);
93 if (len >= size) len = size-1;
94 pj_memcpy(buf, err_str[i].msg, len);
95 buf[len] = '\0';
96 return len;
97 }
98 }
Benny Prijono3ba816e2006-03-18 12:26:55 +000099#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000100
Benny Prijono3ba816e2006-03-18 12:26:55 +0000101 return pj_ansi_snprintf( buf, size, "Unknown pjlib error %d", code);
Benny Prijono9033e312005-11-21 02:08:39 +0000102}
103
Benny Prijonodcc29522006-02-02 19:15:03 +0000104#define IN_RANGE(val,start,end) ((val)>=(start) && (val)<(end))
105
106/* Register strerror handle. */
Benny Prijono8ab968f2007-07-20 08:08:30 +0000107PJ_DEF(pj_status_t) pj_register_strerror( pj_status_t start,
Benny Prijonodcc29522006-02-02 19:15:03 +0000108 pj_status_t space,
Benny Prijonoa0c8b5c2007-05-12 15:03:23 +0000109 pjsip_error_callback f)
Benny Prijonodcc29522006-02-02 19:15:03 +0000110{
111 unsigned i;
112
113 /* Check arguments. */
114 PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
115
116 /* Check if there aren't too many handlers registered. */
117 PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
118 PJ_ETOOMANY);
119
120 /* Start error must be greater than PJ_ERRNO_START_USER */
121 PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
122
123 /* Check that no existing handler has covered the specified range. */
124 for (i=0; i<err_msg_hnd_cnt; ++i) {
125 if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
126 IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
127 {
128 return PJ_EEXISTS;
129 }
130 }
131
132 /* Register the handler. */
133 err_msg_hnd[err_msg_hnd_cnt].begin = start;
134 err_msg_hnd[err_msg_hnd_cnt].end = start + space;
135 err_msg_hnd[err_msg_hnd_cnt].strerror = f;
136
137 ++err_msg_hnd_cnt;
138
139 return PJ_SUCCESS;
140}
141
Benny Prijonof762ee72006-12-01 11:14:37 +0000142/* Internal PJLIB function called by pj_shutdown() to clear error handlers */
143void pj_errno_clear_handlers(void)
144{
145 err_msg_hnd_cnt = 0;
146 pj_bzero(err_msg_hnd, sizeof(err_msg_hnd));
147}
148
149
Benny Prijono9033e312005-11-21 02:08:39 +0000150/*
151 * pj_strerror()
152 */
153PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
154 char *buf, pj_size_t bufsize )
155{
156 int len = -1;
157 pj_str_t errstr;
158
Benny Prijonodcc29522006-02-02 19:15:03 +0000159 pj_assert(buf && bufsize);
160
Benny Prijonod0a35852007-02-23 01:07:54 +0000161 if (statcode == PJ_SUCCESS) {
162 len = pj_ansi_snprintf( buf, bufsize, "Success");
163
164 } else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
Benny Prijonoed811d72006-03-10 12:57:12 +0000165 len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
Benny Prijono9033e312005-11-21 02:08:39 +0000166
167 } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
168 len = pjlib_error(statcode, buf, bufsize);
169
170 } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
171 len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
172
Benny Prijono9033e312005-11-21 02:08:39 +0000173 } else {
Benny Prijonodcc29522006-02-02 19:15:03 +0000174 unsigned i;
Benny Prijono9033e312005-11-21 02:08:39 +0000175
Benny Prijonodcc29522006-02-02 19:15:03 +0000176 /* Find user handler to get the error message. */
177 for (i=0; i<err_msg_hnd_cnt; ++i) {
178 if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
179 return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
180 }
181 }
Benny Prijonod424f5b2006-09-30 11:39:17 +0000182
183 /* Handler not found! */
184 len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
Benny Prijono9033e312005-11-21 02:08:39 +0000185 }
186
187 if (len < 1) {
188 *buf = '\0';
189 len = 0;
190 }
191
192 errstr.ptr = buf;
193 errstr.slen = len;
194
195 return errstr;
196}
197