From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[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 /* Without using union, gcc-6 warns for
57    breaking strict aliasing rules
58  */
59 typedef union {
60         struct sockaddr_storage x_sockaddr_storage;
61         struct sockaddr_in x_sockaddr_in;
62         struct sockaddr_in6 x_sockaddr_in6;
63 } async_netdb_sockaddr_storage_t;
64
65 int _async_netdb_is_done (struct io_thread *io);
66
67 #else
68
69 /* Because the definition for the above case is now union,
70    the definition for this case must also be union...
71 */
72 typedef union {
73         struct sockaddr_in x_sockaddr_in;
74 } async_netdb_sockaddr_storage_t;
75
76 # ifndef EAI_SYSTEM
77 /* The EAI_* codes are specified specifically as preprocessor macros, so
78    the #ifdef here should always work...
79    http://pubs.opengroup.org/onlinepubs/009604499/basedefs/netdb.h.html */
80
81 #   define ASYNC_NETDB_FAKE_EAI 1
82
83 /* Even without addrinfo, the EAI_* error codes are used. The numbers are from
84    Linux's netdb.h. */
85 #   define EAI_NONAME -2
86 #   define EAI_AGAIN  -3
87 #   define EAI_FAIL   -4
88 #   define EAI_MEMORY -10
89 #   define EAI_SYSTEM -11
90
91 const char *_async_netdb_strerror (int errcode);
92
93 #   define gai_strerror(errcode) _async_netdb_strerror (errcode)
94 # endif
95
96 # define _async_netdb_is_done(io) 1
97
98 #endif
99
100 /* In non-threaded mode, _async_name_from_addr_param is used in place of
101    async_name_from_addr. */
102 struct _async_name_from_addr_param
103 {
104   socklen_t addrlen;
105   async_netdb_sockaddr_storage_t addr;
106 };
107
108 typedef struct async_name_from_addr
109 {
110   /*
111      Stupid memory trick, thwarted: The host string could be at the beginning
112      of this structure, and the memory block that contains this struct could
113      be resized and returned directly in async_name_from_addr_finish. But...
114
115      There is no aligned_realloc. In fact, aligned_realloc is a bit of a
116      problem, mostly because:
117      1. realloc() is the only way to resize a heap-allocated memory block.
118      2. realloc() moves memory.
119      3. The location that realloc() moves memory to won't be aligned.
120    */
121
122   struct _async_name_from_addr_param param;
123   struct io_thread io;
124
125   char host[NI_MAXHOST];
126   int gai_error;
127   int errno_error;
128
129 } *async_name_from_addr_t;
130
131 async_name_from_addr_t async_name_from_addr_start (Display *dpy,
132                                                    const struct sockaddr *addr,
133                                                    socklen_t addrlen);
134 /*
135    Starts an asynchronous name-from-address lookup.
136    dpy:     An X11 Display with a .useThreads resource.
137    addr:    An address. Like various socket functions (e.g. bind(2),
138             connect(2), sendto(2)), this isn't really a struct sockaddr so
139             much as a "subtype" of sockaddr, like sockaddr_in, or
140             sockaddr_in6, or whatever.
141    addrlen: The (actual) length of *addr.
142    Returns NULL if the request couldn't be created (due to low memory).
143  */
144
145 #define async_name_from_addr_is_done(self) _async_netdb_is_done (&(self)->io)
146
147 #if ASYNC_NETDB_USE_GAI
148 void async_name_from_addr_cancel (async_name_from_addr_t self);
149 #else
150 # define async_name_from_addr_cancel(self) (free (self))
151 #endif
152
153 int async_name_from_addr_finish (async_name_from_addr_t self,
154                                  char **host, int *errno_error);
155 /*
156    Gets the result of an asynchronous name-from-address lookup. If the lookup
157    operation is still in progress, or if the system can't do async lookups,
158    this will block. This cleans up the lookup operation; do not use 'self'
159    after calling this function.
160    self:        The lookup operation.
161    host:        If no error, the name of the host. Free this with free(3).
162    errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
163    Returns 0 on success, otherwise an error from getnameinfo(3).
164  */
165
166 /* In non-threaded mode, async_addr_from_name contains different stuff. */
167 typedef struct async_addr_from_name
168 {
169 #if ASYNC_NETDB_USE_GAI
170   struct io_thread io;
171
172   int gai_error;
173   int errno_error;
174
175   struct addrinfo *res;
176 #else
177   char dont_complain_about_empty_structs;
178 #endif
179 } *async_addr_from_name_t;
180
181 async_addr_from_name_t async_addr_from_name_start (Display *dpy,
182                                                    const char *host);
183 /*
184    Starts an asynchronous address-from-name lookup.
185    dpy:  An X11 display.
186    host: The hostname to look up.
187    Returns NULL if the request couldn't be created (due to low memory).
188  */
189
190 #define async_addr_from_name_is_done(self) _async_netdb_is_done (&(self)->io)
191
192 #if ASYNC_NETDB_USE_GAI
193 void async_addr_from_name_cancel (async_addr_from_name_t self);
194 #else
195 # define async_addr_from_name_cancel(self) (thread_free (self));
196 #endif
197
198 /* sockaddr must be sizeof(async_netdb_sockaddr_storage_t) in size. */
199 int async_addr_from_name_finish (async_addr_from_name_t self, void *addr,
200                                  socklen_t *addrlen, int *errno_error);
201 /*
202    Returns the address from an asynchronous address-from-name operation. If
203    the lookup is still in progress, or the system can't do an asynchronous
204    lookup, this blocks. This cleans up the lookup operation; do not use 'self'
205    after calling this function.
206    self:        The lookup operation.
207    addr:        A sockaddr. This must be as large as or larger than
208                 sizeof(async_netdb_sockaddr_storage_t). (Hint: just use an
209                 instance of async_netdb_sockaddr_storage_t itself here.)
210    addrlen:     The length of the obtained sockaddr.
211    errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
212    Returns 0 on success, or an error from getaddrinfo(3).
213  */
214
215 #endif
216
217 /* Local Variables:      */
218 /* mode: c               */
219 /* fill-column: 78       */
220 /* c-file-style: "gnu"   */
221 /* c-basic-offset: 2     */
222 /* indent-tabs-mode: nil */
223 /* End:                  */