summaryrefslogtreecommitdiffstats
path: root/utils/async_netdb.h
diff options
context:
space:
mode:
Diffstat (limited to 'utils/async_netdb.h')
-rw-r--r--utils/async_netdb.h223
1 files changed, 223 insertions, 0 deletions
diff --git a/utils/async_netdb.h b/utils/async_netdb.h
new file mode 100644
index 0000000..a72f4d5
--- /dev/null
+++ b/utils/async_netdb.h
@@ -0,0 +1,223 @@
+/* vi: set tw=78: */
+
+/* async_netdb.h, Copyright (c) Dave Odell <dmo2118@gmail.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifndef ASYNC_NETDB_H
+#define ASYNC_NETDB_H
+
+#include "thread_util.h"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+/*
+ Both async_name_from_addr_* and async_addr_from_name_* follow basic pattern
+ for io_thread clients as described in thread_util.h:
+ 1. async_*_from_*_start
+ 2. async_*_from_*_is_done (repeat as necessary)
+ 3a. async_*_from_*_finish to retrieve the results, or:
+ 3b. async_*_from_*_cancel to abort the lookup.
+
+ On systems that can't do asynchronous host lookups, the *_finish functions
+ do the actual lookup.
+ */
+
+#ifndef NI_MAXHOST
+/*
+ From the glibc man page for getnameinfo(3):
+ Since glibc 2.8, these definitions are exposed only if one of the
+ feature test macros _BSD_SOURCE, _SVID_SOURCE, or _GNU_SOURCE is
+ defined.
+ */
+# define NI_MAXHOST 1025
+#endif
+
+#if HAVE_PTHREAD && HAVE_GETADDRINFO
+/*
+ If threads or getaddrinfo() are unavailable, then the older gethostbyname()
+ and gethostbyaddr() functions are used, and IPv6 is disabled.
+ */
+# define ASYNC_NETDB_USE_GAI 1
+#endif
+
+#if ASYNC_NETDB_USE_GAI
+
+/* Without using union, gcc-6 warns for
+ breaking strict aliasing rules
+ */
+typedef union {
+ struct sockaddr_storage x_sockaddr_storage;
+ struct sockaddr_in x_sockaddr_in;
+ struct sockaddr_in6 x_sockaddr_in6;
+} async_netdb_sockaddr_storage_t;
+
+int _async_netdb_is_done (struct io_thread *io);
+
+#else
+
+/* Because the definition for the above case is now union,
+ the definition for this case must also be union...
+*/
+typedef union {
+ struct sockaddr_in x_sockaddr_in;
+} async_netdb_sockaddr_storage_t;
+
+# ifndef EAI_SYSTEM
+/* The EAI_* codes are specified specifically as preprocessor macros, so
+ the #ifdef here should always work...
+ http://pubs.opengroup.org/onlinepubs/009604499/basedefs/netdb.h.html */
+
+# define ASYNC_NETDB_FAKE_EAI 1
+
+/* Even without addrinfo, the EAI_* error codes are used. The numbers are from
+ Linux's netdb.h. */
+# define EAI_NONAME -2
+# define EAI_AGAIN -3
+# define EAI_FAIL -4
+# define EAI_MEMORY -10
+# define EAI_SYSTEM -11
+
+const char *_async_netdb_strerror (int errcode);
+
+# define gai_strerror(errcode) _async_netdb_strerror (errcode)
+# endif
+
+# define _async_netdb_is_done(io) 1
+
+#endif
+
+/* In non-threaded mode, _async_name_from_addr_param is used in place of
+ async_name_from_addr. */
+struct _async_name_from_addr_param
+{
+ socklen_t addrlen;
+ async_netdb_sockaddr_storage_t addr;
+};
+
+typedef struct async_name_from_addr
+{
+ /*
+ Stupid memory trick, thwarted: The host string could be at the beginning
+ of this structure, and the memory block that contains this struct could
+ be resized and returned directly in async_name_from_addr_finish. But...
+
+ There is no aligned_realloc. In fact, aligned_realloc is a bit of a
+ problem, mostly because:
+ 1. realloc() is the only way to resize a heap-allocated memory block.
+ 2. realloc() moves memory.
+ 3. The location that realloc() moves memory to won't be aligned.
+ */
+
+ struct _async_name_from_addr_param param;
+ struct io_thread io;
+
+ char host[NI_MAXHOST];
+ int gai_error;
+ int errno_error;
+
+} *async_name_from_addr_t;
+
+async_name_from_addr_t async_name_from_addr_start (Display *dpy,
+ const struct sockaddr *addr,
+ socklen_t addrlen);
+/*
+ Starts an asynchronous name-from-address lookup.
+ dpy: An X11 Display with a .useThreads resource.
+ addr: An address. Like various socket functions (e.g. bind(2),
+ connect(2), sendto(2)), this isn't really a struct sockaddr so
+ much as a "subtype" of sockaddr, like sockaddr_in, or
+ sockaddr_in6, or whatever.
+ addrlen: The (actual) length of *addr.
+ Returns NULL if the request couldn't be created (due to low memory).
+ */
+
+#define async_name_from_addr_is_done(self) _async_netdb_is_done (&(self)->io)
+
+#if ASYNC_NETDB_USE_GAI
+void async_name_from_addr_cancel (async_name_from_addr_t self);
+#else
+# define async_name_from_addr_cancel(self) (free (self))
+#endif
+
+int async_name_from_addr_finish (async_name_from_addr_t self,
+ char **host, int *errno_error);
+/*
+ Gets the result of an asynchronous name-from-address lookup. If the lookup
+ operation is still in progress, or if the system can't do async lookups,
+ this will block. This cleans up the lookup operation; do not use 'self'
+ after calling this function.
+ self: The lookup operation.
+ host: If no error, the name of the host. Free this with free(3).
+ errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
+ Returns 0 on success, otherwise an error from getnameinfo(3).
+ */
+
+/* In non-threaded mode, async_addr_from_name contains different stuff. */
+typedef struct async_addr_from_name
+{
+#if ASYNC_NETDB_USE_GAI
+ struct io_thread io;
+
+ int gai_error;
+ int errno_error;
+
+ struct addrinfo *res;
+#else
+ char dont_complain_about_empty_structs;
+#endif
+} *async_addr_from_name_t;
+
+async_addr_from_name_t async_addr_from_name_start (Display *dpy,
+ const char *host);
+/*
+ Starts an asynchronous address-from-name lookup.
+ dpy: An X11 display.
+ host: The hostname to look up.
+ Returns NULL if the request couldn't be created (due to low memory).
+ */
+
+#define async_addr_from_name_is_done(self) _async_netdb_is_done (&(self)->io)
+
+#if ASYNC_NETDB_USE_GAI
+void async_addr_from_name_cancel (async_addr_from_name_t self);
+#else
+# define async_addr_from_name_cancel(self) (thread_free (self));
+#endif
+
+/* sockaddr must be sizeof(async_netdb_sockaddr_storage_t) in size. */
+int async_addr_from_name_finish (async_addr_from_name_t self, void *addr,
+ socklen_t *addrlen, int *errno_error);
+/*
+ Returns the address from an asynchronous address-from-name operation. If
+ the lookup is still in progress, or the system can't do an asynchronous
+ lookup, this blocks. This cleans up the lookup operation; do not use 'self'
+ after calling this function.
+ self: The lookup operation.
+ addr: A sockaddr. This must be as large as or larger than
+ sizeof(async_netdb_sockaddr_storage_t). (Hint: just use an
+ instance of async_netdb_sockaddr_storage_t itself here.)
+ addrlen: The length of the obtained sockaddr.
+ errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
+ Returns 0 on success, or an error from getaddrinfo(3).
+ */
+
+#endif
+
+/* Local Variables: */
+/* mode: c */
+/* fill-column: 78 */
+/* c-file-style: "gnu" */
+/* c-basic-offset: 2 */
+/* indent-tabs-mode: nil */
+/* End: */