2 Unix SMB/CIFS implementation.
4 async gethostbyname() name resolution module
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 this module uses a fork() per gethostbyname() call. At first that
24 might seem crazy, but it is actually very fast, and solves many of
25 the tricky problems of keeping a child hanging around in a library
26 (like what happens when the parent forks). We use a talloc
27 destructor to ensure that the child is cleaned up when we have
28 finished with this name resolution.
32 #include "lib/events/events.h"
33 #include "system/network.h"
34 #include "system/filesys.h"
35 #include "libcli/composite/composite.h"
36 #include "librpc/gen_ndr/ndr_nbt.h"
40 const char *reply_addr;
44 struct event_context *event_ctx;
49 kill off a wayward child if needed. This allows us to stop an async
50 name resolution without leaving a potentially blocking call running
53 static int host_destructor(struct host_state *state)
55 close(state->child_fd);
56 if (state->child != (pid_t)-1) {
57 kill(state->child, SIGTERM);
65 static void run_child(struct composite_context *c, int fd)
67 struct host_state *state = talloc_get_type(c->private_data, struct host_state);
71 /* this is the blocking call we are going to lots of trouble
72 to avoid in the parent */
73 ip = interpret_addr2(state->name.name);
75 address = inet_ntoa(ip);
76 if (address != NULL) {
77 write(fd, address, strlen(address)+1);
83 handle a read event on the pipe
85 static void pipe_handler(struct event_context *ev, struct fd_event *fde,
86 uint16_t flags, void *private_data)
88 struct composite_context *c = talloc_get_type(private_data, struct composite_context);
89 struct host_state *state = talloc_get_type(c->private_data, struct host_state);
93 /* if we get any event from the child then we know that we
94 won't need to kill it off */
95 state->child = (pid_t)-1;
97 /* yes, we don't care about EAGAIN or other niceities
98 here. They just can't happen with this parent/child
99 relationship, and even if they did then giving an error is
100 the right thing to do */
101 ret = read(state->child_fd, address, sizeof(address)-1);
103 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
107 /* enusre the address looks good */
109 if (strcmp(address, "0.0.0.0") == 0 ||
110 inet_addr(address) == INADDR_NONE) {
111 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
115 state->reply_addr = talloc_strdup(state, address);
116 if (composite_nomem(state->reply_addr, c)) return;
122 gethostbyname name resolution method - async send
124 struct composite_context *resolve_name_host_send(TALLOC_CTX *mem_ctx,
125 struct event_context *event_ctx,
126 struct nbt_name *name)
128 struct composite_context *c;
129 struct host_state *state;
130 int fd[2] = { -1, -1 };
133 c = composite_create(mem_ctx, event_ctx);
134 if (c == NULL) return NULL;
136 c->event_ctx = talloc_reference(c, event_ctx);
137 if (composite_nomem(c->event_ctx, c)) return c;
139 state = talloc(c, struct host_state);
140 if (composite_nomem(state, c)) return c;
141 c->private_data = state;
143 c->status = nbt_name_dup(state, name, &state->name);
144 if (!composite_is_ok(c)) return c;
146 /* setup a pipe to chat to our child */
149 composite_error(c, map_nt_error_from_unix(errno));
153 state->child_fd = fd[0];
154 state->event_ctx = c->event_ctx;
156 /* we need to put the child in our event context so
157 we know when the gethostbyname() has finished */
158 state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ,
160 if (composite_nomem(state->fde, c)) {
166 /* signal handling in posix really sucks - doing this in a library
167 affects the whole app, but what else to do?? */
168 signal(SIGCHLD, SIG_IGN);
170 state->child = fork();
171 if (state->child == (pid_t)-1) {
172 composite_error(c, map_nt_error_from_unix(errno));
177 if (state->child == 0) {
184 /* cleanup wayward children */
185 talloc_set_destructor(state, host_destructor);
191 gethostbyname name resolution method - recv side
193 NTSTATUS resolve_name_host_recv(struct composite_context *c,
194 TALLOC_CTX *mem_ctx, const char **reply_addr)
198 status = composite_wait(c);
200 if (NT_STATUS_IS_OK(status)) {
201 struct host_state *state = talloc_get_type(c->private_data, struct host_state);
202 *reply_addr = talloc_steal(mem_ctx, state->reply_addr);
210 gethostbyname name resolution method - sync call
212 NTSTATUS resolve_name_host(struct nbt_name *name,
214 const char **reply_addr)
216 struct composite_context *c = resolve_name_host_send(mem_ctx, NULL, name);
217 return resolve_name_host_recv(c, mem_ctx, reply_addr);