Added SILC errno API. Added SilcResult, generic error code and
[crypto.git] / lib / silcutil / silcerrno.c
diff --git a/lib/silcutil/silcerrno.c b/lib/silcutil/silcerrno.c
new file mode 100644 (file)
index 0000000..1739b2d
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+
+  silcerrno.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2007 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silc.h"
+
+/* Get last error */
+
+SilcResult silc_get_errno(void)
+{
+  SilcTls tls = silc_thread_get_tls();
+
+  if (!tls)
+    return SILC_OK;
+
+  return tls->error;
+}
+
+/* Set error */
+
+void silc_set_errno(SilcResult error)
+{
+  SilcTls tls = silc_thread_get_tls();
+
+  if (!tls) {
+    /* Try to create Tls */
+    tls = silc_thread_tls_init();
+    if (!tls)
+      return;
+  }
+
+  SILC_LOG_DEBUG(("Error: %s (%d)", silc_errno_string(error), error));
+
+  tls->error_reason[0] = '\0';
+  tls->error = error;
+}
+
+/* Set error, cannot fail. */
+
+void silc_set_errno_nofail(SilcResult error)
+{
+  SilcTls tls = silc_thread_get_tls();
+
+  if (!tls)
+    return;
+
+  SILC_LOG_DEBUG(("Error: %s (%d)", silc_errno_string(error), error));
+
+  tls->error_reason[0] = '\0';
+  tls->error = error;
+}
+
+/* Set errno and reason for error. */
+
+void silc_set_errno_reason(SilcResult error, const char *format, ...)
+{
+  SilcTls tls = silc_thread_get_tls();
+  va_list va;
+
+  if (!tls) {
+    /* Try to create Tls */
+    tls = silc_thread_tls_init();
+    if (!tls)
+      return;
+  }
+
+  va_start(va, format);
+  silc_vsnprintf(tls->error_reason, sizeof(tls->error_reason), format, va);
+  va_end(va);
+
+  SILC_LOG_DEBUG(("Error: %s (%d): %s", silc_errno_string(error), error,
+                 tls->error_reason));
+
+  tls->error = error;
+}
+
+/* Set errno and reason for error, cannot fail. */
+
+void silc_set_errno_reason_nofail(SilcResult error, const char *format, ...)
+{
+  SilcTls tls = silc_thread_get_tls();
+  va_list va;
+
+  if (!tls)
+    return;
+
+  va_start(va, format);
+  silc_vsnprintf(tls->error_reason, sizeof(tls->error_reason), format, va);
+  va_end(va);
+
+  SILC_LOG_DEBUG(("Error: %s (%d): %s", silc_errno_string(error), error,
+                 tls->error_reason));
+
+  tls->error = error;
+}
+
+/* Set error from POSIX errno. */
+
+void silc_set_errno_posix(int error)
+{
+  if (!error)
+    return;
+
+#ifdef SILC_WIN32
+  /* WSA errors */
+  switch (error) {
+  case WSAEINTR:
+    silc_set_errno(SILC_ERR_INTERRUPTED);
+    break;
+  case WSAEBADF:
+    silc_set_errno(SILC_ERR_BAD_FD);
+    break;
+  case WSAEACCESS:
+    silc_set_errno(SILC_ERR_PERMISSION_DENIED);
+    break;
+  case WSAEFAULT:
+    silc_set_errno(SILC_ERR_BAD_ADDRESS);
+    break;
+  case WSA_INVALID_HANDLE:
+  case WSAENOTSOCK:
+    silc_set_errno(SILC_ERR_BAD_SOCKET);
+    break;
+  case WSA_INVALID_PARAMETER:
+  case WSAEINVAL:
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    break;
+  case WSA_NOT_ENOUGH_MEMORY:
+    silc_set_errno(SILC_ERR_OUT_OF_MEMORY);
+    break;
+  case WSAEWOULDBLOCK:
+    silc_set_errno(SILC_ERR_WOULD_BLOCK);
+    break;
+  case WSAEOPNOTSUPPORT:
+    silc_set_errno(SILC_ERR_NOT_SUPPORTED);
+    break;
+  case WSAEADDRINUSE:
+    silc_set_errno(SILC_ERR_ADDR_IN_USE);
+    break;
+  case WSAEANETDOWN:
+    silc_set_errno(SILC_ERR_NET_DOWN);
+    break;
+  case WSAENETUNREACH:
+  case WSAEHOSTUNREACH:
+    silc_set_errno(SILC_ERR_UNREACHABLE);
+    break;
+  case WSAENETRESET:
+    silc_set_errno(SILC_ERR_RESET);
+    break;
+  case WSAECONNABORTED:
+    silc_set_errno(SILC_ERR_ABORTED);
+    break;
+  case WSAETIMEDOUT:
+    silc_set_errno(SILC_ERR_TIMEOUT);
+    break;
+  case WSAECONNREFUSED:
+    silc_set_errno(SILC_ERR_REFUSED);
+    break;
+  case WSAEHOSTDOWN:
+    silc_set_errno(SILC_ERR_HOST_DOWN);
+    break;
+  default:
+    silc_set_errno(SILC_ERR);
+    break;
+  }
+
+  return;
+#endif /* SILC_WIN32 */
+
+  /* POSIX, etc. errors */
+  switch (error) {
+#if defined(ENOMEM)
+  case ENOMEM:
+    silc_set_errno(SILC_ERR_OUT_OF_MEMORY);
+    break;
+#endif
+#if defined(EAGAIN)
+  case EAGAIN:
+    silc_set_errno(SILC_ERR_WOULD_BLOCK);
+    break;
+#endif
+#if defined(EINVAL)
+  case EINVAL:
+    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    break;
+#endif
+#if defined(EINTR)
+  case EINTR:
+    silc_set_errno(SILC_ERR_INTERRUPTED);
+    break;
+#endif
+#if defined(EIO)
+  case EIO:
+    silc_set_errno(SILC_ERR_IO);
+    break;
+#endif
+#if defined(EPIPE)
+  case EPIPE:
+    silc_set_errno(SILC_ERR_BROKEN_PIPE);
+    break;
+#endif
+#if defined(ENOENT)
+  case ENOENT:
+    silc_set_errno(SILC_ERR_NO_SUCH_FILE);
+    break;
+#endif
+#if defined(EEXIST)
+  case EEXIST:
+    silc_set_errno(SILC_ERR_ALREADY_EXISTS);
+    break;
+#endif
+#if defined(ENOTDIR)
+  case ENOTDIR:
+    silc_set_errno(SILC_ERR_NOT_DIRECTORY);
+    break;
+#endif
+#if defined(EISDIR)
+  case EISDIR:
+    silc_set_errno(SILC_ERR_IS_DIRECTORY);
+    break;
+#endif
+#if defined(EBUSY)
+  case EBUSY:
+    silc_set_errno(SILC_ERR_BUSY);
+    break;
+#endif
+#if defined(ENODEV)
+  case ENODEV:
+    silc_set_errno(SILC_ERR_NO_SUCH_DEVICE);
+    break;
+#endif
+#if defined(ENOSPC)
+  case ENOSPC:
+    silc_set_errno(SILC_ERR_NO_SPACE_LEFT);
+    break;
+#endif
+#if defined(EROFS)
+  case EROFS:
+    silc_set_errno(SILC_ERR_READ_ONLY);
+    break;
+#endif
+#if defined(EBADFS)
+  case EBADFS:
+    silc_set_errno(SILC_ERR_BAD_FD);
+    break;
+#endif
+#if defined(EADDRINUSE)
+  case EADDRINUSE:
+    silc_set_errno(SILC_ERR_ADDR_IN_USE);
+    break;
+#endif
+#if defined(ECONNREFUSED)
+  case ECONNREFUSED:
+    silc_set_errno(SILC_ERR_REFUSED);
+    break;
+#endif
+#if defined(ECONNABORTED)
+  case ECONNABORTED:
+    silc_set_errno(SILC_ERR_ABORTED);
+    break;
+#endif
+#if defined(ECONNRESET)
+  case ECONNRESET:
+    silc_set_errno(SILC_ERR_RESET);
+    break;
+#endif
+#if defined(ENETUNREACH)
+  case ENETUNREACH:
+    silc_set_errno(SILC_ERR_UNREACHABLE);
+    break;
+#endif
+#if defined(EHOSTUNREACH)
+  case EHOSTUNREACH:
+    silc_set_errno(SILC_ERR_UNREACHABLE);
+    break;
+#endif
+#if defined(ENETDOWN)
+  case ENETDOWN:
+    silc_set_errno(SILC_ERR_NET_DOWN);
+    break;
+#endif
+#if defined(ETIMEDOUT)
+  case ETIMEDOUT:
+    silc_set_errno(SILC_ERR_TIMEOUT);
+    break;
+#endif
+#if defined(EHOSTDOWN)
+  case EHOSTDOWN:
+    silc_set_errno(SILC_ERR_HOST_DOWN);
+    break;
+#endif
+  default:
+    silc_set_errno(SILC_ERR);
+    break;
+  }
+}
+
+/* Get last reason for error */
+
+const char *silc_errno_reason(void)
+{
+  SilcTls tls = silc_thread_get_tls();
+
+  if (!tls || tls->error_reason[0] == '\0')
+    return (const char *)"";
+
+  return tls->error_reason;
+}
+
+const char *silc_errno_strings[] =
+{
+  "Ok",
+
+  "Error",
+  "Out of memory",
+  "Allocation by zero",
+  "Too large allocation",
+  "Overflow",
+  "Underflow",
+  "Feature not supported",
+  "Operation not permitted",
+  "Try again",
+  "Permission denied",
+  "Invalid argument",
+  "Bad time",
+  "Timeout",
+  "Assert",
+  "Not found",
+  "Unknown character",
+  "Prohibited character",
+  "Bad character encoding",
+  "Unsupported character encoding",
+  "Bad version",
+  "Bad memory address",
+  "Bad buffer encoding",
+  "Interrupted",
+  "Not valid",
+  "Limit reached",
+
+  "No such file or directory",
+  "Already exists",
+  "Not a directory",
+  "Is a directory",
+  "Directory not empty",
+  "Device or resource busy",
+  "No such device",
+  "No space left on device",
+  "Broken pipe",
+  "Read only",
+  "I/O error",
+  "Bad file descriptor",
+  "End of file",
+
+  "Bad IP address",
+  "Unknown IP address",
+  "Unknown host",
+  "Destination unreachable",
+  "Connection refused",
+  "Connection aborted",
+  "Connection reset by peer",
+  "Would block",
+  "Host is down",
+  "Bad socket",
+  "Bad stream",
+  "Address already in use",
+  "Network is down",
+  "End of stream",
+
+  NULL
+};
+
+/* Map error to string */
+
+const char *silc_errno_string(SilcResult error)
+{
+  if (error < 0 || error >= SILC_ERR_MAX)
+    return (const char *)"";
+
+  return silc_errno_strings[error];
+}