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