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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 this module uses a fork() per gethostbyname() call. At first that
25 might seem crazy, but it is actually very fast, and solves many of
26 the tricky problems of keeping a child hanging around in a library
27 (like what happens when the parent forks). We use a talloc
28 destructor to ensure that the child is cleaned up when we have
29 finished with this name resolution.
33 #include "lib/events/events.h"
34 #include "system/network.h"
35 #include "system/filesys.h"
36 #include "libcli/composite/composite.h"
37 #include "librpc/gen_ndr/ndr_nbt.h"
41 const char *reply_addr
;
45 struct event_context
*event_ctx
;
50 kill off a wayward child if needed. This allows us to stop an async
51 name resolution without leaving a potentially blocking call running
54 static int host_destructor(struct host_state
*state
)
56 close(state
->child_fd
);
57 if (state
->child
!= (pid_t
)-1) {
58 kill(state
->child
, SIGTERM
);
66 static void run_child(struct composite_context
*c
, int fd
)
68 struct host_state
*state
= talloc_get_type(c
->private_data
, struct host_state
);
72 /* this is the blocking call we are going to lots of trouble
73 to avoid in the parent */
74 ip
= interpret_addr2(state
->name
.name
);
76 address
= sys_inet_ntoa(ip
);
77 if (address
!= NULL
) {
78 write(fd
, address
, strlen(address
)+1);
84 handle a read event on the pipe
86 static void pipe_handler(struct event_context
*ev
, struct fd_event
*fde
,
87 uint16_t flags
, void *private_data
)
89 struct composite_context
*c
= talloc_get_type(private_data
, struct composite_context
);
90 struct host_state
*state
= talloc_get_type(c
->private_data
, struct host_state
);
94 /* if we get any event from the child then we know that we
95 won't need to kill it off */
96 state
->child
= (pid_t
)-1;
98 /* yes, we don't care about EAGAIN or other niceities
99 here. They just can't happen with this parent/child
100 relationship, and even if they did then giving an error is
101 the right thing to do */
102 ret
= read(state
->child_fd
, address
, sizeof(address
)-1);
104 composite_error(c
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
108 /* enusre the address looks good */
110 if (strcmp(address
, "0.0.0.0") == 0 ||
111 inet_addr(address
) == INADDR_NONE
) {
112 composite_error(c
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
116 state
->reply_addr
= talloc_strdup(state
, address
);
117 if (composite_nomem(state
->reply_addr
, c
)) return;
123 gethostbyname name resolution method - async send
125 struct composite_context
*resolve_name_host_send(TALLOC_CTX
*mem_ctx
,
126 struct event_context
*event_ctx
,
127 struct nbt_name
*name
)
129 struct composite_context
*c
;
130 struct host_state
*state
;
131 int fd
[2] = { -1, -1 };
134 c
= composite_create(mem_ctx
, event_ctx
);
135 if (c
== NULL
) return NULL
;
137 c
->event_ctx
= talloc_reference(c
, event_ctx
);
138 if (composite_nomem(c
->event_ctx
, c
)) return c
;
140 state
= talloc(c
, struct host_state
);
141 if (composite_nomem(state
, c
)) return c
;
142 c
->private_data
= state
;
144 c
->status
= nbt_name_dup(state
, name
, &state
->name
);
145 if (!composite_is_ok(c
)) return c
;
147 /* setup a pipe to chat to our child */
150 composite_error(c
, map_nt_error_from_unix(errno
));
154 state
->child_fd
= fd
[0];
155 state
->event_ctx
= c
->event_ctx
;
157 /* we need to put the child in our event context so
158 we know when the gethostbyname() has finished */
159 state
->fde
= event_add_fd(c
->event_ctx
, c
, state
->child_fd
, EVENT_FD_READ
,
161 if (composite_nomem(state
->fde
, c
)) {
167 /* signal handling in posix really sucks - doing this in a library
168 affects the whole app, but what else to do?? */
169 signal(SIGCHLD
, SIG_IGN
);
171 state
->child
= fork();
172 if (state
->child
== (pid_t
)-1) {
173 composite_error(c
, map_nt_error_from_unix(errno
));
178 if (state
->child
== 0) {
185 /* cleanup wayward children */
186 talloc_set_destructor(state
, host_destructor
);
192 gethostbyname name resolution method - recv side
194 NTSTATUS
resolve_name_host_recv(struct composite_context
*c
,
195 TALLOC_CTX
*mem_ctx
, const char **reply_addr
)
199 status
= composite_wait(c
);
201 if (NT_STATUS_IS_OK(status
)) {
202 struct host_state
*state
= talloc_get_type(c
->private_data
, struct host_state
);
203 *reply_addr
= talloc_steal(mem_ctx
, state
->reply_addr
);
211 gethostbyname name resolution method - sync call
213 NTSTATUS
resolve_name_host(struct nbt_name
*name
,
215 const char **reply_addr
)
217 struct composite_context
*c
= resolve_name_host_send(mem_ctx
, NULL
, name
);
218 return resolve_name_host_recv(c
, mem_ctx
, reply_addr
);