4 #define _DARWIN_C_SOURCE
11 #include <sys/select.h>
18 #include "allocator_thread.h"
23 #include "remotedns.h"
25 /* stuff for our internal translation table */
35 string_hash_tuple
** list
;
36 } internal_ip_lookup_table
;
38 static void *dumpstring(char* s
, size_t len
) {
39 char* p
= malloc(len
);
40 if(p
) memcpy(p
, s
, len
);
44 static pthread_mutex_t
*internal_ips_lock
;
45 static internal_ip_lookup_table
*internal_ips
;
47 uint32_t index_from_internal_ip(ip_type4 internalip
) {
49 ip_type4 tmp
= internalip
;
51 ret
= tmp
.octet
[3] + (tmp
.octet
[2] << 8) + (tmp
.octet
[1] << 16);
56 char *string_from_internal_ip(ip_type4 internalip
) {
59 uint32_t index
= index_from_internal_ip(internalip
);
60 if(index
< internal_ips
->counter
)
61 res
= internal_ips
->list
[index
]->string
;
65 extern unsigned int remote_dns_subnet
;
66 ip_type4
make_internal_ip(uint32_t index
) {
68 index
++; // so we can start at .0.0.1
71 ret
.octet
[0] = remote_dns_subnet
& 0xFF;
72 ret
.octet
[1] = (index
& 0xFF0000) >> 16;
73 ret
.octet
[2] = (index
& 0xFF00) >> 8;
74 ret
.octet
[3] = index
& 0xFF;
78 static ip_type4
ip_from_internal_list(char* name
, size_t len
) {
79 uint32_t hash
= dalias_hash((char *) name
);
83 // see if we already have this dns entry saved.
84 if(internal_ips
->counter
) {
85 for(i
= 0; i
< internal_ips
->counter
; i
++) {
86 if(internal_ips
->list
[i
]->hash
== hash
&& !strcmp(name
, internal_ips
->list
[i
]->string
)) {
87 res
= make_internal_ip(i
);
88 PDEBUG("got cached ip for %s\n", name
);
93 // grow list if needed.
94 if(internal_ips
->capa
< internal_ips
->counter
+ 1) {
96 new_mem
= realloc(internal_ips
->list
, (internal_ips
->capa
+ 16) * sizeof(void *));
98 internal_ips
->capa
+= 16;
99 internal_ips
->list
= new_mem
;
102 PDEBUG("out of mem\n");
103 goto err_plus_unlock
;
107 res
= make_internal_ip(internal_ips
->counter
);
108 if(res
.as_int
== IPT4_INVALID
.as_int
)
109 goto err_plus_unlock
;
111 string_hash_tuple tmp
= { 0 };
112 new_mem
= dumpstring((char*) &tmp
, sizeof(string_hash_tuple
));
116 PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips
->counter
, name
);
118 internal_ips
->list
[internal_ips
->counter
] = new_mem
;
119 internal_ips
->list
[internal_ips
->counter
]->hash
= hash
;
121 new_mem
= dumpstring((char*) name
, len
);
124 internal_ips
->list
[internal_ips
->counter
] = 0;
127 internal_ips
->list
[internal_ips
->counter
]->string
= new_mem
;
129 internal_ips
->counter
+= 1;
136 PDEBUG("return err\n");
140 /* stuff for communication with the allocator thread */
148 static pthread_t allocator_thread
;
152 static int wait_data(int readfd
) {
156 FD_SET(readfd
, &fds
);
158 while((ret
= select(readfd
+1, &fds
, NULL
, NULL
, NULL
)) <= 0) {
161 if(e
== EINTR
) continue;
164 char* x
= strerror_r(errno
, emsg
, sizeof emsg
);
165 dprintf(2, "select2: %s\n", x
);
173 static int trywrite(int fd
, void* buf
, size_t bytes
) {
175 unsigned char *out
= buf
;
177 ret
= write(fd
, out
, bytes
);
180 if(errno
== EINTR
) goto again
;
184 if(ret
== bytes
|| !bytes
) return 1;
191 static int sendmessage(enum at_direction dir
, struct at_msg
*msg
) {
192 static int* destfd
[ATD_MAX
] = { [ATD_SERVER
] = &req_pipefd
[1], [ATD_CLIENT
] = &resp_pipefd
[1] };
193 assert(msg
->h
.datalen
<= MSG_LEN_MAX
);
194 int ret
= trywrite(*destfd
[dir
], msg
, sizeof (msg
->h
)+msg
->h
.datalen
);
195 assert(msg
->h
.datalen
<= MSG_LEN_MAX
);
199 static int tryread(int fd
, void* buf
, size_t bytes
) {
201 unsigned char *out
= buf
;
203 ret
= read(fd
, out
, bytes
);
206 if(errno
== EINTR
) goto again
;
210 if(ret
== bytes
|| !bytes
) return 1;
216 static int readmsg(int fd
, struct at_msg
*msg
) {
217 int ret
= tryread(fd
, msg
, sizeof(msg
->h
));
218 if(ret
!= 1) return ret
;
219 return tryread(fd
, &msg
->m
, msg
->h
.datalen
);
222 static int getmessage(enum at_direction dir
, struct at_msg
*msg
) {
223 static int* readfd
[ATD_MAX
] = { [ATD_SERVER
] = &req_pipefd
[0], [ATD_CLIENT
] = &resp_pipefd
[0] };
225 if((ret
= wait_data(*readfd
[dir
]))) {
226 if(!readmsg(*readfd
[dir
], msg
))
228 assert(msg
->h
.datalen
<= MSG_LEN_MAX
);
233 static void* threadfunc(void* x
) {
237 while((ret
= getmessage(ATD_SERVER
, &msg
))) {
238 switch(msg
.h
.msgtype
) {
240 /* client wants an ip for a DNS name. iterate our list and check if we have an existing entry.
241 * if not, create a new one. */
242 msg
.m
.ip
= ip_from_internal_list(msg
.m
.host
, msg
.h
.datalen
);
243 msg
.h
.datalen
= sizeof(ip_type4
);
246 char *host
= string_from_internal_ip(msg
.m
.ip
);
248 size_t l
= strlen(host
);
249 assert(l
+1 < MSG_LEN_MAX
);
250 memcpy(msg
.m
.host
, host
, l
+ 1);
251 msg
.h
.datalen
= l
+ 1;
262 ret
= sendmessage(ATD_CLIENT
, &msg
);
267 /* API to access the internal ip mapping */
269 ip_type4
at_get_ip_for_host(char* host
, size_t len
) {
271 MUTEX_LOCK(internal_ips_lock
);
272 if(len
> MSG_LEN_MAX
) goto inv
;
273 struct at_msg msg
= {.h
.msgtype
= ATM_GETIP
, .h
.datalen
= len
+ 1 };
274 memcpy(msg
.m
.host
, host
, len
+1);
275 if(sendmessage(ATD_SERVER
, &msg
) &&
276 getmessage(ATD_CLIENT
, &msg
)) readbuf
= msg
.m
.ip
;
279 readbuf
= IPT4_INVALID
;
281 assert(msg
.h
.msgtype
== ATM_GETIP
);
282 MUTEX_UNLOCK(internal_ips_lock
);
286 size_t at_get_host_for_ip(ip_type4 ip
, char* readbuf
) {
287 struct at_msg msg
= {.h
.msgtype
= ATM_GETNAME
, .h
.datalen
= sizeof(ip_type4
), .m
.ip
= ip
};
289 MUTEX_LOCK(internal_ips_lock
);
290 if(sendmessage(ATD_SERVER
, &msg
) && getmessage(ATD_CLIENT
, &msg
)) {
291 if((int16_t) msg
.h
.datalen
<= 0) res
= 0;
293 memcpy(readbuf
, msg
.m
.host
, msg
.h
.datalen
);
294 res
= msg
.h
.datalen
- 1;
297 assert(msg
.h
.msgtype
== ATM_GETNAME
);
298 MUTEX_UNLOCK(internal_ips_lock
);
303 static void initpipe(int* fds
) {
307 retval
= pipe2(fds
, O_CLOEXEC
);
311 fcntl(fds
[0], F_SETFD
, FD_CLOEXEC
);
312 fcntl(fds
[1], F_SETFD
, FD_CLOEXEC
);
322 #define MAX(x, y) ((x) > (y) ? (x) : (y))
325 #if !defined(PTHREAD_STACK_MIN) || defined(__APPLE__)
326 /* MAC says its min is 8KB, but then crashes in our face. thx hunkOLard */
327 #define PTHREAD_STACK_MIN 64*1024
330 /* initialize with pointers to shared memory. these will
331 * be used to place responses and arguments */
334 void *shm
= mmap(0, 4096, PROT_WRITE
|PROT_READ
, MAP_ANON
|MAP_SHARED
, -1, 0);
336 internal_ips_lock
= shm
;
337 internal_ips
= (void*)((char*)shm
+ 2048);
339 MUTEX_INIT(internal_ips_lock
);
340 memset(internal_ips
, 0, sizeof *internal_ips
);
341 initpipe(req_pipefd
);
342 initpipe(resp_pipefd
);
343 pthread_attr_t allocator_thread_attr
;
344 pthread_attr_init(&allocator_thread_attr
);
345 pthread_attr_setstacksize(&allocator_thread_attr
, MAX(16 * 1024, PTHREAD_STACK_MIN
));
346 pthread_create(&allocator_thread
, &allocator_thread_attr
, threadfunc
, 0);
347 pthread_attr_destroy(&allocator_thread_attr
);
350 void at_close(void) {
352 const int msg
= ATM_EXIT
;
353 write(req_pipefd
[1], &msg
, sizeof(int));
354 pthread_join(allocator_thread
, NULL
);
355 close(req_pipefd
[0]);
356 close(req_pipefd
[1]);
357 close(resp_pipefd
[0]);
358 close(resp_pipefd
[1]);
359 MUTEX_DESTROY(internal_ips_lock
);