spiped 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/ext/spiped/extconf.rb +3 -0
  3. data/ext/spiped/spiped-source/BUILDING +46 -0
  4. data/ext/spiped/spiped-source/CHANGELOG +44 -0
  5. data/ext/spiped/spiped-source/COPYRIGHT +33 -0
  6. data/ext/spiped/spiped-source/Makefile +47 -0
  7. data/ext/spiped/spiped-source/Makefile.POSIX +27 -0
  8. data/ext/spiped/spiped-source/Makefile.inc +20 -0
  9. data/ext/spiped/spiped-source/Makefile.prog +23 -0
  10. data/ext/spiped/spiped-source/POSIX/README +10 -0
  11. data/ext/spiped/spiped-source/POSIX/posix-cflags.sh +10 -0
  12. data/ext/spiped/spiped-source/POSIX/posix-clock_realtime.c +3 -0
  13. data/ext/spiped/spiped-source/POSIX/posix-l.c +1 -0
  14. data/ext/spiped/spiped-source/POSIX/posix-l.sh +14 -0
  15. data/ext/spiped/spiped-source/POSIX/posix-msg_nosignal.c +3 -0
  16. data/ext/spiped/spiped-source/README +198 -0
  17. data/ext/spiped/spiped-source/STYLE +151 -0
  18. data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.c +464 -0
  19. data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.h +45 -0
  20. data/ext/spiped/spiped-source/libcperciva/alg/sha256.c +442 -0
  21. data/ext/spiped/spiped-source/libcperciva/alg/sha256.h +95 -0
  22. data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-AESNI.c +13 -0
  23. data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-CPUID.c +8 -0
  24. data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport.sh +37 -0
  25. data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport.h +63 -0
  26. data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport_x86_aesni.c +30 -0
  27. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.c +166 -0
  28. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.h +31 -0
  29. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.c +229 -0
  30. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.h +31 -0
  31. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.c +124 -0
  32. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.h +41 -0
  33. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.c +293 -0
  34. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.h +43 -0
  35. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.c +46 -0
  36. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.h +9 -0
  37. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.c +215 -0
  38. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.h +14 -0
  39. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.c +21 -0
  40. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.h +14 -0
  41. data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.c +276 -0
  42. data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.h +167 -0
  43. data/ext/spiped/spiped-source/libcperciva/datastruct/mpool.h +85 -0
  44. data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.c +334 -0
  45. data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.h +89 -0
  46. data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.c +241 -0
  47. data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.h +60 -0
  48. data/ext/spiped/spiped-source/libcperciva/events/events.c +203 -0
  49. data/ext/spiped/spiped-source/libcperciva/events/events.h +106 -0
  50. data/ext/spiped/spiped-source/libcperciva/events/events_immediate.c +149 -0
  51. data/ext/spiped/spiped-source/libcperciva/events/events_internal.h +95 -0
  52. data/ext/spiped/spiped-source/libcperciva/events/events_network.c +347 -0
  53. data/ext/spiped/spiped-source/libcperciva/events/events_network_selectstats.c +106 -0
  54. data/ext/spiped/spiped-source/libcperciva/events/events_timer.c +273 -0
  55. data/ext/spiped/spiped-source/libcperciva/network/network.h +95 -0
  56. data/ext/spiped/spiped-source/libcperciva/network/network_accept.c +103 -0
  57. data/ext/spiped/spiped-source/libcperciva/network/network_connect.c +258 -0
  58. data/ext/spiped/spiped-source/libcperciva/network/network_read.c +155 -0
  59. data/ext/spiped/spiped-source/libcperciva/network/network_write.c +188 -0
  60. data/ext/spiped/spiped-source/libcperciva/util/asprintf.c +49 -0
  61. data/ext/spiped/spiped-source/libcperciva/util/asprintf.h +16 -0
  62. data/ext/spiped/spiped-source/libcperciva/util/daemonize.c +134 -0
  63. data/ext/spiped/spiped-source/libcperciva/util/daemonize.h +10 -0
  64. data/ext/spiped/spiped-source/libcperciva/util/entropy.c +76 -0
  65. data/ext/spiped/spiped-source/libcperciva/util/entropy.h +13 -0
  66. data/ext/spiped/spiped-source/libcperciva/util/imalloc.h +33 -0
  67. data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.c +19 -0
  68. data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.h +33 -0
  69. data/ext/spiped/spiped-source/libcperciva/util/monoclock.c +52 -0
  70. data/ext/spiped/spiped-source/libcperciva/util/monoclock.h +14 -0
  71. data/ext/spiped/spiped-source/libcperciva/util/noeintr.c +54 -0
  72. data/ext/spiped/spiped-source/libcperciva/util/noeintr.h +14 -0
  73. data/ext/spiped/spiped-source/libcperciva/util/sock.c +472 -0
  74. data/ext/spiped/spiped-source/libcperciva/util/sock.h +56 -0
  75. data/ext/spiped/spiped-source/libcperciva/util/sock_internal.h +14 -0
  76. data/ext/spiped/spiped-source/libcperciva/util/sock_util.c +271 -0
  77. data/ext/spiped/spiped-source/libcperciva/util/sock_util.h +51 -0
  78. data/ext/spiped/spiped-source/libcperciva/util/sysendian.h +146 -0
  79. data/ext/spiped/spiped-source/libcperciva/util/warnp.c +76 -0
  80. data/ext/spiped/spiped-source/libcperciva/util/warnp.h +59 -0
  81. data/ext/spiped/spiped-source/proto/proto_conn.c +362 -0
  82. data/ext/spiped/spiped-source/proto/proto_conn.h +25 -0
  83. data/ext/spiped/spiped-source/proto/proto_crypt.c +396 -0
  84. data/ext/spiped/spiped-source/proto/proto_crypt.h +102 -0
  85. data/ext/spiped/spiped-source/proto/proto_handshake.c +330 -0
  86. data/ext/spiped/spiped-source/proto/proto_handshake.h +30 -0
  87. data/ext/spiped/spiped-source/proto/proto_pipe.c +202 -0
  88. data/ext/spiped/spiped-source/proto/proto_pipe.h +23 -0
  89. data/ext/spiped/spiped-source/spipe/Makefile +90 -0
  90. data/ext/spiped/spiped-source/spipe/README +24 -0
  91. data/ext/spiped/spiped-source/spipe/main.c +178 -0
  92. data/ext/spiped/spiped-source/spipe/pushbits.c +101 -0
  93. data/ext/spiped/spiped-source/spipe/pushbits.h +10 -0
  94. data/ext/spiped/spiped-source/spipe/spipe.1 +60 -0
  95. data/ext/spiped/spiped-source/spiped/Makefile +98 -0
  96. data/ext/spiped/spiped-source/spiped/README +62 -0
  97. data/ext/spiped/spiped-source/spiped/dispatch.c +214 -0
  98. data/ext/spiped/spiped-source/spiped/dispatch.h +27 -0
  99. data/ext/spiped/spiped-source/spiped/main.c +267 -0
  100. data/ext/spiped/spiped-source/spiped/spiped.1 +112 -0
  101. data/lib/spiped.rb +3 -0
  102. metadata +143 -0
@@ -0,0 +1,151 @@
1
+ Code style
2
+ ==========
3
+
4
+ In general, FreeBSD style(9) should be followed unless it is irrelevant
5
+ (e.g., $FreeBSD$ tags).
6
+
7
+ Functions with external linkage are declared like this:
8
+ /**
9
+ * module_func(arg1, arg2):
10
+ * Description of what the function does, referring to arguments as
11
+ * ${arg1} or suchlike.
12
+ */
13
+ int module_func(void *, int);
14
+
15
+ The identical comment appears in the C file where the function is defined.
16
+
17
+ Static functions may have the above form of comment, or simply a
18
+ /* Brief description of what the function does. */
19
+ line before the function.
20
+
21
+ In general, functions should return (int)(-1) or NULL to indicate error.
22
+
23
+ Errors should be printed via warnp (if errno is relevant) or warn0 (if errno
24
+ is not relevant) when they are first detected and also at higher levels where
25
+ useful. As an exception to this, malloc failures (i.e., errno = ENOMEM) can
26
+ result in failure being passed back up the call chain without being printed
27
+ immediately. (Naturally, other errors can be passed back where a function
28
+ definition so specifies; e.g., ENOENT in cases where a file not existing is
29
+ not erronous.)
30
+
31
+ The first statement in main(), after variable declarations, should be
32
+ "WARNP_INIT;" in order to set the program name used for printing warnings.
33
+
34
+ In general, functions should be structured with one return statement per
35
+ status, e.g., one return() for success and one return() for failure. Errors
36
+ should be handled by using goto to enter the error return path, e.g.,
37
+ int
38
+ foo(int bar)
39
+ {
40
+
41
+ if (something fails)
42
+ goto err0;
43
+ /* ... */
44
+ if (something else fails)
45
+ goto err1;
46
+ /* ... */
47
+ if (yet another operation fails)
48
+ goto err2;
49
+
50
+ /* Success! */
51
+ return (0);
52
+
53
+ err2:
54
+ /* Clean up something. */
55
+ err1:
56
+ /* Clean up something else. */
57
+ err0:
58
+ /* Failure! */
59
+ return (-1);
60
+ }
61
+
62
+ As an exception to the above, if there is only one way for the function to
63
+ fail, the idioms
64
+ return (baz(bar));
65
+ and
66
+ int rc;
67
+
68
+ rc = baz(bar);
69
+ /* ... cleanup code here ... */
70
+ return (rc);
71
+ are allowed; furthermore, in cases such as foo_free(), the idiom
72
+ if (we shouldn't do anything)
73
+ return;
74
+ is preferred over
75
+ if (we shouldn't do anything)
76
+ goto done;
77
+ at the start of a function.
78
+
79
+ Headers should be included in the following groups, with a blank line after
80
+ each (non-empty) group:
81
+ 1. <sys/*.h>, with <sys/types.h> first followed by others alphabetically.
82
+ 2. <net/*.h>, in alphabetical order.
83
+ 3. <*.h>, in alphabetical order.
84
+ 4. header files from /lib/, in alphabetical order.
85
+ 5. header files from the program being built, in alphabetical order.
86
+ 6. header files (usually just one) defining the interface for this C file.
87
+
88
+ If ssize_t is needed, <unistd.h> should be included to provide it.
89
+
90
+ If size_t is needed, <stddef.h> should be included to provide it unless
91
+ <stdio.h>, <stdlib.h>, <string.h>, or <unistd.h> is already required.
92
+
93
+ If the C99 integer types (uint8_t, int64_t, etc.) are required, <stdint.h>
94
+ should be included to provide them unless <inttypes.h> is already required.
95
+
96
+ The type 'char' should only be used to represent human-readable characters
97
+ (input from users, output to users, pathnames, et cetera). The type
98
+ 'char *' should normally be a NUL-terminated string. The types 'signed
99
+ char' and 'unsigned char' should never be used; C99 integer types should
100
+ be used instead.
101
+
102
+ When a variable is declared to have a pointer type, there should be a space
103
+ between the '*' and the variable name, e.g.,
104
+ int
105
+ main(int argc, char * argv[])
106
+ {
107
+ char * opt_p = NULL;
108
+ Note that this is inconsistent with FreeBSD style(9). When used as a unary
109
+ operator, '*' is not separated from its argument, e.g.,
110
+ while (*p != '\0')
111
+ p++;
112
+
113
+ When a struct is referenced, the idiom
114
+ /* Opaque types. */
115
+ struct foo;
116
+
117
+ struct bar * bar_from_foo(struct foo *);
118
+ is preferable to
119
+ #include "foo.h" /* needed for struct foo */
120
+
121
+ struct bar * bar_from_foo(struct foo *);
122
+ unless there is some reason why the internal layout of struct foo is needed
123
+ (e.g., if struct bar contains a struct foo rather than a struct foo *). Such
124
+ struct declarations should be sorted alphabetically.
125
+
126
+ The file foo.c should only export symbols of the following forms:
127
+ foo_* -- most symbols should be of this form.
128
+ FOO_* / BAR_FOO_*
129
+ -- allowed in cases where FOO or BAR_FOO is idiomatic (e.g.,
130
+ MD5, HMAC_SHA256).
131
+ foo() / defoo() / unfoo()
132
+ -- where "foo" is a verb and this improves code clarity.
133
+
134
+ Functions named foo_free should return void, and foo_free(NULL) should have
135
+ no effect.
136
+
137
+ If static variables need to be initialized to 0 (or NULL) then they should be
138
+ explicitly declared that way; implicit initialization should not be used.
139
+
140
+ In non-trivial code, comments should be included which describe in English
141
+ what is being done by the surrounding code with sufficient detail that if the
142
+ code were removed, it could be replaced based on reading the comments without
143
+ requiring any significant creativity.
144
+
145
+ Comments and documentation should be written in en-GB-oed; i.e., with
146
+ the 'u' included in words such as "honour", "colour", and "neighbour",
147
+ and the ending '-ize' in words such as "organize" and "realize". The
148
+ Oxford (aka. serial) comma should be used in lists. Quotation marks
149
+ should be placed logically, i.e., not including punctuation marks which
150
+ do not form a logical part of the quoted text. Two spaces should be used
151
+ after a period which ends a sentence.
@@ -0,0 +1,464 @@
1
+ #include <sys/socket.h>
2
+
3
+ #include <errno.h>
4
+ #include <pthread.h>
5
+ #include <stdint.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <unistd.h>
9
+
10
+ #include "events.h"
11
+ #include "noeintr.h"
12
+ #include "sock.h"
13
+ #include "warnp.h"
14
+
15
+ #include "dnsthread.h"
16
+
17
+ /* Thread management structure. */
18
+ struct dnsthread_internal {
19
+ /* Threading glue. */
20
+ pthread_t thr; /* Thread ID. */
21
+ pthread_mutex_t mtx; /* Controls access to this structure. */
22
+ pthread_cond_t cv; /* Thread sleeps on this. */
23
+
24
+ /* State management. */
25
+ int state; /* THREAD_* as below. */
26
+ int wakeupsock[2]; /* Writes to [0], reads from [1]. */
27
+
28
+ /* Address resolution variables. */
29
+ char * addr; /* Address to be resolved. */
30
+ struct sock_addr ** sas; /* Results. */
31
+ int res_errno; /* Errno to be passed back on failure. */
32
+
33
+ /* Callback to occur when resolution is complete. */
34
+ int (*callback)(void *, struct sock_addr **); /* Callback. */
35
+ void * cookie; /* Cookie. */
36
+ };
37
+
38
+ /* Cookie used by dnsthread_resolve. */
39
+ struct resolve_cookie {
40
+ int (*callback)(void *, struct sock_addr **);
41
+ void * cookie;
42
+ DNSTHREAD T;
43
+ };
44
+
45
+ /*
46
+ * Thread states. _resolveone moves the thread from SLEEPING to HASWORK;
47
+ * workthread moves the thread from HASWORK to SLEEPING; and _kill moves the
48
+ * thread from either state to SUICIDE.
49
+ */
50
+ #define THREAD_SLEEPING 0
51
+ #define THREAD_HASWORK 1
52
+ #define THREAD_SUICIDE 2
53
+
54
+ /* Callback functions used below. */
55
+ static int callback_resolveone(void * cookie);
56
+ static int callback_resolve(void *, struct sock_addr **);
57
+
58
+ /* Address resolution thread. */
59
+ static void *
60
+ workthread(void * cookie)
61
+ {
62
+ struct dnsthread_internal * T = cookie;
63
+ char * addr;
64
+ struct sock_addr ** sas;
65
+ int res_errno = 0;
66
+ int rc;
67
+ uint8_t zero = 0;
68
+
69
+ /* Grab the mutex. */
70
+ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) {
71
+ warn0("pthread_mutex_lock: %s", strerror(rc));
72
+ exit(1);
73
+ }
74
+
75
+ /* Infinite loop doing work until told to suicide. */
76
+ do {
77
+ /*
78
+ * Sleep on the condition variable as long as we're in the
79
+ * SLEEPING state.
80
+ */
81
+ while (T->state == THREAD_SLEEPING) {
82
+ /* Sleep until we're woken up. */
83
+ if ((rc = pthread_cond_wait(&T->cv, &T->mtx)) != 0) {
84
+ warn0("pthread_cond_wait: %s", strerror(rc));
85
+ exit(1);
86
+ }
87
+ }
88
+
89
+ /* If we need to kill ourself, stop looping. */
90
+ if (T->state == THREAD_SUICIDE)
91
+ break;
92
+
93
+ /* Grab the work. */
94
+ addr = T->addr;
95
+
96
+ /* Release the mutex. */
97
+ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) {
98
+ warn0("pthread_mutex_unlock: %s", strerror(rc));
99
+ exit(1);
100
+ }
101
+
102
+ /* Perform the address resolution. */
103
+ if ((sas = sock_resolve(addr)) == NULL)
104
+ res_errno = errno;
105
+
106
+ /* Grab the mutex again. */
107
+ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) {
108
+ warn0("pthread_mutex_lock: %s", strerror(rc));
109
+ exit(1);
110
+ }
111
+
112
+ /* Write the answer back. */
113
+ T->sas = sas;
114
+ T->res_errno = res_errno;
115
+
116
+ /* Send a completion message. */
117
+ if (noeintr_write(T->wakeupsock[0], &zero, 1) != 1) {
118
+ warnp("Error writing to wakeup socket");
119
+ exit(1);
120
+ }
121
+
122
+ /* Return to sleeping, unless we were instructed to die. */
123
+ if (T->state != THREAD_SUICIDE)
124
+ T->state = THREAD_SLEEPING;
125
+ } while (1);
126
+
127
+ /* Close the socket pair. */
128
+ close(T->wakeupsock[1]);
129
+ close(T->wakeupsock[0]);
130
+
131
+ /* Destroy the condition variable. */
132
+ if ((rc = pthread_cond_destroy(&T->cv)) != 0) {
133
+ warn0("pthread_cond_destroy: %s", strerror(rc));
134
+ exit(1);
135
+ }
136
+
137
+ /* Release the mutex. */
138
+ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) {
139
+ warn0("pthread_mutex_unlock: %s", strerror(rc));
140
+ exit(1);
141
+ }
142
+
143
+ /* Destroy the mutex. */
144
+ if ((rc = pthread_mutex_destroy(&T->mtx)) != 0) {
145
+ warn0("pthread_mutex_destroy: %s", strerror(rc));
146
+ exit(1);
147
+ }
148
+
149
+ /* Free the control structure. */
150
+ free(T);
151
+
152
+ /* Successful thread termination. */
153
+ return (NULL);
154
+ }
155
+
156
+ /**
157
+ * dnsthread_spawn(void):
158
+ * Spawn a thread for performing address resolution. Return a token which can
159
+ * be passed to dnsthread_resolveone and dnsthread_kill.
160
+ */
161
+ DNSTHREAD
162
+ dnsthread_spawn(void)
163
+ {
164
+ struct dnsthread_internal * T;
165
+ int rc;
166
+
167
+ /* Allocate a thread management structure. */
168
+ if ((T = malloc(sizeof(struct dnsthread_internal))) == NULL)
169
+ goto err0;
170
+
171
+ /* Create and lock a mutex. */
172
+ if ((rc = pthread_mutex_init(&T->mtx, NULL)) != 0) {
173
+ warn0("pthread_mutex_init: %s", strerror(rc));
174
+ goto err1;
175
+ }
176
+ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) {
177
+ warn0("pthread_mutex_lock: %s", strerror(rc));
178
+ goto err2;
179
+ }
180
+
181
+ /* Create state-changed condition variable. */
182
+ if ((rc = pthread_cond_init(&T->cv, NULL)) != 0) {
183
+ warn0("pthread_cond_init: %s", strerror(rc));
184
+ goto err3;
185
+ }
186
+
187
+ /* Create wakeup socketpair. */
188
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, T->wakeupsock)) {
189
+ warnp("socketpair");
190
+ goto err4;
191
+ }
192
+
193
+ /* The thread starts out sleeping. */
194
+ T->state = THREAD_SLEEPING;
195
+
196
+ /* Create the thread. */
197
+ if ((rc = pthread_create(&T->thr, NULL, workthread, T)) != 0) {
198
+ warn0("pthread_create: %s", strerror(rc));
199
+ goto err5;
200
+ }
201
+
202
+ /* Unlock the mutex. */
203
+ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) {
204
+ warn0("pthread_mutex_unlock: %s", strerror(rc));
205
+ goto err0;
206
+ }
207
+
208
+ /* Success! */
209
+ return (T);
210
+
211
+ err5:
212
+ close(T->wakeupsock[1]);
213
+ close(T->wakeupsock[0]);
214
+ err4:
215
+ pthread_cond_destroy(&T->cv);
216
+ err3:
217
+ pthread_mutex_unlock(&T->mtx);
218
+ err2:
219
+ pthread_mutex_destroy(&T->mtx);
220
+ err1:
221
+ free(T);
222
+ err0:
223
+ /* Failure! */
224
+ return (NULL);
225
+ }
226
+
227
+ /**
228
+ * dnsthread_resolveone(T, addr, callback, cookie):
229
+ * Using the thread for which ${T} was returned by dnsthread_spawn, resolve
230
+ * the address ${addr}, which must be in one of the forms accepted by the
231
+ * sock_resolve function. If ${T} is already resolving an address, do not
232
+ * resolve this address and instead return with errno == EALREADY. Upon
233
+ * completion, invoke ${callback}(${cookie}, sas), where ${sas} is a
234
+ * NULL-terminated array of pointers to sock_addr structures or NULL on
235
+ * resolution failure.
236
+ */
237
+ int
238
+ dnsthread_resolveone(DNSTHREAD T, const char * addr,
239
+ int (* callback)(void *, struct sock_addr **), void * cookie)
240
+ {
241
+ int err = 0;
242
+ int rc;
243
+
244
+ /* Grab the mutex. */
245
+ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) {
246
+ warn0("pthread_mutex_lock: %s", strerror(rc));
247
+ goto err0;
248
+ }
249
+
250
+ /* If the resolver is already busy, fail. */
251
+ if (T->state == THREAD_HASWORK) {
252
+ err = EALREADY;
253
+ goto ealready;
254
+ }
255
+
256
+ /* Duplicate the address to be resolved. */
257
+ if ((T->addr = strdup(addr)) == NULL)
258
+ goto err1;
259
+
260
+ /* Remember what callback we'll need to do eventually. */
261
+ T->callback = callback;
262
+ T->cookie = cookie;
263
+
264
+ /* There is now work for the thread to do. */
265
+ T->state = THREAD_HASWORK;
266
+
267
+ /* Wake up the worker thread. */
268
+ if ((rc = pthread_cond_signal(&T->cv)) != 0) {
269
+ warn0("pthread_cond_signal: %s", strerror(rc));
270
+ goto err1;
271
+ }
272
+
273
+ /* We want a callback when the worker thread pokes us. */
274
+ if (events_network_register(callback_resolveone, T, T->wakeupsock[1],
275
+ EVENTS_NETWORK_OP_READ)) {
276
+ warnp("Error registering wakeup listener");
277
+ goto err1;
278
+ }
279
+
280
+ ealready:
281
+ /* Release the mutex. */
282
+ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) {
283
+ warn0("pthread_mutex_unlock: %s", strerror(rc));
284
+ goto err0;
285
+ }
286
+
287
+ /* If err was set earlier, store the value in errno. */
288
+ if (err)
289
+ errno = err;
290
+
291
+ /* Success! */
292
+ return (0);
293
+
294
+ err1:
295
+ pthread_mutex_unlock(&T->mtx);
296
+ err0:
297
+ /* Failure! */
298
+ return (-1);
299
+ }
300
+
301
+ /* Callback for dnsthread_resolveone, from wakeup socket. */
302
+ static int
303
+ callback_resolveone(void * cookie)
304
+ {
305
+ struct dnsthread_internal * T = cookie;
306
+ struct sock_addr ** sas;
307
+ uint8_t zero;
308
+ int res_errno = 0;
309
+ int (*callback)(void *, struct sock_addr **);
310
+ void * cb_cookie;
311
+ int rc;
312
+
313
+ /* Drain the byte from the socketpair. */
314
+ if (read(T->wakeupsock[1], &zero, 1) != 1) {
315
+ warn0("Error reading from wakeup socket");
316
+ goto err0;
317
+ }
318
+
319
+ /* Grab the mutex. */
320
+ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) {
321
+ warn0("pthread_mutex_lock: %s", strerror(rc));
322
+ goto err0;
323
+ }
324
+
325
+ /* Free the (strduped) address which was to be resolved. */
326
+ free(T->addr);
327
+
328
+ /* Grab the result. */
329
+ sas = T->sas;
330
+ res_errno = T->res_errno;
331
+
332
+ /* Grab the callback. */
333
+ callback = T->callback;
334
+ cb_cookie = T->cookie;
335
+
336
+ /* Release the mutex. */
337
+ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) {
338
+ warn0("pthread_mutex_unlock: %s", strerror(rc));
339
+ goto err0;
340
+ }
341
+
342
+ /* Perform the callback. */
343
+ if (sas == NULL)
344
+ errno = res_errno;
345
+ return ((callback)(cb_cookie, sas));
346
+
347
+ err0:
348
+ /* Failure! */
349
+ return (-1);
350
+ }
351
+
352
+ /**
353
+ * dnsthread_kill(T):
354
+ * Instruct an address resolution thread to die. If the thread does not have
355
+ * an address resolution operation currently pending, wait for the thread to
356
+ * die before returning.
357
+ */
358
+ int
359
+ dnsthread_kill(DNSTHREAD T)
360
+ {
361
+ int rc;
362
+ int ostate;
363
+ pthread_t thr;
364
+
365
+ /* Lock the control structure. */
366
+ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) {
367
+ warn0("pthread_mutex_lock: %s", strerror(rc));
368
+ goto err0;
369
+ }
370
+
371
+ /* Remember what state the thread is currently in. */
372
+ ostate = T->state;
373
+
374
+ /* Grab the thread ID. */
375
+ thr = T->thr;
376
+
377
+ /* Tell the thread to die, and wake it up. */
378
+ T->state = THREAD_SUICIDE;
379
+ if ((rc = pthread_cond_signal(&T->cv)) != 0) {
380
+ warn0("pthread_cond_signal: %s", strerror(rc));
381
+ goto err1;
382
+ }
383
+
384
+ /* Unlock the control structure. */
385
+ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) {
386
+ warn0("pthread_mutex_unlock: %s", strerror(rc));
387
+ goto err0;
388
+ }
389
+
390
+ /* If the thread was sleeping, wait for it to wake up and die. */
391
+ if (ostate == THREAD_SLEEPING) {
392
+ if ((rc = pthread_join(thr, NULL)) != 0) {
393
+ warn0("pthread_join: %s", strerror(rc));
394
+ goto err0;
395
+ }
396
+ }
397
+
398
+ /* Success! */
399
+ return (0);
400
+
401
+ err1:
402
+ pthread_mutex_unlock(&T->mtx);
403
+ err0:
404
+ /* Failure! */
405
+ return (-1);
406
+ }
407
+
408
+ /**
409
+ * dnsthread_resolve(addr, callback, cookie):
410
+ * Perform a non-blocking address resolution of ${addr}. This function may
411
+ * spawn a thread internally.
412
+ */
413
+ int
414
+ dnsthread_resolve(const char * addr,
415
+ int (* callback)(void *, struct sock_addr **), void * cookie)
416
+ {
417
+ struct resolve_cookie * R;
418
+
419
+ /* Bake a cookie. */
420
+ if ((R = malloc(sizeof(struct resolve_cookie))) == NULL)
421
+ goto err0;
422
+ R->callback = callback;
423
+ R->cookie = cookie;
424
+
425
+ /* Spawn a thread. */
426
+ if ((R->T = dnsthread_spawn()) == NULL)
427
+ goto err1;
428
+
429
+ /* Launch the request. */
430
+ if (dnsthread_resolveone(R->T, addr, callback_resolve, R))
431
+ goto err2;
432
+
433
+ /* Success! */
434
+ return (0);
435
+
436
+ err2:
437
+ dnsthread_kill(R->T);
438
+ err1:
439
+ free(R);
440
+ err0:
441
+ /* Failure! */
442
+ return (-1);
443
+ }
444
+
445
+ /* Callback for dnsthread_resolve, from dnsthread_resolveone. */
446
+ static int
447
+ callback_resolve(void * cookie, struct sock_addr ** sas)
448
+ {
449
+ struct resolve_cookie * R = cookie;
450
+ int rc;
451
+
452
+ /* Invoke the upstream callback. */
453
+ rc = (R->callback)(R->cookie, sas);
454
+
455
+ /* Kill the resolver thread. */
456
+ if (dnsthread_kill(R->T))
457
+ rc = -1;
458
+
459
+ /* Free our cookie. */
460
+ free(R);
461
+
462
+ /* Return upstream return code or failure. */
463
+ return (rc);
464
+ }