]>
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 CUPS.
6 * Copyright 2007-2011 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/cups-private.h>
36 static int restart_polling
= 1;
43 static char *dequote(char *d
, const char *s
, int dlen
);
44 static int poll_server(http_t
*http
, int sock
, int port
, int interval
,
46 static void sighup_handler(int sig
);
50 * 'main()' - Open sockets and poll until we are killed...
53 int /* O - Exit status */
54 main(int argc
, /* I - Number of command-line args */
55 char *argv
[]) /* I - Command-line arguments */
57 http_t
*http
; /* HTTP connection */
58 int interval
; /* Polling interval */
59 int sock
; /* Browser sock */
60 int port
; /* Browser port */
61 int val
; /* Socket option value */
62 int seconds
, /* Seconds left from poll */
63 remain
; /* Total remaining time to sleep */
64 char prefix
[1024]; /* Prefix for log messages */
65 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
66 struct sigaction action
; /* Actions for POSIX signals */
67 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
71 * Catch hangup signals for when the network changes...
74 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
75 sigset(SIGHUP
, sighup_handler
);
76 #elif defined(HAVE_SIGACTION)
77 memset(&action
, 0, sizeof(action
));
79 sigemptyset(&action
.sa_mask
);
80 sigaddset(&action
.sa_mask
, SIGHUP
);
81 action
.sa_handler
= sighup_handler
;
82 sigaction(SIGHUP
, &action
, NULL
);
84 signal(SIGHUP
, sighup_handler
);
85 #endif /* HAVE_SIGSET */
88 * Don't buffer log messages...
94 * The command-line must contain the following:
96 * cups-polld server server-port interval port
101 fputs("Usage: cups-polld server server-port interval port\n", stderr
);
105 interval
= atoi(argv
[3]);
106 port
= atoi(argv
[4]);
111 snprintf(prefix
, sizeof(prefix
), "[cups-polld %s:%d]", argv
[1], atoi(argv
[2]));
114 * Open a broadcast socket...
117 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
119 fprintf(stderr
, "ERROR: %s Unable to open broadcast socket: %s\n", prefix
,
125 * Set the "broadcast" flag...
129 if (setsockopt(sock
, SOL_SOCKET
, SO_BROADCAST
, &val
, sizeof(val
)))
131 fprintf(stderr
, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
132 prefix
, strerror(errno
));
139 * Loop forever, asking for available printers and classes...
142 for (http
= NULL
; !ferror(stderr
);)
145 * Open a connection to the server...
148 if (restart_polling
|| !http
)
153 if ((http
= httpConnectEncrypt(argv
[1], atoi(argv
[2]),
154 cupsEncryption())) == NULL
)
156 fprintf(stderr
, "ERROR: %s Unable to connect to %s on port %s: %s\n",
157 prefix
, argv
[1], argv
[2],
158 h_errno
? hstrerror(h_errno
) : strerror(errno
));
163 * Get the printers and classes...
168 if (http
&& (seconds
= poll_server(http
, sock
, port
, interval
, prefix
)) > 0)
172 * Sleep for any remaining time...
175 if (remain
> 0 && !restart_polling
)
184 * 'dequote()' - Remote quotes from a string.
187 static char * /* O - Dequoted string */
188 dequote(char *d
, /* I - Destination string */
189 const char *s
, /* I - Source string */
190 int dlen
) /* I - Destination length */
192 char *dptr
; /* Pointer into destination */
197 for (dptr
= d
, dlen
--; *s
&& dlen
> 0; s
++)
214 * 'poll_server()' - Poll the server for the given set of printers or classes.
217 static int /* O - Number of seconds or -1 on error */
218 poll_server(http_t
*http
, /* I - HTTP connection */
219 int sock
, /* I - Broadcast sock */
220 int port
, /* I - Broadcast port */
221 int interval
, /* I - Polling interval */
222 const char *prefix
) /* I - Prefix for log messages */
224 int seconds
; /* Number of seconds */
225 int count
, /* Current number of printers/classes */
226 max_count
; /* Maximum printers/classes per second */
227 ipp_t
*request
, /* Request data */
228 *response
; /* Response data */
229 ipp_attribute_t
*attr
; /* Current attribute */
230 const char *uri
; /* printer-uri */
231 char info
[1024], /* printer-info */
232 job_sheets
[1024],/* job-sheets-default */
233 location
[1024], /* printer-location */
235 /* printer-make-and-model */
236 cups_ptype_t type
; /* printer-type */
237 ipp_pstate_t state
; /* printer-state */
238 int accepting
; /* printer-is-accepting-jobs */
239 struct sockaddr_in addr
; /* Broadcast address */
240 char packet
[1540]; /* Data packet */
241 static const char * const attrs
[] = /* Requested attributes */
243 "job-sheets-default",
245 "printer-is-accepting-jobs",
247 "printer-make-and-model",
251 "printer-uri-supported"
256 * Broadcast to 127.0.0.1 (localhost)
259 memset(&addr
, 0, sizeof(addr
));
260 addr
.sin_addr
.s_addr
= htonl(0x7f000001);
261 addr
.sin_family
= AF_INET
;
262 addr
.sin_port
= htons(port
);
265 * Build a CUPS_GET_PRINTERS request and pass along a list of the
266 * attributes we are interested in along with the types of printers
267 * (and classes) we want.
270 request
= ippNewRequest(CUPS_GET_PRINTERS
);
272 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
273 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
276 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
278 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
280 CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
281 CUPS_PRINTER_NOT_SHARED
);
284 * Do the request and get back a response...
287 seconds
= time(NULL
);
288 response
= cupsDoRequest(http
, request
, "/");
290 if (cupsLastError() > IPP_OK_CONFLICT
)
292 fprintf(stderr
, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix
,
293 cupsLastErrorString());
301 * Figure out how many printers/classes we have...
304 for (attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
),
307 attr
= ippFindNextAttribute(response
, "printer-name", IPP_TAG_NAME
),
310 fprintf(stderr
, "DEBUG: %s Found %d printers.\n", prefix
, max_count
);
313 max_count
= 2 * max_count
/ interval
+ 1;
316 * Loop through the printers or classes returned in the list...
319 for (attr
= response
->attrs
; attr
; attr
= attr
->next
)
322 * Skip leading attributes until we hit a printer...
325 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
332 * Pull the needed attributes from this printer...
337 job_sheets
[0] = '\0';
339 make_model
[0] = '\0';
340 type
= CUPS_PRINTER_REMOTE
;
342 state
= IPP_PRINTER_IDLE
;
344 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
346 if (!strcmp(attr
->name
, "job-sheets-default") &&
347 (attr
->value_tag
== IPP_TAG_NAME
||
348 attr
->value_tag
== IPP_TAG_KEYWORD
))
350 if (attr
->num_values
== 1)
351 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s",
352 attr
->values
[0].string
.text
);
354 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s,%s",
355 attr
->values
[0].string
.text
,
356 attr
->values
[1].string
.text
);
358 else if (!strcmp(attr
->name
, "printer-uri-supported") &&
359 attr
->value_tag
== IPP_TAG_URI
)
360 uri
= attr
->values
[0].string
.text
;
361 else if (!strcmp(attr
->name
, "printer-info") &&
362 attr
->value_tag
== IPP_TAG_TEXT
)
363 dequote(info
, attr
->values
[0].string
.text
, sizeof(info
));
364 else if (!strcmp(attr
->name
, "printer-is-accepting-jobs") &&
365 attr
->value_tag
== IPP_TAG_BOOLEAN
)
366 accepting
= attr
->values
[0].boolean
;
367 else if (!strcmp(attr
->name
, "printer-location") &&
368 attr
->value_tag
== IPP_TAG_TEXT
)
369 dequote(location
, attr
->values
[0].string
.text
, sizeof(location
));
370 else if (!strcmp(attr
->name
, "printer-make-and-model") &&
371 attr
->value_tag
== IPP_TAG_TEXT
)
372 dequote(make_model
, attr
->values
[0].string
.text
, sizeof(location
));
373 else if (!strcmp(attr
->name
, "printer-state") &&
374 attr
->value_tag
== IPP_TAG_ENUM
)
375 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
376 else if (!strcmp(attr
->name
, "printer-type") &&
377 attr
->value_tag
== IPP_TAG_ENUM
)
378 type
= (cups_ptype_t
)attr
->values
[0].integer
;
384 * See if we have everything needed...
396 * Send the printer information...
399 type
|= CUPS_PRINTER_REMOTE
;
402 type
|= CUPS_PRINTER_REJECTING
;
404 snprintf(packet
, sizeof(packet
),
405 "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n",
406 type
, state
, uri
, location
, info
, make_model
, interval
* 2,
409 fprintf(stderr
, "DEBUG2: %s Sending %s", prefix
, packet
);
411 if (sendto(sock
, packet
, strlen(packet
), 0,
412 (struct sockaddr
*)&addr
, sizeof(addr
)) <= 0)
415 perror("cups-polld");
420 * Throttle the local broadcasts as needed so that we don't
421 * overwhelm the local server...
425 if (count
>= max_count
)
428 * Sleep for a second...
436 if (!attr
|| restart_polling
)
444 * Return the number of seconds we used...
447 return (time(NULL
) - seconds
);
452 * 'sighup_handler()' - Handle 'hangup' signals to restart polling.
456 sighup_handler(int sig
) /* I - Signal number */
462 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
463 signal(SIGHUP
, sighup_handler
);
464 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
469 * End of "$Id: cups-polld.c 7198 2008-01-08 00:12:17Z mike $".