Skip to content
Browse files

use FormatMessage for winsock errors

  • Loading branch information...
1 parent 7296512 commit 0c6ec5d816189805c6fafdf385b171cbc3f67ff3 @ppelleti ppelleti committed Feb 7, 2013
Showing with 130 additions and 68 deletions.
  1. +2 −0 event.c
  2. +1 −0 evthread-internal.h
  3. +127 −68 evutil.c
View
2 event.c
@@ -3468,6 +3468,8 @@ event_global_setup_locks_(const int enable_locks)
#endif
if (evsig_global_setup_locks_(enable_locks) < 0)
return -1;
+ if (evutil_global_setup_locks_(enable_locks) < 0)
+ return -1;
if (evutil_secure_rng_global_setup_locks_(enable_locks) < 0)
return -1;
return 0;
View
1 evthread-internal.h
@@ -373,6 +373,7 @@ void *evthread_setup_global_lock_(void *lock_, unsigned locktype,
int event_global_setup_locks_(const int enable_locks);
int evsig_global_setup_locks_(const int enable_locks);
+int evutil_global_setup_locks_(const int enable_locks);
int evutil_secure_rng_global_setup_locks_(const int enable_locks);
#endif
View
195 evutil.c
@@ -81,6 +81,7 @@
#include "util-internal.h"
#include "log-internal.h"
#include "mm-internal.h"
+#include "evthread-internal.h"
#include "strlcpy-internal.h"
#include "ipv6-internal.h"
@@ -1597,80 +1598,137 @@ evutil_gai_strerror(int err)
}
#ifdef _WIN32
-#define E(code, s) { code, (s " [" #code " ]") }
-static struct { int code; const char *msg; } windows_socket_errors[] = {
- E(WSAEINTR, "Interrupted function call"),
- E(WSAEACCES, "Permission denied"),
- E(WSAEFAULT, "Bad address"),
- E(WSAEINVAL, "Invalid argument"),
- E(WSAEMFILE, "Too many open files"),
- E(WSAEWOULDBLOCK, "Resource temporarily unavailable"),
- E(WSAEINPROGRESS, "Operation now in progress"),
- E(WSAEALREADY, "Operation already in progress"),
- E(WSAENOTSOCK, "Socket operation on nonsocket"),
- E(WSAEDESTADDRREQ, "Destination address required"),
- E(WSAEMSGSIZE, "Message too long"),
- E(WSAEPROTOTYPE, "Protocol wrong for socket"),
- E(WSAENOPROTOOPT, "Bad protocol option"),
- E(WSAEPROTONOSUPPORT, "Protocol not supported"),
- E(WSAESOCKTNOSUPPORT, "Socket type not supported"),
- /* What's the difference between NOTSUPP and NOSUPPORT? :) */
- E(WSAEOPNOTSUPP, "Operation not supported"),
- E(WSAEPFNOSUPPORT, "Protocol family not supported"),
- E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"),
- E(WSAEADDRINUSE, "Address already in use"),
- E(WSAEADDRNOTAVAIL, "Cannot assign requested address"),
- E(WSAENETDOWN, "Network is down"),
- E(WSAENETUNREACH, "Network is unreachable"),
- E(WSAENETRESET, "Network dropped connection on reset"),
- E(WSAECONNABORTED, "Software caused connection abort"),
- E(WSAECONNRESET, "Connection reset by peer"),
- E(WSAENOBUFS, "No buffer space available"),
- E(WSAEISCONN, "Socket is already connected"),
- E(WSAENOTCONN, "Socket is not connected"),
- E(WSAESHUTDOWN, "Cannot send after socket shutdown"),
- E(WSAETIMEDOUT, "Connection timed out"),
- E(WSAECONNREFUSED, "Connection refused"),
- E(WSAEHOSTDOWN, "Host is down"),
- E(WSAEHOSTUNREACH, "No route to host"),
- E(WSAEPROCLIM, "Too many processes"),
-
- /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */
- E(WSASYSNOTREADY, "Network subsystem is unavailable"),
- E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"),
- E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"),
- E(WSAEDISCON, "Graceful shutdown now in progress"),
-#ifdef WSATYPE_NOT_FOUND
- E(WSATYPE_NOT_FOUND, "Class type not found"),
-#endif
- E(WSAHOST_NOT_FOUND, "Host not found"),
- E(WSATRY_AGAIN, "Nonauthoritative host not found"),
- E(WSANO_RECOVERY, "This is a nonrecoverable error"),
- E(WSANO_DATA, "Valid name, no data record of requested type)"),
-
- /* There are some more error codes whose numeric values are marked
- * <b>OS dependent</b>. They start with WSA_, apparently for the same
- * reason that practitioners of some craft traditions deliberately
- * introduce imperfections into their baskets and rugs "to allow the
- * evil spirits to escape." If we catch them, then our binaries
- * might not report consistent results across versions of Windows.
- * Thus, I'm going to let them all fall through.
- */
- { -1, NULL },
+/* destructively remove a trailing line terminator from s */
+static void
+chomp (char *s)
+{
+ size_t len;
+ if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') {
+ s[--len] = 0;
+ if (len > 0 && s[len - 1] == '\r')
+ s[--len] = 0;
+ }
+}
+
+/* FormatMessage returns allocated strings, but evutil_socket_error_to_string
+ * is supposed to return a string which is good indefinitely without having
+ * to be freed. To make this work without leaking memory, we cache the
+ * string the first time FormatMessage is called on a particular error
+ * code, and then return the cached string on subsequent calls with the
+ * same code. The strings aren't freed until libevent_global_shutdown
+ * (or never). We use a linked list to cache the errors, because we
+ * only expect there to be a few dozen, and that should be fast enough.
+ */
+
+struct cached_sock_errs {
+ DWORD code;
+ char *msg; /* allocated with LocalAlloc; free with LocalFree */
+ struct cached_sock_errs *next;
};
-#undef E
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+static void *windows_socket_errors_lock_ = NULL;
+#endif
+
+static struct cached_sock_errs *windows_socket_errors;
+
/** Equivalent to strerror, but for windows socket errors. */
const char *
evutil_socket_error_to_string(int errcode)
{
- /* XXXX Is there really no built-in function to do this? */
- int i;
- for (i=0; windows_socket_errors[i].code >= 0; ++i) {
- if (errcode == windows_socket_errors[i].code)
- return windows_socket_errors[i].msg;
- }
- return strerror(errcode);
+ struct cached_sock_errs *errs, *newerr;
+ char *msg = NULL;
+
+ EVLOCK_LOCK(windows_socket_errors_lock_, 0);
+
+ for (errs = windows_socket_errors; errs != NULL; errs = errs->next)
+ if (errs->code == errcode) {
+ msg = errs->msg;
+ goto done;
+ }
+
+ if (0 != FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL, errcode, 0, (LPTSTR)&msg, 0, NULL))
+ chomp (msg); /* because message has trailing newline */
+ else {
+ size_t len = 50;
+ /* use LocalAlloc because FormatMessage does */
+ msg = LocalAlloc(LMEM_FIXED, len);
+ if (!msg) {
+ msg = "winsock error";
+ goto done;
+ }
+ evutil_snprintf(msg, len, "winsock error 0x%08x", errcode);
+ }
+
+ newerr = (struct cached_sock_errs *)
+ mm_malloc(sizeof (struct cached_sock_errs));
+
+ if (!newerr) {
+ LocalFree(msg);
+ msg = "winsock error";
+ goto done;
+ }
+
+ newerr->code = errcode;
+ newerr->msg = msg;
+ newerr->next = windows_socket_errors;
+ windows_socket_errors = newerr;
+
+ done:
+ EVLOCK_UNLOCK(windows_socket_errors_lock_, 0);
+
+ return msg;
}
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evutil_global_setup_locks_(const int enable_locks)
+{
+ EVTHREAD_SETUP_GLOBAL_LOCK(windows_socket_errors_lock_, 0);
+ return 0;
+}
+#endif
+
+static void
+evutil_free_sock_err_globals(void)
+{
+ struct cached_sock_errs *errs, *tofree;
+
+ for (errs = windows_socket_errors; errs != NULL; ) {
+ LocalFree (errs->msg);
+ tofree = errs;
+ errs = errs->next;
+ mm_free (tofree);
+ }
+
+ windows_socket_errors = NULL;
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+ if (windows_socket_errors_lock_ != NULL) {
+ EVTHREAD_FREE_LOCK(windows_socket_errors_lock_, 0);
+ windows_socket_errors_lock_ = NULL;
+ }
+#endif
+}
+
+#else
+
+#ifndef EVENT__DISABLE_THREAD_SUPPORT
+int
+evutil_global_setup_locks_(const int enable_locks)
+{
+ return 0;
+}
+#endif
+
+static void
+evutil_free_sock_err_globals(void)
+{
+}
+
#endif
int
@@ -2529,4 +2587,5 @@ void
evutil_free_globals_(void)
{
evutil_free_secure_rng_globals_();
+ evutil_free_sock_err_globals();
}

0 comments on commit 0c6ec5d

Please sign in to comment.
Something went wrong with that request. Please try again.