]>
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.\n",
157 prefix
, argv
[1], argv
[2]);
162 * Get the printers and classes...
167 if (http
&& (seconds
= poll_server(http
, sock
, port
, interval
, prefix
)) > 0)
171 * Sleep for any remaining time...
174 if (remain
> 0 && !restart_polling
)
183 * 'dequote()' - Remote quotes from a string.
186 static char * /* O - Dequoted string */
187 dequote(char *d
, /* I - Destination string */
188 const char *s
, /* I - Source string */
189 int dlen
) /* I - Destination length */
191 char *dptr
; /* Pointer into destination */
196 for (dptr
= d
, dlen
--; *s
&& dlen
> 0; s
++)
213 * 'poll_server()' - Poll the server for the given set of printers or classes.
216 static int /* O - Number of seconds or -1 on error */
217 poll_server(http_t
*http
, /* I - HTTP connection */
218 int sock
, /* I - Broadcast sock */
219 int port
, /* I - Broadcast port */
220 int interval
, /* I - Polling interval */
221 const char *prefix
) /* I - Prefix for log messages */
223 int seconds
; /* Number of seconds */
224 int count
, /* Current number of printers/classes */
225 max_count
; /* Maximum printers/classes per second */
226 ipp_t
*request
, /* Request data */
227 *response
; /* Response data */
228 ipp_attribute_t
*attr
; /* Current attribute */
229 const char *uri
; /* printer-uri */
230 char info
[1024], /* printer-info */
231 job_sheets
[1024],/* job-sheets-default */
232 location
[1024], /* printer-location */
234 /* printer-make-and-model */
235 cups_ptype_t type
; /* printer-type */
236 ipp_pstate_t state
; /* printer-state */
237 int accepting
; /* printer-is-accepting-jobs */
238 struct sockaddr_in addr
; /* Broadcast address */
239 char packet
[1540]; /* Data packet */
240 static const char * const attrs
[] = /* Requested attributes */
242 "job-sheets-default",
244 "printer-is-accepting-jobs",
246 "printer-make-and-model",
250 "printer-uri-supported"
255 * Broadcast to 127.0.0.1 (localhost)
258 memset(&addr
, 0, sizeof(addr
));
259 addr
.sin_addr
.s_addr
= htonl(0x7f000001);
260 addr
.sin_family
= AF_INET
;
261 addr
.sin_port
= htons(port
);
264 * Build a CUPS_GET_PRINTERS request and pass along a list of the
265 * attributes we are interested in along with the types of printers
266 * (and classes) we want.
269 request
= ippNewRequest(CUPS_GET_PRINTERS
);
271 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
272 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
275 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
277 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
279 CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
280 CUPS_PRINTER_NOT_SHARED
);
283 * Do the request and get back a response...
286 seconds
= time(NULL
);
287 response
= cupsDoRequest(http
, request
, "/");
289 if (cupsLastError() > IPP_OK_CONFLICT
)
291 fprintf(stderr
, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix
,
292 cupsLastErrorString());
300 * Figure out how many printers/classes we have...
303 for (attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
),
306 attr
= ippFindNextAttribute(response
, "printer-name", IPP_TAG_NAME
),
309 fprintf(stderr
, "DEBUG: %s Found %d printers.\n", prefix
, max_count
);
312 max_count
= 2 * max_count
/ interval
+ 1;
315 * Loop through the printers or classes returned in the list...
318 for (attr
= response
->attrs
; attr
; attr
= attr
->next
)
321 * Skip leading attributes until we hit a printer...
324 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
331 * Pull the needed attributes from this printer...
336 job_sheets
[0] = '\0';
338 make_model
[0] = '\0';
339 type
= CUPS_PRINTER_REMOTE
;
341 state
= IPP_PRINTER_IDLE
;
343 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
345 if (!strcmp(attr
->name
, "job-sheets-default") &&
346 (attr
->value_tag
== IPP_TAG_NAME
||
347 attr
->value_tag
== IPP_TAG_KEYWORD
))
349 if (attr
->num_values
== 1)
350 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s",
351 attr
->values
[0].string
.text
);
353 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s,%s",
354 attr
->values
[0].string
.text
,
355 attr
->values
[1].string
.text
);
357 else if (!strcmp(attr
->name
, "printer-uri-supported") &&
358 attr
->value_tag
== IPP_TAG_URI
)
359 uri
= attr
->values
[0].string
.text
;
360 else if (!strcmp(attr
->name
, "printer-info") &&
361 attr
->value_tag
== IPP_TAG_TEXT
)
362 dequote(info
, attr
->values
[0].string
.text
, sizeof(info
));
363 else if (!strcmp(attr
->name
, "printer-is-accepting-jobs") &&
364 attr
->value_tag
== IPP_TAG_BOOLEAN
)
365 accepting
= attr
->values
[0].boolean
;
366 else if (!strcmp(attr
->name
, "printer-location") &&
367 attr
->value_tag
== IPP_TAG_TEXT
)
368 dequote(location
, attr
->values
[0].string
.text
, sizeof(location
));
369 else if (!strcmp(attr
->name
, "printer-make-and-model") &&
370 attr
->value_tag
== IPP_TAG_TEXT
)
371 dequote(make_model
, attr
->values
[0].string
.text
, sizeof(location
));
372 else if (!strcmp(attr
->name
, "printer-state") &&
373 attr
->value_tag
== IPP_TAG_ENUM
)
374 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
375 else if (!strcmp(attr
->name
, "printer-type") &&
376 attr
->value_tag
== IPP_TAG_ENUM
)
377 type
= (cups_ptype_t
)attr
->values
[0].integer
;
383 * See if we have everything needed...
395 * Send the printer information...
398 type
|= CUPS_PRINTER_REMOTE
;
401 type
|= CUPS_PRINTER_REJECTING
;
403 snprintf(packet
, sizeof(packet
),
404 "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n",
405 type
, state
, uri
, location
, info
, make_model
, interval
* 2,
408 fprintf(stderr
, "DEBUG2: %s Sending %s", prefix
, packet
);
410 if (sendto(sock
, packet
, strlen(packet
), 0,
411 (struct sockaddr
*)&addr
, sizeof(addr
)) <= 0)
414 perror("cups-polld");
419 * Throttle the local broadcasts as needed so that we don't
420 * overwhelm the local server...
424 if (count
>= max_count
)
427 * Sleep for a second...
435 if (!attr
|| restart_polling
)
443 * Return the number of seconds we used...
446 return (time(NULL
) - seconds
);
451 * 'sighup_handler()' - Handle 'hangup' signals to restart polling.
455 sighup_handler(int sig
) /* I - Signal number */
461 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
462 signal(SIGHUP
, sighup_handler
);
463 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
468 * End of "$Id: cups-polld.c 7198 2008-01-08 00:12:17Z mike $".