diff options
-rw-r--r-- | source3/printing/notify.c | 110 | ||||
-rw-r--r-- | source3/rpc_server/srv_spoolss_nt.c | 59 | ||||
-rw-r--r-- | source3/smbd/connection.c | 71 | ||||
-rw-r--r-- | source3/smbd/process.c | 10 |
4 files changed, 213 insertions, 37 deletions
diff --git a/source3/printing/notify.c b/source3/printing/notify.c index 925d49a21d..4bde6a94f6 100644 --- a/source3/printing/notify.c +++ b/source3/printing/notify.c @@ -22,21 +22,96 @@ #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, diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 37f8071e69..a20fa615fd 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -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; @@ -883,6 +884,49 @@ static void receive_notify2_message(int msg_type, pid_t src, void *buf, } /******************************************************************** + 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 driver @@ -2133,7 +2177,7 @@ static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uin if(!spoolss_connect_to_client(¬ify_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; } diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c index bc897a95cb..ad394a01ca 100644 --- a/source3/smbd/connection.c +++ b/source3/smbd/connection.c @@ -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; +} diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 2c35eadb18..c796797fad 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -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. |