Merge branch 'master' of ssh://git.samba.org/data/git/samba
[bbaumbach/samba-autobuild/.git] / source4 / libcli / resolve / host.c
index 5b28a850fccdf50bdffd3efffead7a52aa2f2992..7b1aef803e780f054b4698b14a65aa92b564dd4b 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
 */
 
 #include "includes.h"
-#include "events.h"
+#include "lib/events/events.h"
 #include "system/network.h"
-#include "libcli/raw/libcliraw.h"
+#include "system/filesys.h"
+#include "lib/socket/socket.h"
 #include "libcli/composite/composite.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "libcli/resolve/resolve.h"
 
 struct host_state {
        struct nbt_name name;
-       const char *reply_addr;
+       struct socket_address **addrs;
        pid_t child;
        int child_fd;
        struct fd_event *fde;
@@ -50,137 +52,144 @@ struct host_state {
   name resolution without leaving a potentially blocking call running
   in a child
 */
-static int host_destructor(void *ptr)
+static int host_destructor(struct host_state *state)
 {
-       struct host_state *state = talloc_get_type(ptr, struct host_state);
+       int status;
+
+       kill(state->child, SIGTERM);
        close(state->child_fd);
-       if (state->child != (pid_t)-1) {
-               kill(state->child, SIGTERM);
+       if (waitpid(state->child, &status, WNOHANG) == 0) {
+               kill(state->child, SIGKILL);
+               waitpid(state->child, &status, 0);
        }
+
        return 0;
 }
 
 /*
   the blocking child
 */
-static void run_child(struct smbcli_composite *c, int fd)
+static void run_child(struct composite_context *c, int fd)
 {
-       struct host_state *state = talloc_get_type(c->private, struct host_state);
-       struct ipv4_addr ip;
+       struct host_state *state = talloc_get_type(c->private_data, struct host_state);
+       struct in_addr ip;
        const char *address;
 
        /* this is the blocking call we are going to lots of trouble
           to avoid in the parent */
        ip = interpret_addr2(state->name.name);
 
-       address = sys_inet_ntoa(ip);
+       address = inet_ntoa(ip);
        if (address != NULL) {
                write(fd, address, strlen(address)+1);
        }
+       close(fd);
 }
 
 /*
   handle a read event on the pipe
 */
 static void pipe_handler(struct event_context *ev, struct fd_event *fde, 
-                        struct timeval t, uint16_t flags)
+                        uint16_t flags, void *private_data)
 {
-       struct smbcli_composite *c = talloc_get_type(fde->private, struct smbcli_composite);
-       struct host_state *state = talloc_get_type(c->private, struct host_state);
+       struct composite_context *c = talloc_get_type(private_data, struct composite_context);
+       struct host_state *state = talloc_get_type(c->private_data, struct host_state);
        char address[128];
        int ret;
+       int status;
 
        /* if we get any event from the child then we know that we
           won't need to kill it off */
-       state->child = (pid_t)-1;
+       talloc_set_destructor(state, NULL);
 
        /* yes, we don't care about EAGAIN or other niceities
           here. They just can't happen with this parent/child
           relationship, and even if they did then giving an error is
           the right thing to do */
        ret = read(state->child_fd, address, sizeof(address)-1);
-       if (ret <= 0) goto failed;
+       close(state->child_fd);
+       if (waitpid(state->child, &status, WNOHANG) == 0) {
+               kill(state->child, SIGKILL);
+               waitpid(state->child, &status, 0);
+       }
+       if (ret <= 0) {
+               composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+               return;
+       }
 
        /* enusre the address looks good */
        address[ret] = 0;
        if (strcmp(address, "0.0.0.0") == 0 ||
-           sys_inet_addr(address) == INADDR_NONE) {
-               goto failed;
+           inet_addr(address) == INADDR_NONE) {
+               composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+               return;
        }
 
-       state->reply_addr = talloc_strdup(state, address);
-       if (state->reply_addr == NULL) goto failed;
+       state->addrs = talloc_array(state, struct socket_address *, 2);
+       if (composite_nomem(state->addrs, c)) return;
 
-       c->status = NT_STATUS_OK;
-       c->state = SMBCLI_REQUEST_DONE;
-       if (c->async.fn) {
-               c->async.fn(c);
-       }
-       return;
+       state->addrs[0] = socket_address_from_strings(state->addrs,
+                                                     "ipv4",
+                                                     address,
+                                                     0);
+       if (composite_nomem(state->addrs[0], c)) return;
+       state->addrs[1] = NULL;
 
-failed:
-       c->status = NT_STATUS_BAD_NETWORK_NAME;
-       c->state = SMBCLI_REQUEST_ERROR;
-       if (c->async.fn) {
-               c->async.fn(c);
-       }
+       composite_done(c);
 }
 
 /*
   gethostbyname name resolution method - async send
  */
-struct smbcli_composite *resolve_name_host_send(struct nbt_name *name, 
-                                               struct event_context *event_ctx)
+struct composite_context *resolve_name_host_send(TALLOC_CTX *mem_ctx,
+                                                struct event_context *event_ctx,
+                                                void *privdata,
+                                                struct nbt_name *name)
 {
-       struct smbcli_composite *c;
+       struct composite_context *c;
        struct host_state *state;
-       NTSTATUS status;
        int fd[2] = { -1, -1 };
-       struct fd_event fde;
        int ret;
 
-       c = talloc_zero(NULL, struct smbcli_composite);
-       if (c == NULL) goto failed;
+       c = composite_create(mem_ctx, event_ctx);
+       if (c == NULL) return NULL;
 
-       state = talloc(c, struct host_state);
-       if (state == NULL) goto failed;
+       if (composite_nomem(c->event_ctx, c)) return c;
 
-       status = nbt_name_dup(state, name, &state->name);
-       if (!NT_STATUS_IS_OK(status)) goto failed;
+       state = talloc(c, struct host_state);
+       if (composite_nomem(state, c)) return c;
+       c->private_data = state;
 
-       c->state = SMBCLI_REQUEST_SEND;
-       c->private = state;
-       c->event_ctx = talloc_reference(c, event_ctx);
+       c->status = nbt_name_dup(state, name, &state->name);
+       if (!composite_is_ok(c)) return c;
 
        /* setup a pipe to chat to our child */
        ret = pipe(fd);
-       if (ret == -1) goto failed;
+       if (ret == -1) {
+               composite_error(c, map_nt_error_from_unix(errno));
+               return c;
+       }
 
        state->child_fd = fd[0];
        state->event_ctx = c->event_ctx;
 
        /* we need to put the child in our event context so
           we know when the gethostbyname() has finished */
-       fde.fd = state->child_fd;
-       fde.flags = EVENT_FD_READ;
-       fde.handler = pipe_handler;
-       fde.private = c;
-       state->fde = event_add_fd(c->event_ctx, &fde, state);
-       if (state->fde == NULL) {
+       state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ, 
+                                 pipe_handler, c);
+       if (composite_nomem(state->fde, c)) {
                close(fd[0]);
                close(fd[1]);
-               goto failed;
+               return c;
        }
 
-       /* signal handling in posix really sucks - doing this in a library
-          affects the whole app, but what else to do?? */
-       signal(SIGCHLD, SIG_IGN);
-
        state->child = fork();
        if (state->child == (pid_t)-1) {
-               goto failed;
+               composite_error(c, map_nt_error_from_unix(errno));
+               return c;
        }
 
+
        if (state->child == 0) {
                close(fd[0]);
                run_child(c, fd[1]);
@@ -191,26 +200,23 @@ struct smbcli_composite *resolve_name_host_send(struct nbt_name *name,
        /* cleanup wayward children */
        talloc_set_destructor(state, host_destructor);
 
-       return c;       
-
-failed:
-       talloc_free(c);
-       return NULL;
+       return c;
 }
 
 /*
   gethostbyname name resolution method - recv side
 */
-NTSTATUS resolve_name_host_recv(struct smbcli_composite *c, 
-                                TALLOC_CTX *mem_ctx, const char **reply_addr)
+NTSTATUS resolve_name_host_recv(struct composite_context *c, 
+                               TALLOC_CTX *mem_ctx,
+                               struct socket_address ***addrs)
 {
        NTSTATUS status;
 
-       status = smb_composite_wait(c);
+       status = composite_wait(c);
 
        if (NT_STATUS_IS_OK(status)) {
-               struct host_state *state = talloc_get_type(c->private, struct host_state);
-               *reply_addr = talloc_steal(mem_ctx, state->reply_addr);
+               struct host_state *state = talloc_get_type(c->private_data, struct host_state);
+               *addrs = talloc_steal(mem_ctx, state->addrs);
        }
 
        talloc_free(c);
@@ -222,9 +228,14 @@ NTSTATUS resolve_name_host_recv(struct smbcli_composite *c,
  */
 NTSTATUS resolve_name_host(struct nbt_name *name, 
                            TALLOC_CTX *mem_ctx,
-                           const char **reply_addr)
+                           struct socket_address ***addrs)
 {
-       struct smbcli_composite *c = resolve_name_host_send(name, NULL);
-       return resolve_name_host_recv(c, mem_ctx, reply_addr);
+       struct composite_context *c = resolve_name_host_send(mem_ctx, NULL, NULL, name);
+       return resolve_name_host_recv(c, mem_ctx, addrs);
 }
 
+bool resolve_context_add_host_method(struct resolve_context *ctx)
+{
+       return resolve_context_add_method(ctx, resolve_name_host_send, resolve_name_host_recv,
+                                         NULL);
+}