Add an error code.
[libradsec.git] / lib / err.c
1 /* Copyright 2010, 2011 NORDUnet A/S. All rights reserved.
2    See the file COPYING for licensing information.  */
3
4 #if defined HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <radsec/radsec.h>
12 #include <radsec/radsec-impl.h>
13
14 static const char *_errtxt[] = {
15   "SUCCESS",                    /* 0 RSE_OK */
16   "out of memory",              /* 1 RSE_NOMEM */
17   "not yet implemented",        /* 2 RSE_NOSYS */
18   "invalid handle",             /* 3 RSE_INVALID_CTX */
19   "invalid connection",         /* 4 RSE_INVALID_CONN */
20   "connection type mismatch",   /* 5 RSE_CONN_TYPE_MISMATCH */
21   "FreeRadius error",           /* 6 RSE_FR */
22   "bad hostname or port",       /* 7 RSE_BADADDR */
23   "no peer configured",         /* 8 RSE_NOPEER */
24   "libevent error",             /* 9 RSE_EVENT */
25   "socket error",               /* 10 RSE_SOCKERR */
26   "invalid configuration file", /* 11 RSE_CONFIG */
27   "authentication failed",      /* 12 RSE_BADAUTH */
28   "internal error",             /* 13 RSE_INTERNAL */
29   "SSL error",                  /* 14 RSE_SSLERR */
30   "invalid packet",             /* 15 RSE_INVALID_PKT */
31   "connect timeout",            /* 16 RSE_TIMEOUT_CONN */
32   "invalid argument",           /* 17 RSE_INVAL */
33   "I/O timeout",                /* 18 RSE_TIMEOUT_IO */
34   "timeout",                    /* 19 RSE_TIMEOUT */
35   "peer disconnected",          /* 20 RSE_DISCO */
36   "invalid credentials",        /* 21 RSE_CRED */
37   "certificate validation error", /* 22 RSE_CERT */
38 };
39 #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt))
40
41 static struct rs_error *
42 _err_vcreate (unsigned int code, const char *file, int line, const char *fmt,
43               va_list args)
44 {
45   struct rs_error *err = NULL;
46
47   err = malloc (sizeof(struct rs_error));
48   if (err)
49     {
50       int n;
51       memset (err, 0, sizeof(struct rs_error));
52       err->code = code;
53       if (fmt)
54         n = vsnprintf (err->buf, sizeof(err->buf), fmt, args);
55       else
56         {
57           strncpy (err->buf,
58                    err->code < ERRTXT_SIZE ? _errtxt[err->code] : "",
59                    sizeof(err->buf));
60           n = strlen (err->buf);
61         }
62       if (n >= 0 && file)
63         {
64           char *sep = strrchr (file, '/');
65           if (sep)
66             file = sep + 1;
67           snprintf (err->buf + n, sizeof(err->buf) - n, " (%s:%d)", file,
68                     line);
69         }
70     }
71   return err;
72 }
73
74 struct rs_error *
75 err_create (unsigned int code,
76             const char *file,
77             int line,
78             const char *fmt,
79             ...)
80 {
81   struct rs_error *err = NULL;
82
83   va_list args;
84   va_start (args, fmt);
85   err = _err_vcreate (code, file, line, fmt, args);
86   va_end (args);
87
88   return err;
89 }
90
91 static int
92 _ctx_err_vpush_fl (struct rs_context *ctx, int code, const char *file,
93                    int line, const char *fmt, va_list args)
94 {
95   struct rs_error *err = _err_vcreate (code, file, line, fmt, args);
96
97   if (!err)
98     return RSE_NOMEM;
99
100   /* TODO: Implement a stack.  */
101   if (ctx->err)
102     rs_err_free (ctx->err);
103   ctx->err = err;
104
105   return err->code;
106 }
107
108 int
109 rs_err_ctx_push (struct rs_context *ctx, int code, const char *fmt, ...)
110 {
111   int r = 0;
112   va_list args;
113
114   va_start (args, fmt);
115   r = _ctx_err_vpush_fl (ctx, code, NULL, 0, fmt, args);
116   va_end (args);
117
118   return r;
119 }
120
121 int
122 rs_err_ctx_push_fl (struct rs_context *ctx, int code, const char *file,
123                     int line, const char *fmt, ...)
124 {
125   int r = 0;
126   va_list args;
127
128   va_start (args, fmt);
129   r = _ctx_err_vpush_fl (ctx, code, file, line, fmt, args);
130   va_end (args);
131
132   return r;
133 }
134
135 int
136 err_conn_push_err (struct rs_connection *conn, struct rs_error *err)
137 {
138
139   if (conn->err)
140     rs_err_free (conn->err);
141   conn->err = err;              /* FIXME: use a stack */
142
143   return err->code;
144 }
145
146 static int
147 _conn_err_vpush_fl (struct rs_connection *conn, int code, const char *file,
148                     int line, const char *fmt, va_list args)
149 {
150   struct rs_error *err = _err_vcreate (code, file, line, fmt, args);
151
152   if (!err)
153     return RSE_NOMEM;
154
155   return err_conn_push_err (conn, err);
156 }
157
158 int
159 rs_err_conn_push (struct rs_connection *conn, int code, const char *fmt, ...)
160 {
161   int r = 0;
162
163   va_list args;
164   va_start (args, fmt);
165   r = _conn_err_vpush_fl (conn, code, NULL, 0, fmt, args);
166   va_end (args);
167
168   return r;
169 }
170
171 int
172 rs_err_conn_push_fl (struct rs_connection *conn, int code, const char *file,
173                      int line, const char *fmt, ...)
174 {
175   int r = 0;
176
177   va_list args;
178   va_start (args, fmt);
179   r = _conn_err_vpush_fl (conn, code, file, line, fmt, args);
180   va_end (args);
181
182   return r;
183 }
184
185 struct rs_error *
186 rs_err_ctx_pop (struct rs_context *ctx)
187 {
188   struct rs_error *err;
189
190   if (!ctx)
191     return NULL;                /* FIXME: RSE_INVALID_CTX.  */
192   err = ctx->err;
193   ctx->err = NULL;
194
195   return err;
196 }
197
198 struct rs_error *
199 rs_err_conn_pop (struct rs_connection *conn)
200 {
201   struct rs_error *err;
202
203   if (!conn)
204     return NULL;                /* FIXME: RSE_INVALID_CONN */
205   err = conn->err;
206   conn->err = NULL;
207
208   return err;
209 }
210
211 int
212 rs_err_conn_peek_code (struct rs_connection *conn)
213 {
214   if (!conn)
215     return -1;                  /* FIXME: RSE_INVALID_CONN */
216   if (conn->err)
217     return conn->err->code;
218
219   return RSE_OK;
220 }
221
222 void
223 rs_err_free (struct rs_error *err)
224 {
225   assert (err);
226   free (err);
227 }
228
229 char *
230 rs_err_msg (struct rs_error *err)
231 {
232   if (!err)
233     return NULL;
234
235   return err->buf;
236 }
237
238 int
239 rs_err_code (struct rs_error *err, int dofree_flag)
240 {
241   int code;
242
243   if (!err)
244     return -1;
245   code = err->code;
246
247   if (dofree_flag)
248     rs_err_free (err);
249
250   return code;
251 }