]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cups-polld.c
2 * "$Id: cups-polld.c 5871 2006-08-23 20:55:33Z mike $"
4 * Polling daemon for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Open sockets and poll until we are killed...
27 * dequote() - Remote quotes from a string.
28 * poll_server() - Poll the server for the given set of printers or
30 * sighup_handler() - Handle 'hangup' signals to restart polling.
34 * Include necessary headers...
37 #include <cups/http-private.h>
38 #include <cups/cups.h>
41 #include <cups/language.h>
42 #include <cups/string.h>
50 static int restart_polling
= 1;
57 static char *dequote(char *d
, const char *s
, int dlen
);
58 static int poll_server(http_t
*http
, int sock
, int port
, int interval
,
60 static void sighup_handler(int sig
);
64 * 'main()' - Open sockets and poll until we are killed...
67 int /* O - Exit status */
68 main(int argc
, /* I - Number of command-line args */
69 char *argv
[]) /* I - Command-line arguments */
71 http_t
*http
; /* HTTP connection */
72 int interval
; /* Polling interval */
73 int sock
; /* Browser sock */
74 int port
; /* Browser port */
75 int val
; /* Socket option value */
76 int seconds
, /* Seconds left from poll */
77 remain
; /* Total remaining time to sleep */
78 char prefix
[1024]; /* Prefix for log messages */
79 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
80 struct sigaction action
; /* Actions for POSIX signals */
81 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
85 * Catch hangup signals for when the network changes...
88 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
89 sigset(SIGHUP
, sighup_handler
);
90 #elif defined(HAVE_SIGACTION)
91 memset(&action
, 0, sizeof(action
));
93 sigemptyset(&action
.sa_mask
);
94 sigaddset(&action
.sa_mask
, SIGHUP
);
95 action
.sa_handler
= sighup_handler
;
96 sigaction(SIGHUP
, &action
, NULL
);
98 signal(SIGHUP
, sighup_handler
);
99 #endif /* HAVE_SIGSET */
102 * Don't buffer log messages...
105 setbuf(stderr
, NULL
);
108 * The command-line must contain the following:
110 * cups-polld server server-port interval port
115 fputs("Usage: cups-polld server server-port interval port\n", stderr
);
119 interval
= atoi(argv
[3]);
120 port
= atoi(argv
[4]);
125 snprintf(prefix
, sizeof(prefix
), "[cups-polld %s:%d]", argv
[1], atoi(argv
[2]));
128 * Open a broadcast socket...
131 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
133 fprintf(stderr
, "ERROR: %s Unable to open broadcast socket: %s\n", prefix
,
139 * Set the "broadcast" flag...
143 if (setsockopt(sock
, SOL_SOCKET
, SO_BROADCAST
, &val
, sizeof(val
)))
145 fprintf(stderr
, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
146 prefix
, strerror(errno
));
153 * Loop forever, asking for available printers and classes...
159 * Open a connection to the server...
162 if (restart_polling
|| !http
)
167 if ((http
= httpConnectEncrypt(argv
[1], atoi(argv
[2]),
168 cupsEncryption())) == NULL
)
170 fprintf(stderr
, "ERROR: %s Unable to connect to %s on port %s: %s\n",
171 prefix
, argv
[1], argv
[2],
172 h_errno
? hstrerror(h_errno
) : strerror(errno
));
177 * Get the printers and classes...
182 if (http
&& (seconds
= poll_server(http
, sock
, port
, interval
, prefix
)) > 0)
186 * Sleep for any remaining time...
189 if (remain
> 0 && !restart_polling
)
196 * 'dequote()' - Remote quotes from a string.
199 static char * /* O - Dequoted string */
200 dequote(char *d
, /* I - Destination string */
201 const char *s
, /* I - Source string */
202 int dlen
) /* I - Destination length */
204 char *dptr
; /* Pointer into destination */
209 for (dptr
= d
, dlen
--; *s
&& dlen
> 0; s
++)
226 * 'poll_server()' - Poll the server for the given set of printers or classes.
229 static int /* O - Number of seconds or -1 on error */
230 poll_server(http_t
*http
, /* I - HTTP connection */
231 int sock
, /* I - Broadcast sock */
232 int port
, /* I - Broadcast port */
233 int interval
, /* I - Polling interval */
234 const char *prefix
) /* I - Prefix for log messages */
236 int seconds
; /* Number of seconds */
237 int count
, /* Current number of printers/classes */
238 max_count
; /* Maximum printers/classes per second */
239 ipp_t
*request
, /* Request data */
240 *response
; /* Response data */
241 ipp_attribute_t
*attr
; /* Current attribute */
242 const char *uri
; /* printer-uri */
243 char info
[1024], /* printer-info */
244 job_sheets
[1024],/* job-sheets-default */
245 location
[1024], /* printer-location */
247 /* printer-make-and-model */
248 cups_ptype_t type
; /* printer-type */
249 ipp_pstate_t state
; /* printer-state */
250 int accepting
; /* printer-is-accepting-jobs */
251 struct sockaddr_in addr
; /* Broadcast address */
252 char packet
[1540]; /* Data packet */
253 static const char * const attrs
[] = /* Requested attributes */
255 "job-sheets-default",
257 "printer-is-accepting-jobs",
259 "printer-make-and-model",
263 "printer-uri-supported"
268 * Broadcast to 127.0.0.1 (localhost)
271 memset(&addr
, 0, sizeof(addr
));
272 addr
.sin_addr
.s_addr
= htonl(0x7f000001);
273 addr
.sin_family
= AF_INET
;
274 addr
.sin_port
= htons(port
);
277 * Build a CUPS_GET_PRINTERS request and pass along a list of the
278 * attributes we are interested in along with the types of printers
279 * (and classes) we want.
282 request
= ippNewRequest(CUPS_GET_PRINTERS
);
284 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
285 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
288 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
290 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
292 CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
293 CUPS_PRINTER_NOT_SHARED
);
296 * Do the request and get back a response...
299 seconds
= time(NULL
);
300 response
= cupsDoRequest(http
, request
, "/");
302 if (cupsLastError() > IPP_OK_CONFLICT
)
304 fprintf(stderr
, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix
,
305 cupsLastErrorString());
313 * Figure out how many printers/classes we have...
316 for (attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
),
319 attr
= ippFindNextAttribute(response
, "printer-name", IPP_TAG_NAME
),
322 fprintf(stderr
, "DEBUG: %s Found %d printers.\n", prefix
, max_count
);
325 max_count
= max_count
/ interval
+ 1;
328 * Loop through the printers or classes returned in the list...
331 for (attr
= response
->attrs
; attr
; attr
= attr
->next
)
334 * Skip leading attributes until we hit a printer...
337 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
344 * Pull the needed attributes from this printer...
349 job_sheets
[0] = '\0';
351 make_model
[0] = '\0';
352 type
= CUPS_PRINTER_REMOTE
;
354 state
= IPP_PRINTER_IDLE
;
356 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
358 if (!strcmp(attr
->name
, "job-sheets-default") &&
359 (attr
->value_tag
== IPP_TAG_NAME
||
360 attr
->value_tag
== IPP_TAG_KEYWORD
))
362 if (attr
->num_values
== 1)
363 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s",
364 attr
->values
[0].string
.text
);
366 snprintf(job_sheets
, sizeof(job_sheets
), " job-sheets=%s,%s",
367 attr
->values
[0].string
.text
,
368 attr
->values
[1].string
.text
);
370 else if (!strcmp(attr
->name
, "printer-uri-supported") &&
371 attr
->value_tag
== IPP_TAG_URI
)
372 uri
= attr
->values
[0].string
.text
;
373 else if (!strcmp(attr
->name
, "printer-info") &&
374 attr
->value_tag
== IPP_TAG_TEXT
)
375 dequote(info
, attr
->values
[0].string
.text
, sizeof(info
));
376 else if (!strcmp(attr
->name
, "printer-is-accepting-jobs") &&
377 attr
->value_tag
== IPP_TAG_BOOLEAN
)
378 accepting
= attr
->values
[0].boolean
;
379 else if (!strcmp(attr
->name
, "printer-location") &&
380 attr
->value_tag
== IPP_TAG_TEXT
)
381 dequote(location
, attr
->values
[0].string
.text
, sizeof(location
));
382 else if (!strcmp(attr
->name
, "printer-make-and-model") &&
383 attr
->value_tag
== IPP_TAG_TEXT
)
384 dequote(make_model
, attr
->values
[0].string
.text
, sizeof(location
));
385 else if (!strcmp(attr
->name
, "printer-state") &&
386 attr
->value_tag
== IPP_TAG_ENUM
)
387 state
= (ipp_pstate_t
)attr
->values
[0].integer
;
388 else if (!strcmp(attr
->name
, "printer-type") &&
389 attr
->value_tag
== IPP_TAG_ENUM
)
390 type
= (cups_ptype_t
)attr
->values
[0].integer
;
396 * See if we have everything needed...
408 * Send the printer information...
411 type
|= CUPS_PRINTER_REMOTE
;
414 type
|= CUPS_PRINTER_REJECTING
;
416 snprintf(packet
, sizeof(packet
),
417 "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n",
418 type
, state
, uri
, location
, info
, make_model
, interval
* 2,
421 fprintf(stderr
, "DEBUG2: %s Sending %s", prefix
, packet
);
423 if (sendto(sock
, packet
, strlen(packet
), 0,
424 (struct sockaddr
*)&addr
, sizeof(addr
)) <= 0)
427 perror("cups-polld");
432 * Throttle the local broadcasts as needed so that we don't
433 * overwhelm the local server...
437 if (count
>= max_count
)
440 * Sleep for a second...
448 if (!attr
|| restart_polling
)
456 * Return the number of seconds we used...
459 return (time(NULL
) - seconds
);
464 * 'sighup_handler()' - Handle 'hangup' signals to restart polling.
468 sighup_handler(int sig
) /* I - Signal number */
474 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
475 signal(SIGHUP
, sighup_handler
);
476 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
481 * End of "$Id: cups-polld.c 5871 2006-08-23 20:55:33Z mike $".