Merge of (apparently working :-) new printing notify code.
authorJeremy Allison <jra@samba.org>
Wed, 4 Sep 2002 21:59:38 +0000 (21:59 +0000)
committerJeremy Allison <jra@samba.org>
Wed, 4 Sep 2002 21:59:38 +0000 (21:59 +0000)
Jeremy.
(This used to be commit 8595c6ce4d74539089b600b3b0ff858a04b793ff)

source3/printing/notify.c
source3/rpc_server/srv_spoolss_nt.c
source3/smbd/connection.c
source3/smbd/process.c

index 925d49a21d6abaf4db43ae3fbff36f673cad341f..4bde6a94f692c22c2d55291a84666f1946e6077d 100644 (file)
 
 #include "printing.h"
 
-/*
- * Print notification routines
- */
+static TALLOC_CTX *send_ctx;
+
+static struct notify_queue {
+       struct notify_queue *next, *prev;
+       void *buf;
+       size_t buflen;
+} *notify_queue_head = NULL;
+
+/*******************************************************************
+ Used to decide if we need a short select timeout.
+*******************************************************************/
+
+BOOL print_notify_messages_pending(void)
+{
+       return (notify_queue_head != NULL);
+}
+
+/*******************************************************************
+ Actually send the batched messages.
+*******************************************************************/
+
+void print_notify_send_messages(void)
+{
+       TDB_CONTEXT *tdb;
+       char *buf;
+       struct notify_queue *pq;
+       size_t msg_count = 0, offset = 0;
+
+       if (!print_notify_messages_pending())
+               return;
+
+       if (!send_ctx)
+               return;
+
+       tdb = conn_tdb_ctx();
+
+       if (!tdb) {
+               DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
+               return;
+       }
+       
+       /* Count the space needed to send the messages. */
+       for (pq = notify_queue_head; pq; pq = pq->next, msg_count++)
+               offset += (pq->buflen + 4);
+               
+       offset += 4; /* For count. */
+
+       buf = talloc(send_ctx, offset);
+       if (!buf) {
+               DEBUG(0,("print_notify_send_messages: Out of memory\n"));
+               talloc_destroy_pool(send_ctx);
+               return;
+       }
+
+       offset = 0;
+       SIVAL(buf,offset,msg_count);
+       offset += 4;
+       for (pq = notify_queue_head; pq; pq = pq->next) {
+               SIVAL(buf,offset,pq->buflen);
+               offset += 4;
+               memcpy(buf + offset, pq->buf, pq->buflen);
+               offset += pq->buflen;
+       }
+
+       message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf, offset, False, NULL);
+       talloc_destroy_pool(send_ctx);
+       notify_queue_head = NULL;
+}
+
+/*******************************************************************
+ Batch up print notify messages.
+*******************************************************************/
 
 static void send_spoolss_notify2_msg(struct spoolss_notify_msg *msg)
 {
        char *buf = NULL;
-       int buflen = 0, len;
-       TDB_CONTEXT *tdb;
+       size_t buflen = 0, len;
+       struct notify_queue *pnqueue;
 
        /* Let's not waste any time with this */
 
        if (lp_disable_spoolss())
                return;
 
+       if (!send_ctx)
+               send_ctx = talloc_init_named("print notify queue");
+
+       if (!send_ctx)
+               goto fail;
+
        /* Flatten data into a message */
 
 again:
@@ -59,24 +134,27 @@ again:
                                msg->len, msg->notify.data);
 
        if (buflen != len) {
-               buf = Realloc(buf, len);
+               buf = talloc_realloc(send_ctx, buf, len);
+               if (!buf)
+                       goto fail;
                buflen = len;
                goto again;
        }
 
-       /* Send message */
+       /* Store the message on the pending queue. */
 
-       tdb = conn_tdb_ctx();
+       pnqueue = talloc(send_ctx, sizeof(*pnqueue));
+       if (!pnqueue)
+               goto fail;
 
-       if (!tdb) {
-               DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
-               goto done;
-       }
-       
-       message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf, buflen, False, NULL);
+       pnqueue->buf = buf;
+       pnqueue->buflen = buflen;
+       DLIST_ADD(notify_queue_head, pnqueue);
+       return;
+
+  fail:
 
-done:
-       SAFE_FREE(buf);
+       DEBUG(0,("send_spoolss_notify2_msg: Out of memory.\n"));
 }
 
 static void send_notify_field_values(const char *printer_name, uint32 type,
index 37f8071e6944af87ca1a8bc75f07a63f4b7d20c8..a20fa615fdbda9bb294fb431e705c22cf2beaf14 100644 (file)
@@ -220,6 +220,9 @@ static void free_printer_entry(void *ptr)
        Printer->notify.option=NULL;
        Printer->notify.client_connected=False;
 
+       /* Tell the connections db we're not interested in printer notify messages. */
+       register_message_flags(False, FLAG_MSG_PRINTING);
+
        /* Remove from the internal list. */
        DLIST_REMOVE(printers_list, Printer);
 
@@ -728,8 +731,7 @@ static struct notify2_message_table job_notify_table[] = {
  back registered
  **********************************************************************/
 
-static void process_notify2_message(struct spoolss_notify_msg *msg, 
-                                   TALLOC_CTX *mem_ctx)
+static void process_notify2_message(struct spoolss_notify_msg *msg, TALLOC_CTX *mem_ctx)
 {
        Printer_entry *p;
 
@@ -837,8 +839,7 @@ done:
  Receive a notify2 message
  ********************************************************************/
 
-static void receive_notify2_message(int msg_type, pid_t src, void *buf, 
-                                   size_t len)
+static void receive_notify2_message(void *buf, size_t len)
 {
        struct spoolss_notify_msg msg;
        int offset = 0;
@@ -882,6 +883,49 @@ static void receive_notify2_message(int msg_type, pid_t src, void *buf,
        talloc_destroy(mem_ctx);
 }
 
+/********************************************************************
+ Receive a notify2 message list
+ ********************************************************************/
+
+static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, size_t len)
+{
+       size_t msg_count, i;
+       char *buf = (char *)msg;
+       char *msg_ptr;
+
+       if (len < 4)
+               goto bad_msg;
+
+       msg_count = IVAL(buf, 0);
+       msg_ptr = buf + 4;
+
+       if (msg_count == 0)
+               goto bad_msg;
+
+       for (i = 0; i < msg_count; i++) {
+               size_t msg_len;
+
+               if (msg_ptr + 4 - buf > len)
+                       goto bad_msg;
+
+               msg_len = IVAL(msg_ptr,0);
+               msg_ptr += 4;
+
+               if (msg_ptr + msg_len - buf > len)
+                       goto bad_msg;
+               receive_notify2_message(msg_ptr, msg_len);
+               msg_ptr += msg_len;
+       }
+
+       DEBUG(10,("receive_notify2_message_list: processed %u messages\n",
+               (unsigned int)msg_count ));
+       return;
+
+  bad_msg:
+
+       DEBUG(0,("receive_notify2_message_list: bad message format !\n"));
+}
+
 /********************************************************************
  Send a message to ourself about new driver being installed
  so we can upgrade the information for each printer bound to this
@@ -2133,7 +2177,7 @@ static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uin
                if(!spoolss_connect_to_client(&notify_cli, unix_printer))
                        return False;
                        
-               message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message);
+               message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list);
        }
 
        smb_connections++;
@@ -2196,6 +2240,8 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
                                        &Printer->notify.client_hnd))
                return WERR_SERVER_UNAVAILABLE;
 
+       /* Tell the connections db we're interested in printer notify messages. */
+       register_message_flags(True, FLAG_MSG_PRINTING);
        Printer->notify.client_connected=True;
 
        return WERR_OK;
@@ -5544,6 +5590,9 @@ WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
                free_spool_notify_option(&Printer->notify.option);
        Printer->notify.client_connected=False;
 
+       /* Tell the connections db we're not interested in printer notify messages. */
+       register_message_flags(False, FLAG_MSG_PRINTING);
+
        return WERR_OK;
 }
 
index bc897a95cb318d3d324b24471962c43afd97d248..ad394a01ca0fd99362dc42fbd714092a22027fd3 100644 (file)
@@ -35,6 +35,17 @@ TDB_CONTEXT *conn_tdb_ctx(void)
        return tdb;
 }
 
+static void make_conn_key(connection_struct *conn,char *name, TDB_DATA *pkbuf, struct connections_key *pkey)
+{
+       ZERO_STRUCTP(pkey);
+       pkey->pid = sys_getpid();
+       pkey->cnum = conn?conn->cnum:-1;
+       fstrcpy(pkey->name, name);
+
+       pkbuf->dptr = (char *)pkey;
+       pkbuf->dsize = sizeof(*pkey);
+}
+
 /****************************************************************************
  Delete a connection record.
 ****************************************************************************/
@@ -49,13 +60,7 @@ BOOL yield_connection(connection_struct *conn,char *name)
 
        DEBUG(3,("Yielding connection to %s\n",name));
 
-       ZERO_STRUCT(key);
-       key.pid = sys_getpid();
-       key.cnum = conn?conn->cnum:-1;
-       fstrcpy(key.name, name);
-
-       kbuf.dptr = (char *)&key;
-       kbuf.dsize = sizeof(key);
+       make_conn_key(conn, name, &kbuf, &key);
 
        if (tdb_delete(tdb, kbuf) != 0) {
                int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0;
@@ -88,7 +93,7 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u
 
        memcpy(&crec, dbuf.dptr, sizeof(crec));
  
-    if (crec.cnum == -1)
+       if (crec.cnum == -1)
                return 0;
 
        /* If the pid was not found delete the entry from connections.tdb */
@@ -156,13 +161,7 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
 
        DEBUG(5,("claiming %s %d\n",name,max_connections));
 
-       ZERO_STRUCT(key);
-       key.pid = sys_getpid();
-       key.cnum = conn?conn->cnum:-1;
-       fstrcpy(key.name, name);
-
-       kbuf.dptr = (char *)&key;
-       kbuf.dsize = sizeof(key);
+       make_conn_key(conn, name, &kbuf, &key);
 
        /* fill in the crec */
        ZERO_STRUCT(crec);
@@ -192,3 +191,45 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
 
        return True;
 }
+
+BOOL register_message_flags(BOOL doreg, uint32 msg_flags)
+{
+       struct connections_key key;
+       struct connections_data *pcrec;
+       TDB_DATA kbuf, dbuf;
+
+       if (!tdb)
+               return False;
+
+       DEBUG(10,("register_message_flags: %s flags 0x%x\n",
+               doreg ? "adding" : "removing",
+               (unsigned int)msg_flags ));
+
+       make_conn_key(NULL, "", &kbuf, &key);
+
+        dbuf = tdb_fetch(tdb, kbuf);
+        if (!dbuf.dptr) {
+               DEBUG(0,("register_message_flags: tdb_fetch failed\n"));
+               return False;
+       }
+
+       pcrec = (struct connections_data *)dbuf.dptr;
+       pcrec->bcast_msg_flags = msg_flags;
+       if (doreg)
+               pcrec->bcast_msg_flags |= msg_flags;
+       else
+               pcrec->bcast_msg_flags &= ~msg_flags;
+
+       if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+               DEBUG(0,("register_message_flags: tdb_store failed with error %s.\n",
+                       tdb_errorstr(tdb) ));
+               SAFE_FREE(dbuf.dptr);
+               return False;
+       }
+
+       DEBUG(10,("register_message_flags: new flags 0x%x\n",
+               (unsigned int)pcrec->bcast_msg_flags ));
+
+       SAFE_FREE(dbuf.dptr);
+       return True;
+}
index 2c35eadb18a2c953c70135292f1b9120e33f8b1e..c796797fad126dff5664d2830cc28b6ac2d8acc6 100644 (file)
@@ -1030,7 +1030,11 @@ static int setup_select_timeout(void)
        select_timeout *= 1000;
 
        t = change_notify_timeout();
-       if (t != -1) select_timeout = MIN(select_timeout, t*1000);
+       if (t != -1)
+               select_timeout = MIN(select_timeout, t*1000);
+
+       if (print_notify_messages_pending())
+               select_timeout = MIN(select_timeout, 1000);
 
        return select_timeout;
 }
@@ -1190,6 +1194,10 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup ));
   force_check_log_size();
   check_log_size();
 
+  /* Send any queued printer notify message to interested smbd's. */
+
+  print_notify_send_messages();
+
   /*
    * Modify the select timeout depending upon
    * what we have remaining in our queues.