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