]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cups-polld.c
2 * "$Id: cups-polld.c 7198 2008-01-08 00:12:17Z mike $"
4 * Polling daemon for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * main() - Open sockets and poll until we are killed...
18 * dequote() - Remote quotes from a string.
19 * poll_server() - Poll the server for the given set of printers or
21 * sighup_handler() - Handle 'hangup' signals to restart polling.
25 * Include necessary headers...
28 #include <cups/http-private.h>
29 #include <cups/cups.h>
32 #include <cups/language.h>
33 #include <cups/string.h>
41 static int restart_polling
= 1;
48 static char *dequote(char *d
, const char *s
, int dlen
);
49 static int poll_server(http_t
*http
, int sock
, int port
, int interval
,
51 static void sighup_handler(int sig
);
55 * 'main()' - Open sockets and poll until we are killed...
58 int /* O - Exit status */
59 main(int argc
, /* I - Number of command-line args */
60 char *argv
[]) /* I - Command-line arguments */
62 http_t
*http
; /* HTTP connection */
63 int interval
; /* Polling interval */
64 int sock
; /* Browser sock */
65 int port
; /* Browser port */
66 int val
; /* Socket option value */
67 int seconds
, /* Seconds left from poll */
68 remain
; /* Total remaining time to sleep */
69 char prefix
[1024]; /* Prefix for log messages */
70 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
71 struct sigaction action
; /* Actions for POSIX signals */
72 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
76 * Catch hangup signals for when the network changes...
79 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
80 sigset(SIGHUP
, sighup_handler
);
81 #elif defined(HAVE_SIGACTION)
82 memset(&action
, 0, sizeof(action
));
84 sigemptyset(&action
.sa_mask
);
85 sigaddset(&action
.sa_mask
, SIGHUP
);
86 action
.sa_handler
= sighup_handler
;
87 sigaction(SIGHUP
, &action
, NULL
);
89 signal(SIGHUP
, sighup_handler
);
90 #endif /* HAVE_SIGSET */
93 * Don't buffer log messages...
99 * The command-line must contain the following:
101 * cups-polld server server-port interval port
106 fputs("Usage: cups-polld server server-port interval port\n", stderr
);
110 interval
= atoi(argv
[3]);
111 port
= atoi(argv
[4]);
116 snprintf(prefix
, sizeof(prefix
), "[cups-polld %s:%d]", argv
[1], atoi(argv
[2]));
119 * Open a broadcast socket...
122 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
124 fprintf(stderr
, "ERROR: %s Unable to open broadcast socket: %s\n", prefix
,
130 * Set the "broadcast" flag...
134 if (setsockopt(sock
, SOL_SOCKET
, SO_BROADCAST
, &val
, sizeof(val
)))
136 fprintf(stderr
, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
137 prefix
, strerror(errno
));
144 * Loop forever, asking for available printers and classes...
147 for (http
= NULL
; !ferror(stderr
);)
150 * Open a connection to the server...
153 if (restart_polling
|| !http
)
158 if ((http
= httpConnectEncrypt(argv
[1], atoi(argv
[2]),
159 cupsEncryption())) == NULL
)
161 fprintf(stderr
, "ERROR: %s Unable to connect to %s on port %s: %s\n",
162 prefix
, argv
[1], argv
[2],
163 h_errno
? hstrerror(h_errno
) : strerror(errno
));
168 * Get the printers and classes...
173 if (http
&& (seconds
= poll_server(http
, sock
, port
, interval
, prefix
)) > 0)
177 * Sleep for any remaining time...
180 if (remain
> 0 && !restart_polling
)
189 * 'dequote()' - Remote quotes from a string.
192 static char * /* O - Dequoted string */
193 dequote(char *d
, /* I - Destination string */
194 const char *s
, /* I - Source string */
195 int dlen
) /* I - Destination length */
197 char *dptr
; /* Pointer into destination */
202 for (dptr
= d
, dlen
--; *s
&& dlen
> 0; s
++)
219 * 'poll_server()' - Poll the server for the given set of printers or classes.
222 static int /* O - Number of seconds or -1 on error */
223 poll_server(http_t
*http
, /* I - HTTP connection */
224 int sock
, /* I - Broadcast sock */
225 int port
, /* I - Broadcast port */
226 int interval
, /* I - Polling interval */
227 const char *prefix
) /* I - Prefix for log messages */
229 int seconds
; /* Number of seconds */
230 int count
, /* Current number of printers/classes */
231 max_count
; /* Maximum printers/classes per second */
232 ipp_t
*request
, /* Request data */
233 *response
; /* Response data */
234 ipp_attribute_t
*attr
; /* Current attribute */
235 const char *uri
; /* printer-uri */
236 char info
[1024], /* printer-info */
237 job_sheets
[1024],/* job-sheets-default */
238 location
[1024], /* printer-location */
240 /* printer-make-and-model */
241 cups_ptype_t type
; /* printer-type */
242 ipp_pstate_t state
; /* printer-state */
243 int accepting
; /* printer-is-accepting-jobs */
244 struct sockaddr_in addr
; /* Broadcast address */
245 char packet
[1540]; /* Data packet */
246 static const char * const attrs
[] = /* Requested attributes */
248 "job-sheets-default",
250 "printer-is-accepting-jobs",
252 "printer-make-and-model",
256 "printer-uri-supported"
261 * Broadcast to 127.0.0.1 (localhost)
264 memset(&addr
, 0, sizeof(addr
));
265 addr
.sin_addr
.s_addr
= htonl(0x7f000001);
266 addr
.sin_family
= AF_INET
;
267 addr
.sin_port
= htons(port
);
270 * Build a CUPS_GET_PRINTERS request and pass along a list of the
271 * attributes we are interested in along with the types of printers
272 * (and classes) we want.
275 request
= ippNewRequest(CUPS_GET_PRINTERS
);
277 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
278 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
281 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
283 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
285 CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
286 CUPS_PRINTER_NOT_SHARED
);
289 * Do the request and get back a response...
292 seconds
= time(NULL
);
293 response
= cupsDoRequest(http
, request
, "/");
295 if (cupsLastError() > IPP_OK_CONFLICT
)
297 fprintf(stderr
, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix
,
298 cupsLastErrorString());
306 * Figure out how many printers/classes we have...
309 for (attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
),
312 attr
= ippFindNextAttribute(response
, "printer-name", IPP_TAG_NAME
),
315 fprintf(stderr
, "DEBUG: %s Found %d printers.\n", prefix
, max_count
);
318 max_count
= max_count
/ interval
+ 1;
321 * Loop through the printers or classes returned in the list...
324 for (attr
= response
->attrs
; attr
; attr
= attr
->next
)
327 * Skip leading attributes until we hit a printer...
330 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
337 * Pull the needed attributes from this printer...
342 job_sheets
[0] = '\0';
344 make_model
[0] = '\0';
345 type
= CUPS_PRINTER_REMOTE
;
347 state
= IPP_PRINTER_IDLE
;
349 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
351 if (!strcmp(attr
->name
, "job-sheets-default") &&
352 (attr
->value_tag
== IPP_TAG_NAME
||
353 attr
->value_tag
== IPP_TAG_KEYWORD
))
355 if (attr
->num_values
== 1)
356 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s",
357 attr
->values
[0].string
.text
);
359 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s,%s",
360 attr
->values
[0].string
.text
,
361 attr
->values
[1].string
.text
);
363 else if (!strcmp(attr
->name
, "printer-uri-supported") &&
364 attr
->value_tag
== IPP_TAG_URI
)
365 uri
= attr
->values
[0].string
.text
;
366 else if (!strcmp(attr
->name
, "printer-info") &&
367 attr
->value_tag
== IPP_TAG_TEXT
)
368 dequote(info
, attr
->values
[0].string
.text
, sizeof(info
));
369 else if (!strcmp(attr
->name
, "printer-is-accepting-jobs") &&
370 attr
->value_tag
== IPP_TAG_BOOLEAN
)
371 accepting
= attr
->values
[0].boolean
;
372 else if (!strcmp(attr
->name
, "printer-location") &&
373 attr
->value_tag
== IPP_TAG_TEXT
)
374 dequote(location
, attr
->values
[0].string
.text
, sizeof(location
));
375 else if (!strcmp(attr
->name
, "printer-make-and-model") &&
376 attr
->value_tag
== IPP_TAG_TEXT
)
377 dequote(make_model
, attr
->values
[0].string
.text
, sizeof(location
));
378 else if (!strcmp(attr
->name
, "printer-state") &&
379 attr
->value_tag
== IPP_TAG_ENUM
)
380 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
381 else if (!strcmp(attr
->name
, "printer-type") &&
382 attr
->value_tag
== IPP_TAG_ENUM
)
383 type
= (cups_ptype_t
)attr
->values
[0].integer
;
389 * See if we have everything needed...
401 * Send the printer information...
404 type
|= CUPS_PRINTER_REMOTE
;
407 type
|= CUPS_PRINTER_REJECTING
;
409 snprintf(packet
, sizeof(packet
),
410 "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n",
411 type
, state
, uri
, location
, info
, make_model
, interval
* 2,
414 fprintf(stderr
, "DEBUG2: %s Sending %s", prefix
, packet
);
416 if (sendto(sock
, packet
, strlen(packet
), 0,
417 (struct sockaddr
*)&addr
, sizeof(addr
)) <= 0)
420 perror("cups-polld");
425 * Throttle the local broadcasts as needed so that we don't
426 * overwhelm the local server...
430 if (count
>= max_count
)
433 * Sleep for a second...
441 if (!attr
|| restart_polling
)
449 * Return the number of seconds we used...
452 return (time(NULL
) - seconds
);
457 * 'sighup_handler()' - Handle 'hangup' signals to restart polling.
461 sighup_handler(int sig
) /* I - Signal number */
467 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
468 signal(SIGHUP
, sighup_handler
);
469 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
474 * End of "$Id: cups-polld.c 7198 2008-01-08 00:12:17Z mike $".