/* 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: */