1<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Chapter�15.�Samba Printing Internals</title><link rel="stylesheet" href="samba.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.71.0"><link rel="start" href="index.html" title="SAMBA Developers Guide"><link rel="up" href="pt04.html" title="Part�IV.�Debugging and tracing"><link rel="prev" href="tracing.html" title="Chapter�14.�Tracing samba system calls"><link rel="next" href="pt05.html" title="Part�V.�Appendices"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter�15.�Samba Printing Internals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="tracing.html">Prev</a>�</td><th width="60%" align="center">Part�IV.�Debugging and tracing</th><td width="20%" align="right">�<a accesskey="n" href="pt05.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="devprinting"></a>Chapter�15.�Samba Printing Internals</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Gerald</span> <span class="surname">Carter</span></h3></div></div><div><p class="pubdate">October 2002</p></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="devprinting.html#id326484">Abstract</a></span></dt><dt><span class="sect1"><a href="devprinting.html#id326495"> 2Printing Interface to Various Back ends 3</a></span></dt><dt><span class="sect1"><a href="devprinting.html#id326569"> 4Print Queue TDB's 5</a></span></dt><dt><span class="sect1"><a href="devprinting.html#id326708"> 6ChangeID and Client Caching of Printer Information 7</a></span></dt><dt><span class="sect1"><a href="devprinting.html#id326718"> 8Windows NT/2K Printer Change Notify 9</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id326484"></a>Abstract</h2></div></div></div><p> 10The purpose of this document is to provide some insight into 11Samba's printing functionality and also to describe the semantics 12of certain features of Windows client printing. 13</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id326495"></a> 14Printing Interface to Various Back ends 15</h2></div></div></div><p> 16Samba uses a table of function pointers to seven functions. The 17function prototypes are defined in the <code class="varname">printif</code> structure declared 18in <code class="filename">printing.h</code>. 19</p><div class="itemizedlist"><ul type="disc"><li><p>retrieve the contents of a print queue</p></li><li><p>pause the print queue</p></li><li><p>resume a paused print queue</p></li><li><p>delete a job from the queue</p></li><li><p>pause a job in the print queue</p></li><li><p>result a paused print job in the queue</p></li><li><p>submit a job to the print queue</p></li></ul></div><p> 20Currently there are only two printing back end implementations 21defined. 22</p><div class="itemizedlist"><ul type="disc"><li><p>a generic set of functions for working with standard UNIX 23 printing subsystems</p></li><li><p>a set of CUPS specific functions (this is only enabled if 24 the CUPS libraries were located at compile time).</p></li></ul></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id326569"></a> 25Print Queue TDB's 26</h2></div></div></div><p> 27Samba provides periodic caching of the output from the "lpq command" 28for performance reasons. This cache time is configurable in seconds. 29Obviously the longer the cache time the less often smbd will be 30required to exec a copy of lpq. However, the accuracy of the print 31queue contents displayed to clients will be diminished as well. 32</p><p> 33The list of currently opened print queue TDB's can be found 34be examining the list of tdb_print_db structures ( see print_db_head 35in printing.c ). A queue TDB is opened using the wrapper function 36printing.c:get_print_db_byname(). The function ensures that smbd 37does not open more than MAX_PRINT_DBS_OPEN in an effort to prevent 38a large print server from exhausting all available file descriptors. 39If the number of open queue TDB's exceeds the MAX_PRINT_DBS_OPEN 40limit, smbd falls back to a most recently used algorithm for maintaining 41a list of open TDB's. 42</p><p> 43There are two ways in which a a print job can be entered into 44a print queue's TDB. The first is to submit the job from a Windows 45client which will insert the job information directly into the TDB. 46The second method is to have the print job picked up by executing the 47"lpq command". 48</p><pre class="programlisting"> 49/* included from printing.h */ 50struct printjob { 51 pid_t pid; /* which process launched the job */ 52 int sysjob; /* the system (lp) job number */ 53 int fd; /* file descriptor of open file if open */ 54 time_t starttime; /* when the job started spooling */ 55 int status; /* the status of this job */ 56 size_t size; /* the size of the job so far */ 57 int page_count; /* then number of pages so far */ 58 BOOL spooled; /* has it been sent to the spooler yet? */ 59 BOOL smbjob; /* set if the job is a SMB job */ 60 fstring filename; /* the filename used to spool the file */ 61 fstring jobname; /* the job name given to us by the client */ 62 fstring user; /* the user who started the job */ 63 fstring queuename; /* service number of printer for this job */ 64 NT_DEVICEMODE *nt_devmode; 65}; 66</pre><p> 67The current manifestation of the printjob structure contains a field 68for the UNIX job id returned from the "lpq command" and a Windows job 69ID (32-bit bounded by PRINT_MAX_JOBID). When a print job is returned 70by the "lpq command" that does not match an existing job in the queue's 71TDB, a 32-bit job ID above the <*vance doesn't know what word is missing here*> is generating by adding UNIX_JOB_START to 72the id reported by lpq. 73</p><p> 74In order to match a 32-bit Windows jobid onto a 16-bit lanman print job 75id, smbd uses an in memory TDB to match the former to a number appropriate 76for old lanman clients. 77</p><p> 78When updating a print queue, smbd will perform the following 79steps ( refer to <code class="filename">print.c:print_queue_update()</code> ): 80</p><div class="orderedlist"><ol type="1"><li><p>Check to see if another smbd is currently in 81 the process of updating the queue contents by checking the pid 82 stored in <code class="constant">LOCK/<em class="replaceable"><code>printer_name</code></em></code>. 83 If so, then do not update the TDB.</p></li><li><p>Lock the mutex entry in the TDB and store our own pid. 84 Check that this succeeded, else fail.</p></li><li><p>Store the updated time stamp for the new cache 85 listing</p></li><li><p>Retrieve the queue listing via "lpq command"</p></li><li><pre class="programlisting"> 86 foreach job in the queue 87 { 88 if the job is a UNIX job, create a new entry; 89 if the job has a Windows based jobid, then 90 { 91 Lookup the record by the jobid; 92 if the lookup failed, then 93 treat it as a UNIX job; 94 else 95 update the job status only 96 } 97 }</pre></li><li><p>Delete any jobs in the TDB that are not 98 in the in the lpq listing</p></li><li><p>Store the print queue status in the TDB</p></li><li><p>update the cache time stamp again</p></li></ol></div><p> 99Note that it is the contents of this TDB that is returned to Windows 100clients and not the actual listing from the "lpq command". 101</p><p> 102The NT_DEVICEMODE stored as part of the printjob structure is used to 103store a pointer to a non-default DeviceMode associated with the print 104job. The pointer will be non-null when the client included a Device 105Mode in the OpenPrinterEx() call and subsequently submitted a job for 106printing on that same handle. If the client did not include a Device 107Mode in the OpenPrinterEx() request, the nt_devmode field is NULL 108and the job has the printer's device mode associated with it by default. 109</p><p> 110Only non-default Device Mode are stored with print jobs in the print 111queue TDB. Otherwise, the Device Mode is obtained from the printer 112object when the client issues a GetJob(level == 2) request. 113</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id326708"></a> 114ChangeID and Client Caching of Printer Information 115</h2></div></div></div><p> 116[To be filled in later] 117</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id326718"></a> 118Windows NT/2K Printer Change Notify 119</h2></div></div></div><p> 120When working with Windows NT+ clients, it is possible for a 121print server to use RPC to send asynchronous change notification 122events to clients for certain printer and print job attributes. 123This can be useful when the client needs to know that a new 124job has been added to the queue for a given printer or that the 125driver for a printer has been changed. Note that this is done 126entirely orthogonal to cache updates based on a new ChangeID for 127a printer object. 128</p><p> 129The basic set of RPC's used to implement change notification are 130</p><div class="itemizedlist"><ul type="disc"><li><p>RemoteFindFirstPrinterChangeNotifyEx ( RFFPCN )</p></li><li><p>RemoteFindNextPrinterChangeNotifyEx ( RFNPCN )</p></li><li><p>FindClosePrinterChangeNotify( FCPCN )</p></li><li><p>ReplyOpenPrinter</p></li><li><p>ReplyClosePrinter</p></li><li><p>RouteRefreshPrinterChangeNotify ( RRPCN )</p></li></ul></div><p> 131One additional RPC is available to a server, but is never used by the 132Windows spooler service: 133</p><div class="itemizedlist"><ul type="disc"><li><p>RouteReplyPrinter()</p></li></ul></div><p> 134The opnum for all of these RPC's are defined in include/rpc_spoolss.h 135</p><p> 136Windows NT print servers use a bizarre method of sending print 137notification event to clients. The process of registering a new change 138notification handle is as follows. The 'C' is for client and the 139'S' is for server. All error conditions have been eliminated. 140</p><pre class="programlisting"> 141C: Obtain handle to printer or to the printer 142 server via the standard OpenPrinterEx() call. 143S: Respond with a valid handle to object 144 145C: Send a RFFPCN request with the previously obtained 146 handle with either (a) set of flags for change events 147 to monitor, or (b) a PRINTER_NOTIFY_OPTIONS structure 148 containing the event information to monitor. The windows 149 spooler has only been observed to use (b). 150S: The <* another missing word*> opens a new TCP session to the client (thus requiring 151 all print clients to be CIFS servers as well) and sends 152 a ReplyOpenPrinter() request to the client. 153C: The client responds with a printer handle that can be used to 154 send event notification messages. 155S: The server replies success to the RFFPCN request. 156 157C: The windows spooler follows the RFFPCN with a RFNPCN 158 request to fetch the current values of all monitored 159 attributes. 160S: The server replies with an array SPOOL_NOTIFY_INFO_DATA 161 structures (contained in a SPOOL_NOTIFY_INFO structure). 162 163C: If the change notification handle is ever released by the 164 client via a FCPCN request, the server sends a ReplyClosePrinter() 165 request back to the client first. However a request of this 166 nature from the client is often an indication that the previous 167 notification event was not marshalled correctly by the server 168 or a piece of data was wrong. 169S: The server closes the internal change notification handle 170 (POLICY_HND) and does not send any further change notification 171 events to the client for that printer or job. 172</pre><p> 173The current list of notification events supported by Samba can be 174found by examining the internal tables in srv_spoolss_nt.c 175</p><div class="itemizedlist"><ul type="disc"><li><p>printer_notify_table[]</p></li><li><p>job_notify_table[]</p></li></ul></div><p> 176When an event occurs that could be monitored, smbd sends a message 177to itself about the change. The list of events to be transmitted 178are queued by the smbd process sending the message to prevent an 179overload of TDB usage and the internal message is sent during smbd's 180idle loop (refer to printing/notify.c and the functions 181send_spoolss_notify2_msg() and print_notify_send_messages() ). 182</p><p> 183The decision of whether or not the change is to be sent to connected 184clients is made by the routine which actually sends the notification. 185( refer to srv_spoolss_nt.c:recieve_notify2_message() ). 186</p><p> 187Because it possible to receive a listing of multiple changes for 188multiple printers, the notification events must be split into 189categories by the printer name. This makes it possible to group 190multiple change events to be sent in a single RPC according to the 191printer handle obtained via a ReplyOpenPrinter(). 192</p><p> 193The actual change notification is performed using the RRPCN request 194RPC. This packet contains 195</p><div class="itemizedlist"><ul type="disc"><li><p>the printer handle registered with the 196client's spooler on which the change occurred</p></li><li><p>The change_low value which was sent as part 197of the last RFNPCN request from the client</p></li><li><p>The SPOOL_NOTIFY_INFO container with the event 198information</p></li></ul></div><p> 199A <code class="varname">SPOOL_NOTIFY_INFO</code> contains: 200</p><div class="itemizedlist"><ul type="disc"><li><p>the version and flags field are predefined 201and should not be changed</p></li><li><p>The count field is the number of entries 202in the SPOOL_NOTIFY_INFO_DATA array</p></li></ul></div><p> 203The <code class="varname">SPOOL_NOTIFY_INFO_DATA</code> entries contain: 204</p><div class="itemizedlist"><ul type="disc"><li><p>The type defines whether or not this event 205is for a printer or a print job</p></li><li><p>The field is the flag identifying the event</p></li><li><p>the notify_data union contains the new valuie of the 206attribute</p></li><li><p>The enc_type defines the size of the structure for marshalling 207and unmarshalling</p></li><li><p>(a) the id must be 0 for a printer event on a printer handle. 208(b) the id must be the job id for an event on a printer job 209(c) the id must be the matching number of the printer index used 210in the response packet to the RFNPCN when using a print server 211handle for notification. Samba currently uses the snum of 212the printer for this which can break if the list of services 213has been modified since the notification handle was registered.</p></li><li><p>The size is either (a) the string length in UNICODE for strings, 214(b) the size in bytes of the security descriptor, or (c) 0 for 215data values.</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="tracing.html">Prev</a>�</td><td width="20%" align="center"><a accesskey="u" href="pt04.html">Up</a></td><td width="40%" align="right">�<a accesskey="n" href="pt05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter�14.�Tracing samba system calls�</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">�Part�V.�Appendices</td></tr></table></div></body></html> 216