]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cups-polld.c
Remove old files.
[thirdparty/cups.git] / scheduler / cups-polld.c
CommitLineData
ef416fc2 1/*
bc44d920 2 * "$Id: cups-polld.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * Polling daemon for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 by Apple Inc.
8ca02f3c 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 14 *
15 * Contents:
16 *
d09495fa 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
20 * classes.
21 * sighup_handler() - Handle 'hangup' signals to restart polling.
ef416fc2 22 */
23
24/*
25 * Include necessary headers...
26 */
27
28#include <cups/http-private.h>
29#include <cups/cups.h>
30#include <stdlib.h>
31#include <errno.h>
32#include <cups/language.h>
33#include <cups/string.h>
d09495fa 34#include <signal.h>
35
36
37/*
38 * Local globals...
39 */
40
41static int restart_polling = 1;
ef416fc2 42
43
44/*
45 * Local functions...
46 */
47
8ca02f3c 48static char *dequote(char *d, const char *s, int dlen);
49static int poll_server(http_t *http, int sock, int port, int interval,
e1d6a774 50 const char *prefix);
d09495fa 51static void sighup_handler(int sig);
ef416fc2 52
53
54/*
55 * 'main()' - Open sockets and poll until we are killed...
56 */
57
58int /* O - Exit status */
8ca02f3c 59main(int argc, /* I - Number of command-line args */
ef416fc2 60 char *argv[]) /* I - Command-line arguments */
61{
8ca02f3c 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 */
d09495fa 70#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
71 struct sigaction action; /* Actions for POSIX signals */
72#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
ef416fc2 73
74
d09495fa 75 /*
76 * Catch hangup signals for when the network changes...
77 */
78
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));
83
84 sigemptyset(&action.sa_mask);
85 sigaddset(&action.sa_mask, SIGHUP);
86 action.sa_handler = sighup_handler;
87 sigaction(SIGHUP, &action, NULL);
88#else
89 signal(SIGHUP, sighup_handler);
90#endif /* HAVE_SIGSET */
91
ef416fc2 92 /*
93 * Don't buffer log messages...
94 */
95
96 setbuf(stderr, NULL);
97
98 /*
99 * The command-line must contain the following:
100 *
101 * cups-polld server server-port interval port
102 */
103
104 if (argc != 5)
105 {
106 fputs("Usage: cups-polld server server-port interval port\n", stderr);
107 return (1);
108 }
109
110 interval = atoi(argv[3]);
111 port = atoi(argv[4]);
112
113 if (interval < 2)
114 interval = 2;
115
116 snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2]));
117
118 /*
119 * Open a broadcast socket...
120 */
121
122 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
123 {
124 fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix,
125 strerror(errno));
126 return (1);
127 }
128
129 /*
130 * Set the "broadcast" flag...
131 */
132
133 val = 1;
134 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
135 {
136 fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
137 prefix, strerror(errno));
138
139 close(sock);
140 return (1);
141 }
142
143 /*
d09495fa 144 * Loop forever, asking for available printers and classes...
ef416fc2 145 */
146
080811b1 147 for (http = NULL; !ferror(stderr);)
ef416fc2 148 {
d09495fa 149 /*
150 * Open a connection to the server...
151 */
ef416fc2 152
d09495fa 153 if (restart_polling || !http)
154 {
155 restart_polling = 0;
156 httpClose(http);
157
158 if ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
159 cupsEncryption())) == NULL)
160 {
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));
164 }
165 }
ef416fc2 166
ef416fc2 167 /*
8ca02f3c 168 * Get the printers and classes...
ef416fc2 169 */
170
171 remain = interval;
172
d09495fa 173 if (http && (seconds = poll_server(http, sock, port, interval, prefix)) > 0)
ef416fc2 174 remain -= seconds;
175
176 /*
177 * Sleep for any remaining time...
178 */
179
d09495fa 180 if (remain > 0 && !restart_polling)
ef416fc2 181 sleep(remain);
182 }
080811b1
MS
183
184 return (1);
ef416fc2 185}
186
187
8ca02f3c 188/*
189 * 'dequote()' - Remote quotes from a string.
190 */
191
192static char * /* O - Dequoted string */
193dequote(char *d, /* I - Destination string */
194 const char *s, /* I - Source string */
195 int dlen) /* I - Destination length */
196{
197 char *dptr; /* Pointer into destination */
198
199
200 if (s)
201 {
202 for (dptr = d, dlen --; *s && dlen > 0; s ++)
203 if (*s != '\"')
204 {
205 *dptr++ = *s;
206 dlen --;
207 }
208
209 *dptr = '\0';
210 }
211 else
212 *d = '\0';
213
214 return (d);
215}
216
217
ef416fc2 218/*
219 * 'poll_server()' - Poll the server for the given set of printers or classes.
220 */
221
e1d6a774 222static int /* O - Number of seconds or -1 on error */
ef416fc2 223poll_server(http_t *http, /* I - HTTP connection */
ef416fc2 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 */
228{
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 */
8ca02f3c 235 const char *uri; /* printer-uri */
236 char info[1024], /* printer-info */
237 job_sheets[1024],/* job-sheets-default */
238 location[1024], /* printer-location */
239 make_model[1024];
240 /* printer-make-and-model */
ef416fc2 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 */
247 {
8ca02f3c 248 "job-sheets-default",
ef416fc2 249 "printer-info",
250 "printer-is-accepting-jobs",
251 "printer-location",
252 "printer-make-and-model",
253 "printer-name",
254 "printer-state",
255 "printer-type",
256 "printer-uri-supported"
257 };
258
259
260 /*
261 * Broadcast to 127.0.0.1 (localhost)
262 */
263
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);
268
269 /*
8ca02f3c 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.
ef416fc2 273 */
274
8ca02f3c 275 request = ippNewRequest(CUPS_GET_PRINTERS);
ef416fc2 276
277 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
278 "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
279 NULL, attrs);
280
281 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
282 "printer-type", 0);
283 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
284 "printer-type-mask",
285 CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
286 CUPS_PRINTER_NOT_SHARED);
287
288 /*
289 * Do the request and get back a response...
290 */
291
d09495fa 292 seconds = time(NULL);
8ca02f3c 293 response = cupsDoRequest(http, request, "/");
294
295 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 296 {
8ca02f3c 297 fprintf(stderr, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix,
298 cupsLastErrorString());
299 ippDelete(response);
300 return (-1);
301 }
ef416fc2 302
8ca02f3c 303 if (response)
304 {
ef416fc2 305 /*
306 * Figure out how many printers/classes we have...
307 */
308
309 for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME),
310 max_count = 0;
311 attr != NULL;
312 attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME),
313 max_count ++);
314
8ca02f3c 315 fprintf(stderr, "DEBUG: %s Found %d printers.\n", prefix, max_count);
ef416fc2 316
317 count = 0;
ef416fc2 318 max_count = max_count / interval + 1;
319
320 /*
321 * Loop through the printers or classes returned in the list...
322 */
323
8ca02f3c 324 for (attr = response->attrs; attr; attr = attr->next)
ef416fc2 325 {
326 /*
327 * Skip leading attributes until we hit a printer...
328 */
329
8ca02f3c 330 while (attr && attr->group_tag != IPP_TAG_PRINTER)
ef416fc2 331 attr = attr->next;
332
8ca02f3c 333 if (!attr)
ef416fc2 334 break;
335
336 /*
337 * Pull the needed attributes from this printer...
338 */
339
8ca02f3c 340 uri = NULL;
341 info[0] = '\0';
342 job_sheets[0] = '\0';
343 location[0] = '\0';
344 make_model[0] = '\0';
345 type = CUPS_PRINTER_REMOTE;
346 accepting = 1;
347 state = IPP_PRINTER_IDLE;
ef416fc2 348
349 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
350 {
8ca02f3c 351 if (!strcmp(attr->name, "job-sheets-default") &&
352 (attr->value_tag == IPP_TAG_NAME ||
353 attr->value_tag == IPP_TAG_KEYWORD))
354 {
355 if (attr->num_values == 1)
356 snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s",
357 attr->values[0].string.text);
358 else
359 snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s,%s",
360 attr->values[0].string.text,
361 attr->values[1].string.text);
362 }
363 else if (!strcmp(attr->name, "printer-uri-supported") &&
364 attr->value_tag == IPP_TAG_URI)
ef416fc2 365 uri = attr->values[0].string.text;
8ca02f3c 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)
ef416fc2 371 accepting = attr->values[0].boolean;
8ca02f3c 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)
ef416fc2 380 state = (ipp_pstate_t)attr->values[0].integer;
8ca02f3c 381 else if (!strcmp(attr->name, "printer-type") &&
382 attr->value_tag == IPP_TAG_ENUM)
ef416fc2 383 type = (cups_ptype_t)attr->values[0].integer;
384
385 attr = attr->next;
386 }
387
388 /*
389 * See if we have everything needed...
390 */
391
392 if (uri == NULL)
393 {
394 if (attr == NULL)
395 break;
396 else
397 continue;
398 }
399
400 /*
401 * Send the printer information...
402 */
403
404 type |= CUPS_PRINTER_REMOTE;
405
406 if (!accepting)
407 type |= CUPS_PRINTER_REJECTING;
408
8ca02f3c 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,
412 job_sheets);
ef416fc2 413
414 fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet);
415
416 if (sendto(sock, packet, strlen(packet), 0,
417 (struct sockaddr *)&addr, sizeof(addr)) <= 0)
418 {
419 ippDelete(response);
420 perror("cups-polld");
421 return (-1);
422 }
423
424 /*
425 * Throttle the local broadcasts as needed so that we don't
426 * overwhelm the local server...
427 */
428
429 count ++;
430 if (count >= max_count)
431 {
432 /*
433 * Sleep for a second...
434 */
435
436 count = 0;
8ca02f3c 437
ef416fc2 438 sleep(1);
439 }
440
d09495fa 441 if (!attr || restart_polling)
ef416fc2 442 break;
443 }
444
445 ippDelete(response);
446 }
ef416fc2 447
448 /*
449 * Return the number of seconds we used...
450 */
451
452 return (time(NULL) - seconds);
453}
454
455
456/*
d09495fa 457 * 'sighup_handler()' - Handle 'hangup' signals to restart polling.
458 */
459
460static void
461sighup_handler(int sig) /* I - Signal number */
462{
463 (void)sig;
464
465 restart_polling = 1;
466
467#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
468 signal(SIGHUP, sighup_handler);
469#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
470}
471
472
473/*
bc44d920 474 * End of "$Id: cups-polld.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 475 */