]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cups-polld.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / scheduler / cups-polld.c
CommitLineData
ef416fc2 1/*
c07d5b2d 2 * "$Id: cups-polld.c 177 2006-06-21 00:20:03Z jlovell $"
ef416fc2 3 *
4 * Polling daemon for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
7 *
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
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Open sockets and poll until we are killed...
27 * poll_server() - Poll the server for the given set of printers or classes.
28 */
29
30/*
31 * Include necessary headers...
32 */
33
34#include <cups/http-private.h>
35#include <cups/cups.h>
36#include <stdlib.h>
37#include <errno.h>
38#include <cups/language.h>
39#include <cups/string.h>
40
41
42/*
43 * Local functions...
44 */
45
e1d6a774 46static int poll_server(http_t *http, cups_lang_t *language, ipp_op_t op,
47 int sock, int port, int interval,
48 const char *prefix);
ef416fc2 49
50
51/*
52 * 'main()' - Open sockets and poll until we are killed...
53 */
54
55int /* O - Exit status */
56main(int argc, /* I - Number of command-line arguments */
57 char *argv[]) /* I - Command-line arguments */
58{
59 http_t *http; /* HTTP connection */
60 cups_lang_t *language; /* Language info */
61 int interval; /* Polling interval */
62 int sock; /* Browser sock */
63 int port; /* Browser port */
64 int val; /* Socket option value */
65 int seconds, /* Seconds left from poll */
66 remain; /* Total remaining time to sleep */
67 char prefix[1024]; /* Prefix for log messages */
68
69
70 /*
71 * Don't buffer log messages...
72 */
73
74 setbuf(stderr, NULL);
75
76 /*
77 * The command-line must contain the following:
78 *
79 * cups-polld server server-port interval port
80 */
81
82 if (argc != 5)
83 {
84 fputs("Usage: cups-polld server server-port interval port\n", stderr);
85 return (1);
86 }
87
88 interval = atoi(argv[3]);
89 port = atoi(argv[4]);
90
91 if (interval < 2)
92 interval = 2;
93
94 snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2]));
95
96 /*
97 * Open a broadcast socket...
98 */
99
100 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
101 {
102 fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix,
103 strerror(errno));
104 return (1);
105 }
106
107 /*
108 * Set the "broadcast" flag...
109 */
110
111 val = 1;
112 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
113 {
114 fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
115 prefix, strerror(errno));
116
117 close(sock);
118 return (1);
119 }
120
121 /*
122 * Open a connection to the server...
123 */
124
125 while ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
126 cupsEncryption())) == NULL)
127 {
128 fprintf(stderr, "ERROR: %s Unable to connect to %s on port %s: %s\n",
129 prefix, argv[1], argv[2],
130 h_errno ? hstrerror(h_errno) : strerror(errno));
131 sleep (interval);
132 }
133
134 /*
135 * Loop forever, asking for available printers and classes...
136 */
137
138 language = cupsLangDefault();
139
140 for (;;)
141 {
142 /*
143 * Get the printers, then the classes...
144 */
145
146 remain = interval;
147
148 if ((seconds = poll_server(http, language, CUPS_GET_PRINTERS, sock, port,
149 interval, prefix)) > 0)
150 remain -= seconds;
151
152 /*
153 * Sleep for any remaining time...
154 */
155
156 if (remain > 0)
157 sleep(remain);
158 }
159}
160
161
162/*
163 * 'poll_server()' - Poll the server for the given set of printers or classes.
164 */
165
e1d6a774 166static int /* O - Number of seconds or -1 on error */
ef416fc2 167poll_server(http_t *http, /* I - HTTP connection */
168 cups_lang_t *language, /* I - Language */
169 ipp_op_t op, /* I - Operation code */
170 int sock, /* I - Broadcast sock */
171 int port, /* I - Broadcast port */
172 int interval, /* I - Polling interval */
173 const char *prefix) /* I - Prefix for log messages */
174{
175 int seconds; /* Number of seconds */
176 int count, /* Current number of printers/classes */
177 max_count; /* Maximum printers/classes per second */
178 ipp_t *request, /* Request data */
179 *response; /* Response data */
180 ipp_attribute_t *attr; /* Current attribute */
181 const char *uri, /* printer-uri */
182 *info, /* printer-info */
183 *location, /* printer-location */
184 *make_model; /* printer-make-and-model */
185 cups_ptype_t type; /* printer-type */
186 ipp_pstate_t state; /* printer-state */
187 int accepting; /* printer-is-accepting-jobs */
188 struct sockaddr_in addr; /* Broadcast address */
189 char packet[1540]; /* Data packet */
190 static const char * const attrs[] = /* Requested attributes */
191 {
192 "printer-info",
193 "printer-is-accepting-jobs",
194 "printer-location",
195 "printer-make-and-model",
196 "printer-name",
197 "printer-state",
198 "printer-type",
199 "printer-uri-supported"
200 };
201
202
203 /*
204 * Broadcast to 127.0.0.1 (localhost)
205 */
206
207 memset(&addr, 0, sizeof(addr));
208 addr.sin_addr.s_addr = htonl(0x7f000001);
209 addr.sin_family = AF_INET;
210 addr.sin_port = htons(port);
211
212 /*
213 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which requires
214 * only the attributes-charset and attributes-natural-language attributes.
215 */
216
217 request = ippNew();
218
219 request->request.op.operation_id = op;
220 request->request.op.request_id = 1;
221
222 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
223 "attributes-charset", NULL, cupsLangEncoding(language));
224
225 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
226 "attributes-natural-language", NULL, language->language);
227
228 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
229 "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
230 NULL, attrs);
231
232 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
233 "printer-type", 0);
234 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
235 "printer-type-mask",
236 CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
237 CUPS_PRINTER_NOT_SHARED);
238
239 /*
240 * Do the request and get back a response...
241 */
242
243 if ((response = cupsDoRequest(http, request, "/")) != NULL)
244 {
245 if (response->request.status.status_code > IPP_OK_CONFLICT)
246 {
247 fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix,
248 op == CUPS_GET_PRINTERS ? "printers" : "classes",
249 ippErrorString(response->request.status.status_code));
250 ippDelete(response);
251 return (-1);
252 }
253
254 /*
255 * Figure out how many printers/classes we have...
256 */
257
258 for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME),
259 max_count = 0;
260 attr != NULL;
261 attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME),
262 max_count ++);
263
264 fprintf(stderr, "DEBUG: %s found %d %s.\n", prefix, max_count,
265 op == CUPS_GET_PRINTERS ? "printers" : "classes");
266
267 count = 0;
268 seconds = time(NULL);
269 max_count = max_count / interval + 1;
270
271 /*
272 * Loop through the printers or classes returned in the list...
273 */
274
275 for (attr = response->attrs; attr != NULL; attr = attr->next)
276 {
277 /*
278 * Skip leading attributes until we hit a printer...
279 */
280
281 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
282 attr = attr->next;
283
284 if (attr == NULL)
285 break;
286
287 /*
288 * Pull the needed attributes from this printer...
289 */
290
291 uri = NULL;
292 info = "";
293 location = "";
294 make_model = "";
295 type = CUPS_PRINTER_REMOTE;
296 accepting = 1;
297 state = IPP_PRINTER_IDLE;
298
299 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
300 {
301 if (strcmp(attr->name, "printer-uri-supported") == 0 &&
302 attr->value_tag == IPP_TAG_URI)
303 uri = attr->values[0].string.text;
304
305 if (strcmp(attr->name, "printer-info") == 0 &&
306 attr->value_tag == IPP_TAG_TEXT)
307 info = attr->values[0].string.text;
308
309 if (strcmp(attr->name, "printer-is-accepting-jobs") == 0 &&
310 attr->value_tag == IPP_TAG_BOOLEAN)
311 accepting = attr->values[0].boolean;
312
313 if (strcmp(attr->name, "printer-location") == 0 &&
314 attr->value_tag == IPP_TAG_TEXT)
315 location = attr->values[0].string.text;
316
317 if (strcmp(attr->name, "printer-make-and-model") == 0 &&
318 attr->value_tag == IPP_TAG_TEXT)
319 make_model = attr->values[0].string.text;
320
321 if (strcmp(attr->name, "printer-state") == 0 &&
322 attr->value_tag == IPP_TAG_ENUM)
323 state = (ipp_pstate_t)attr->values[0].integer;
324
325 if (strcmp(attr->name, "printer-type") == 0 &&
326 attr->value_tag == IPP_TAG_ENUM)
327 type = (cups_ptype_t)attr->values[0].integer;
328
329 attr = attr->next;
330 }
331
332 /*
333 * See if we have everything needed...
334 */
335
336 if (uri == NULL)
337 {
338 if (attr == NULL)
339 break;
340 else
341 continue;
342 }
343
344 /*
345 * Send the printer information...
346 */
347
348 type |= CUPS_PRINTER_REMOTE;
349
350 if (!accepting)
351 type |= CUPS_PRINTER_REJECTING;
352
353 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
354 type, state, uri, location, info, make_model);
355
356 fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet);
357
358 if (sendto(sock, packet, strlen(packet), 0,
359 (struct sockaddr *)&addr, sizeof(addr)) <= 0)
360 {
361 ippDelete(response);
362 perror("cups-polld");
363 return (-1);
364 }
365
366 /*
367 * Throttle the local broadcasts as needed so that we don't
368 * overwhelm the local server...
369 */
370
371 count ++;
372 if (count >= max_count)
373 {
374 /*
375 * Sleep for a second...
376 */
377
378 count = 0;
379 sleep(1);
380 }
381
382 if (attr == NULL)
383 break;
384 }
385
386 ippDelete(response);
387 }
388 else
389 {
390 fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix,
391 op == CUPS_GET_PRINTERS ? "printers" : "classes",
392 ippErrorString(cupsLastError()));
393 return (-1);
394 }
395
396 /*
397 * Return the number of seconds we used...
398 */
399
400 return (time(NULL) - seconds);
401}
402
403
404/*
c07d5b2d 405 * End of "$Id: cups-polld.c 177 2006-06-21 00:20:03Z jlovell $".
ef416fc2 406 */