X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=utils%2Fasync_netdb.h;fp=utils%2Fasync_netdb.h;h=df6c59c63534081cb8925cea59e196a447505c67;hp=0000000000000000000000000000000000000000;hb=d5186197bc394e10a4402f7f6d23fbb14103bc50;hpb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e diff --git a/utils/async_netdb.h b/utils/async_netdb.h new file mode 100644 index 00000000..df6c59c6 --- /dev/null +++ b/utils/async_netdb.h @@ -0,0 +1,211 @@ +/* vi: set tw=78: */ + +/* async_netdb.h, Copyright (c) Dave Odell + * + * 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 +#include +#include +#include + +/* + 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 + +typedef struct sockaddr_storage async_netdb_sockaddr_storage_t; + +int _async_netdb_is_done (struct io_thread *io); + +#else + +typedef struct 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: */