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 "lib/socket/socket.h"
36 #include "libcli/composite/composite.h"
37 #include "librpc/gen_ndr/ndr_nbt.h"
38 #include "libcli/resolve/resolve.h"
42 struct socket_address **addrs;
46 struct event_context *event_ctx;
51 kill off a wayward child if needed. This allows us to stop an async
52 name resolution without leaving a potentially blocking call running
55 static int host_destructor(struct host_state *state)
59 kill(state->child, SIGTERM);
60 close(state->child_fd);
61 if (waitpid(state->child, &status, WNOHANG) == 0) {
62 kill(state->child, SIGKILL);
63 waitpid(state->child, &status, 0);
72 static void run_child(struct composite_context *c, int fd)
74 struct host_state *state = talloc_get_type(c->private_data, struct host_state);
78 /* this is the blocking call we are going to lots of trouble
79 to avoid in the parent */
80 ip = interpret_addr2(state->name.name);
82 address = inet_ntoa(ip);
83 if (address != NULL) {
84 write(fd, address, strlen(address)+1);
90 handle a read event on the pipe
92 static void pipe_handler(struct event_context *ev, struct fd_event *fde,
93 uint16_t flags, void *private_data)
95 struct composite_context *c = talloc_get_type(private_data, struct composite_context);
96 struct host_state *state = talloc_get_type(c->private_data, struct host_state);
101 /* if we get any event from the child then we know that we
102 won't need to kill it off */
103 talloc_set_destructor(state, NULL);
105 /* yes, we don't care about EAGAIN or other niceities
106 here. They just can't happen with this parent/child
107 relationship, and even if they did then giving an error is
108 the right thing to do */
109 ret = read(state->child_fd, address, sizeof(address)-1);
110 close(state->child_fd);
111 if (waitpid(state->child, &status, WNOHANG) == 0) {
112 kill(state->child, SIGKILL);
113 waitpid(state->child, &status, 0);
116 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
120 /* enusre the address looks good */
122 if (strcmp(address, "0.0.0.0") == 0 ||
123 inet_addr(address) == INADDR_NONE) {
124 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
128 state->addrs = talloc_array(state, struct socket_address *, 2);
129 if (composite_nomem(state->addrs, c)) return;
131 state->addrs[0] = socket_address_from_strings(state->addrs,
135 if (composite_nomem(state->addrs[0], c)) return;
136 state->addrs[1] = NULL;
142 gethostbyname name resolution method - async send
144 struct composite_context *resolve_name_host_send(TALLOC_CTX *mem_ctx,
145 struct event_context *event_ctx,
147 struct nbt_name *name)
149 struct composite_context *c;
150 struct host_state *state;
151 int fd[2] = { -1, -1 };
154 c = composite_create(mem_ctx, event_ctx);
155 if (c == NULL) return NULL;
157 if (composite_nomem(c->event_ctx, c)) return c;
159 state = talloc(c, struct host_state);
160 if (composite_nomem(state, c)) return c;
161 c->private_data = state;
163 c->status = nbt_name_dup(state, name, &state->name);
164 if (!composite_is_ok(c)) return c;
166 /* setup a pipe to chat to our child */
169 composite_error(c, map_nt_error_from_unix(errno));
173 state->child_fd = fd[0];
174 state->event_ctx = c->event_ctx;
176 /* we need to put the child in our event context so
177 we know when the gethostbyname() has finished */
178 state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ,
180 if (composite_nomem(state->fde, c)) {
186 state->child = fork();
187 if (state->child == (pid_t)-1) {
188 composite_error(c, map_nt_error_from_unix(errno));
193 if (state->child == 0) {
200 /* cleanup wayward children */
201 talloc_set_destructor(state, host_destructor);
207 gethostbyname name resolution method - recv side
209 NTSTATUS resolve_name_host_recv(struct composite_context *c,
211 struct socket_address ***addrs)
215 status = composite_wait(c);
217 if (NT_STATUS_IS_OK(status)) {
218 struct host_state *state = talloc_get_type(c->private_data, struct host_state);
219 *addrs = talloc_steal(mem_ctx, state->addrs);
227 gethostbyname name resolution method - sync call
229 NTSTATUS resolve_name_host(struct nbt_name *name,
231 struct socket_address ***addrs)
233 struct composite_context *c = resolve_name_host_send(mem_ctx, NULL, NULL, name);
234 return resolve_name_host_recv(c, mem_ctx, addrs);
237 bool resolve_context_add_host_method(struct resolve_context *ctx)
239 return resolve_context_add_method(ctx, resolve_name_host_send, resolve_name_host_recv,