df6c59c63534081cb8925cea59e196a447505c67
[xscreensaver] / utils / async_netdb.h
1 /* vi: set tw=78: */
2
3 /* async_netdb.h, Copyright (c) Dave Odell <dmo2118@gmail.com>
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation.  No representations are made about the suitability of this
10  * software for any purpose.  It is provided "as is" without express or
11  * implied warranty.
12  */
13
14 #ifndef ASYNC_NETDB_H
15 #define ASYNC_NETDB_H
16
17 #include "thread_util.h"
18
19 #include <netdb.h>
20 #include <netinet/in.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23
24 /*
25    Both async_name_from_addr_* and async_addr_from_name_* follow basic pattern
26    for io_thread clients as described in thread_util.h:
27    1. async_*_from_*_start
28    2. async_*_from_*_is_done (repeat as necessary)
29    3a. async_*_from_*_finish to retrieve the results, or:
30    3b. async_*_from_*_cancel to abort the lookup.
31
32    On systems that can't do asynchronous host lookups, the *_finish functions
33    do the actual lookup.
34  */
35
36 #ifndef NI_MAXHOST
37 /*
38    From the glibc man page for getnameinfo(3):
39       Since glibc 2.8, these definitions are exposed only if one of the
40       feature test macros _BSD_SOURCE, _SVID_SOURCE, or _GNU_SOURCE is
41       defined.
42  */
43 # define NI_MAXHOST 1025
44 #endif
45
46 #if HAVE_PTHREAD && HAVE_GETADDRINFO
47 /*
48    If threads or getaddrinfo() are unavailable, then the older gethostbyname()
49    and gethostbyaddr() functions are used, and IPv6 is disabled.
50  */
51 # define ASYNC_NETDB_USE_GAI 1
52 #endif
53
54 #if ASYNC_NETDB_USE_GAI
55
56 typedef struct sockaddr_storage async_netdb_sockaddr_storage_t;
57
58 int _async_netdb_is_done (struct io_thread *io);
59
60 #else
61
62 typedef struct sockaddr_in async_netdb_sockaddr_storage_t;
63
64 # ifndef EAI_SYSTEM
65 /* The EAI_* codes are specified specifically as preprocessor macros, so
66    the #ifdef here should always work...
67    http://pubs.opengroup.org/onlinepubs/009604499/basedefs/netdb.h.html */
68
69 #   define ASYNC_NETDB_FAKE_EAI 1
70
71 /* Even without addrinfo, the EAI_* error codes are used. The numbers are from
72    Linux's netdb.h. */
73 #   define EAI_NONAME -2
74 #   define EAI_AGAIN  -3
75 #   define EAI_FAIL   -4
76 #   define EAI_MEMORY -10
77 #   define EAI_SYSTEM -11
78
79 const char *_async_netdb_strerror (int errcode);
80
81 #   define gai_strerror(errcode) _async_netdb_strerror (errcode)
82 # endif
83
84 # define _async_netdb_is_done(io) 1
85
86 #endif
87
88 /* In non-threaded mode, _async_name_from_addr_param is used in place of
89    async_name_from_addr. */
90 struct _async_name_from_addr_param
91 {
92   socklen_t addrlen;
93   async_netdb_sockaddr_storage_t addr;
94 };
95
96 typedef struct async_name_from_addr
97 {
98   /*
99      Stupid memory trick, thwarted: The host string could be at the beginning
100      of this structure, and the memory block that contains this struct could
101      be resized and returned directly in async_name_from_addr_finish. But...
102
103      There is no aligned_realloc. In fact, aligned_realloc is a bit of a
104      problem, mostly because:
105      1. realloc() is the only way to resize a heap-allocated memory block.
106      2. realloc() moves memory.
107      3. The location that realloc() moves memory to won't be aligned.
108    */
109
110   struct _async_name_from_addr_param param;
111   struct io_thread io;
112
113   char host[NI_MAXHOST];
114   int gai_error;
115   int errno_error;
116
117 } *async_name_from_addr_t;
118
119 async_name_from_addr_t async_name_from_addr_start (Display *dpy,
120                                                    const struct sockaddr *addr,
121                                                    socklen_t addrlen);
122 /*
123    Starts an asynchronous name-from-address lookup.
124    dpy:     An X11 Display with a .useThreads resource.
125    addr:    An address. Like various socket functions (e.g. bind(2),
126             connect(2), sendto(2)), this isn't really a struct sockaddr so
127             much as a "subtype" of sockaddr, like sockaddr_in, or
128             sockaddr_in6, or whatever.
129    addrlen: The (actual) length of *addr.
130    Returns NULL if the request couldn't be created (due to low memory).
131  */
132
133 #define async_name_from_addr_is_done(self) _async_netdb_is_done (&(self)->io)
134
135 #if ASYNC_NETDB_USE_GAI
136 void async_name_from_addr_cancel (async_name_from_addr_t self);
137 #else
138 # define async_name_from_addr_cancel(self) (free (self))
139 #endif
140
141 int async_name_from_addr_finish (async_name_from_addr_t self,
142                                  char **host, int *errno_error);
143 /*
144    Gets the result of an asynchronous name-from-address lookup. If the lookup
145    operation is still in progress, or if the system can't do async lookups,
146    this will block. This cleans up the lookup operation; do not use 'self'
147    after calling this function.
148    self:        The lookup operation.
149    host:        If no error, the name of the host. Free this with free(3).
150    errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
151    Returns 0 on success, otherwise an error from getnameinfo(3).
152  */
153
154 /* In non-threaded mode, async_addr_from_name contains different stuff. */
155 typedef struct async_addr_from_name
156 {
157 #if ASYNC_NETDB_USE_GAI
158   struct io_thread io;
159
160   int gai_error;
161   int errno_error;
162
163   struct addrinfo *res;
164 #else
165   char dont_complain_about_empty_structs;
166 #endif
167 } *async_addr_from_name_t;
168
169 async_addr_from_name_t async_addr_from_name_start (Display *dpy,
170                                                    const char *host);
171 /*
172    Starts an asynchronous address-from-name lookup.
173    dpy:  An X11 display.
174    host: The hostname to look up.
175    Returns NULL if the request couldn't be created (due to low memory).
176  */
177
178 #define async_addr_from_name_is_done(self) _async_netdb_is_done (&(self)->io)
179
180 #if ASYNC_NETDB_USE_GAI
181 void async_addr_from_name_cancel (async_addr_from_name_t self);
182 #else
183 # define async_addr_from_name_cancel(self) (thread_free (self));
184 #endif
185
186 /* sockaddr must be sizeof(async_netdb_sockaddr_storage_t) in size. */
187 int async_addr_from_name_finish (async_addr_from_name_t self, void *addr,
188                                  socklen_t *addrlen, int *errno_error);
189 /*
190    Returns the address from an asynchronous address-from-name operation. If
191    the lookup is still in progress, or the system can't do an asynchronous
192    lookup, this blocks. This cleans up the lookup operation; do not use 'self'
193    after calling this function.
194    self:        The lookup operation.
195    addr:        A sockaddr. This must be as large as or larger than
196                 sizeof(async_netdb_sockaddr_storage_t). (Hint: just use an
197                 instance of async_netdb_sockaddr_storage_t itself here.)
198    addrlen:     The length of the obtained sockaddr.
199    errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
200    Returns 0 on success, or an error from getaddrinfo(3).
201  */
202
203 #endif
204
205 /* Local Variables:      */
206 /* mode: c               */
207 /* fill-column: 78       */
208 /* c-file-style: "gnu"   */
209 /* c-basic-offset: 2     */
210 /* indent-tabs-mode: nil */
211 /* End:                  */