s3-printing: fix cups pcap reload with no printers
[nivanova/samba-autobuild/.git] / source3 / printing / print_cups.c
index f96e8e17268c000dac4aee5e03fe43b721eea7c9..3031a88e5d110c905d9d53c974f56dc022c8fc5c 100644 (file)
@@ -390,8 +390,7 @@ static bool cups_cache_reload_async(int fd)
        return ret;
 }
 
-static struct pcap_cache *local_pcap_copy;
-struct fd_event *cache_fd_event;
+static struct fd_event *cache_fd_event;
 
 static bool cups_pcap_load_async(struct tevent_context *ev,
                                 struct messaging_context *msg_ctx,
@@ -449,14 +448,24 @@ static bool cups_pcap_load_async(struct tevent_context *ev,
        _exit(0);
 }
 
+struct cups_async_cb_args {
+       int pipe_fd;
+       struct event_context *event_ctx;
+       struct messaging_context *msg_ctx;
+       void (*post_cache_fill_fn)(struct event_context *,
+                                  struct messaging_context *);
+};
+
 static void cups_async_callback(struct event_context *event_ctx,
                                struct fd_event *event,
                                uint16 flags,
                                void *p)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-       int fd = *(int *)p;
+       struct cups_async_cb_args *cb_args = (struct cups_async_cb_args *)p;
+       int fd = cb_args->pipe_fd;
        struct pcap_cache *tmp_pcap_cache = NULL;
+       bool ret_ok = true;
 
        DEBUG(5,("cups_async_callback: callback received for printer data. "
                "fd = %d\n", fd));
@@ -474,6 +483,7 @@ static void cups_async_callback(struct event_context *event_ctx,
                if (ret != sizeof(namelen)) {
                        DEBUG(10,("cups_async_callback: namelen read failed %d %s\n",
                                errno, strerror(errno)));
+                       ret_ok = false;
                        break;
                }
 
@@ -488,6 +498,7 @@ static void cups_async_callback(struct event_context *event_ctx,
                if (ret != sizeof(infolen)) {
                        DEBUG(10,("cups_async_callback: infolen read failed %s\n",
                                strerror(errno)));
+                       ret_ok = false;
                        break;
                }
 
@@ -497,6 +508,7 @@ static void cups_async_callback(struct event_context *event_ctx,
                if (namelen) {
                        name = TALLOC_ARRAY(frame, char, namelen);
                        if (!name) {
+                               ret_ok = false;
                                break;
                        }
                        ret = sys_read(fd, name, namelen);
@@ -507,6 +519,7 @@ static void cups_async_callback(struct event_context *event_ctx,
                        if (ret != namelen) {
                                DEBUG(10,("cups_async_callback: name read failed %s\n",
                                        strerror(errno)));
+                               ret_ok = false;
                                break;
                        }
                        DEBUG(11,("cups_async_callback: read name %s\n",
@@ -517,6 +530,7 @@ static void cups_async_callback(struct event_context *event_ctx,
                if (infolen) {
                        info = TALLOC_ARRAY(frame, char, infolen);
                        if (!info) {
+                               ret_ok = false;
                                break;
                        }
                        ret = sys_read(fd, info, infolen);
@@ -527,6 +541,7 @@ static void cups_async_callback(struct event_context *event_ctx,
                        if (ret != infolen) {
                                DEBUG(10,("cups_async_callback: info read failed %s\n",
                                        strerror(errno)));
+                               ret_ok = false;
                                break;
                        }
                        DEBUG(11,("cups_async_callback: read info %s\n",
@@ -536,76 +551,81 @@ static void cups_async_callback(struct event_context *event_ctx,
                }
 
                /* Add to our local pcap cache. */
-               pcap_cache_add_specific(&tmp_pcap_cache, name, info);
+               ret_ok = pcap_cache_add_specific(&tmp_pcap_cache, name, info);
                TALLOC_FREE(name);
                TALLOC_FREE(info);
+               if (!ret_ok) {
+                       DEBUG(0, ("failed to add to tmp pcap cache\n"));
+                       break;
+               }
        }
 
        TALLOC_FREE(frame);
-       if (tmp_pcap_cache) {
-               /* We got a namelist, replace our local cache. */
-               pcap_cache_destroy_specific(&local_pcap_copy);
-               local_pcap_copy = tmp_pcap_cache;
-
-               /* And the systemwide pcap cache. */
-               pcap_cache_replace(local_pcap_copy);
+       if (!ret_ok) {
+               DEBUG(0, ("failed to read a new printer list\n"));
+               pcap_cache_destroy_specific(&tmp_pcap_cache);
        } else {
-               DEBUG(2,("cups_async_callback: failed to read a new "
-                       "printer list\n"));
+               /*
+                * replace the system-wide pcap cache with a (possibly empty)
+                * new one.
+                * FIXME The child process does not currently propagate cups
+                * errors back up to the parent, therefore we cannot
+                * differentiate between an empty printer list and a failure.
+                */
+               ret_ok = pcap_cache_replace(tmp_pcap_cache);
+               if (!ret_ok) {
+                       DEBUG(0, ("failed to replace pcap cache\n"));
+               } else if (cb_args->post_cache_fill_fn != NULL) {
+                       /* Caller requested post cache fill callback */
+                       cb_args->post_cache_fill_fn(cb_args->event_ctx,
+                                                   cb_args->msg_ctx);
+               }
        }
        close(fd);
-       TALLOC_FREE(p);
+       TALLOC_FREE(cb_args);
        TALLOC_FREE(cache_fd_event);
 }
 
 bool cups_cache_reload(struct tevent_context *ev,
-                      struct messaging_context *msg_ctx)
+                      struct messaging_context *msg_ctx,
+                      void (*post_cache_fill_fn)(struct tevent_context *,
+                                                 struct messaging_context *))
 {
-       int *p_pipe_fd = TALLOC_P(NULL, int);
+       struct cups_async_cb_args *cb_args;
+       int *p_pipe_fd;
 
-       if (!p_pipe_fd) {
+       cb_args = TALLOC_P(NULL, struct cups_async_cb_args);
+       if (cb_args == NULL) {
                return false;
        }
 
+       cb_args->post_cache_fill_fn = post_cache_fill_fn;
+       cb_args->event_ctx = ev;
+       cb_args->msg_ctx = msg_ctx;
+       p_pipe_fd = &cb_args->pipe_fd;
        *p_pipe_fd = -1;
 
        /* Set up an async refresh. */
        if (!cups_pcap_load_async(ev, msg_ctx, p_pipe_fd)) {
+               talloc_free(cb_args);
                return false;
        }
-       if (!local_pcap_copy) {
-               /* We have no local cache, wait directly for
-                * async refresh to complete.
-                */
-               DEBUG(10,("cups_cache_reload: sync read on fd %d\n",
-                       *p_pipe_fd ));
-
-               cups_async_callback(ev, NULL,
-                                       EVENT_FD_READ,
-                                       (void *)p_pipe_fd);
-               if (!local_pcap_copy) {
-                       return false;
-               }
-       } else {
-               /* Replace the system cache with our
-                * local copy. */
-               pcap_cache_replace(local_pcap_copy);
-
-               DEBUG(10,("cups_cache_reload: async read on fd %d\n",
-                       *p_pipe_fd ));
-
-               /* Trigger an event when the pipe can be read. */
-               cache_fd_event = event_add_fd(ev,
-                                       NULL, *p_pipe_fd,
-                                       EVENT_FD_READ,
-                                       cups_async_callback,
-                                       (void *)p_pipe_fd);
-               if (!cache_fd_event) {
-                       close(*p_pipe_fd);
-                       TALLOC_FREE(p_pipe_fd);
-                       return false;
-               }
+
+       DEBUG(10,("cups_cache_reload: async read on fd %d\n",
+               *p_pipe_fd ));
+
+       /* Trigger an event when the pipe can be read. */
+       cache_fd_event = event_add_fd(ev,
+                               NULL, *p_pipe_fd,
+                               EVENT_FD_READ,
+                               cups_async_callback,
+                               (void *)cb_args);
+       if (!cache_fd_event) {
+               close(*p_pipe_fd);
+               TALLOC_FREE(cb_args);
+               return false;
        }
+
        return true;
 }
 
@@ -912,7 +932,6 @@ static int cups_job_submit(int snum, struct printjob *pjob)
        ipp_attribute_t *attr_job_id = NULL;    /* IPP Attribute "job-id" */
        cups_lang_t     *language = NULL;       /* Default language */
        char            uri[HTTP_MAX_URI]; /* printer-uri attribute */
-       const char      *clientname = NULL;     /* hostname of client for job-originating-host attribute */
        char *new_jobname = NULL;
        int             num_options = 0;
        cups_option_t   *options = NULL;
@@ -923,7 +942,6 @@ static int cups_job_submit(int snum, struct printjob *pjob)
        char *filename = NULL;
        size_t size;
        uint32_t jobid = (uint32_t)-1;
-       char addr[INET6_ADDRSTRLEN];
 
        DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
 
@@ -981,14 +999,9 @@ static int cups_job_submit(int snum, struct printjob *pjob)
        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
                     NULL, user);
 
-       clientname = client_name(get_client_fd());
-       if (strcmp(clientname, "UNKNOWN") == 0) {
-               clientname = client_addr(get_client_fd(),addr,sizeof(addr));
-       }
-
        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                     "job-originating-host-name", NULL,
-                     clientname);
+                    pjob->clientmachine);
 
        /* Get the jobid from the filename. */
        jobid = print_parse_jobid(pjob->filename);