]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/runloop.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / backend / runloop.c
CommitLineData
ed486911 1/*
5a1d7a17 2 * Common run loop APIs for CUPS backends.
ed486911 3 *
7e86f2f6 4 * Copyright 2007-2014 by Apple Inc.
5a1d7a17 5 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
ed486911 6 *
5a1d7a17
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * "LICENSE" which should have been included with this file. If this
11 * file is missing or damaged, see the license at "http://www.cups.org/".
ed486911 12 */
13
14/*
15 * Include necessary headers.
16 */
17
18#include "backend-private.h"
568fa3fa 19#include <limits.h>
5a1d7a17 20#include <sys/select.h>
ed486911 21
22
09a101d6 23/*
24 * 'backendDrainOutput()' - Drain pending print data to the device.
25 */
26
27int /* O - 0 on success, -1 on error */
28backendDrainOutput(int print_fd, /* I - Print file descriptor */
29 int device_fd) /* I - Device file descriptor */
30{
31 int nfds; /* Maximum file descriptor value + 1 */
32 fd_set input; /* Input set for reading */
33 ssize_t print_bytes, /* Print bytes read */
34 bytes; /* Bytes written */
35 char print_buffer[8192], /* Print data buffer */
36 *print_ptr; /* Pointer into print data buffer */
37 struct timeval timeout; /* Timeout for read... */
38
39
40 fprintf(stderr, "DEBUG: backendDrainOutput(print_fd=%d, device_fd=%d)\n",
41 print_fd, device_fd);
42
43 /*
44 * Figure out the maximum file descriptor value to use with select()...
45 */
46
47 nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
48
49 /*
50 * Now loop until we are out of data from print_fd...
51 */
52
53 for (;;)
54 {
55 /*
56 * Use select() to determine whether we have data to copy around...
57 */
58
59 FD_ZERO(&input);
60 FD_SET(print_fd, &input);
61
62 timeout.tv_sec = 0;
63 timeout.tv_usec = 0;
64
65 if (select(nfds, &input, NULL, NULL, &timeout) < 0)
66 return (-1);
67
68 if (!FD_ISSET(print_fd, &input))
69 return (0);
70
71 if ((print_bytes = read(print_fd, print_buffer,
72 sizeof(print_buffer))) < 0)
73 {
74 /*
75 * Read error - bail if we don't see EAGAIN or EINTR...
76 */
77
0b1399a2 78 if (errno != EAGAIN && errno != EINTR)
09a101d6 79 {
f3c17241
MS
80 fprintf(stderr, "DEBUG: Read failed: %s\n", strerror(errno));
81 _cupsLangPrintFilter(stderr, "ERROR", _("Unable to read print data."));
09a101d6 82 return (-1);
83 }
84
85 print_bytes = 0;
86 }
87 else if (print_bytes == 0)
88 {
89 /*
90 * End of file, return...
91 */
92
93 return (0);
94 }
95
96 fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
97 (int)print_bytes);
98
99 for (print_ptr = print_buffer; print_bytes > 0;)
100 {
7e86f2f6 101 if ((bytes = write(device_fd, print_ptr, (size_t)print_bytes)) < 0)
09a101d6 102 {
103 /*
104 * Write error - bail if we don't see an error we can retry...
105 */
106
107 if (errno != ENOSPC && errno != ENXIO && errno != EAGAIN &&
108 errno != EINTR && errno != ENOTTY)
109 {
0837b7e8 110 _cupsLangPrintError("ERROR", _("Unable to write print data"));
09a101d6 111 return (-1);
112 }
113 }
114 else
115 {
116 fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
117
118 print_bytes -= bytes;
119 print_ptr += bytes;
120 }
121 }
122 }
123}
124
125
ed486911 126/*
127 * 'backendRunLoop()' - Read and write print and back-channel data.
128 */
129
130ssize_t /* O - Total bytes on success, -1 on error */
f7deaa1a 131backendRunLoop(
c8fef167
MS
132 int print_fd, /* I - Print file descriptor */
133 int device_fd, /* I - Device file descriptor */
134 int snmp_fd, /* I - SNMP socket or -1 if none */
135 http_addr_t *addr, /* I - Address of device */
136 int use_bc, /* I - Use back-channel? */
137 int update_state, /* I - Update printer-state-reasons? */
138 _cups_sccb_t side_cb) /* I - Side-channel callback */
ed486911 139{
140 int nfds; /* Maximum file descriptor value + 1 */
141 fd_set input, /* Input set for reading */
142 output; /* Output set for writing */
143 ssize_t print_bytes, /* Print bytes read */
144 bc_bytes, /* Backchannel bytes read */
145 total_bytes, /* Total bytes written */
146 bytes; /* Bytes written */
147 int paperout; /* "Paper out" status */
8ca02f3c 148 int offline; /* "Off-line" status */
ed486911 149 char print_buffer[8192], /* Print data buffer */
150 *print_ptr, /* Pointer into print data buffer */
151 bc_buffer[1024]; /* Back-channel data buffer */
568fa3fa
MS
152 struct timeval timeout; /* Timeout for select() */
153 time_t curtime, /* Current time */
154 snmp_update = 0;
ed486911 155#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
156 struct sigaction action; /* Actions for POSIX signals */
157#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
158
159
c0e1af83 160 fprintf(stderr,
568fa3fa
MS
161 "DEBUG: backendRunLoop(print_fd=%d, device_fd=%d, snmp_fd=%d, "
162 "addr=%p, use_bc=%d, side_cb=%p)\n",
163 print_fd, device_fd, snmp_fd, addr, use_bc, side_cb);
8ca02f3c 164
ed486911 165 /*
166 * If we are printing data from a print driver on stdin, ignore SIGTERM
167 * so that the driver can finish out any page data, e.g. to eject the
168 * current page. We only do this for stdin printing as otherwise there
169 * is no way to cancel a raw print job...
170 */
171
172 if (!print_fd)
173 {
174#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
175 sigset(SIGTERM, SIG_IGN);
176#elif defined(HAVE_SIGACTION)
177 memset(&action, 0, sizeof(action));
178
179 sigemptyset(&action.sa_mask);
180 action.sa_handler = SIG_IGN;
181 sigaction(SIGTERM, &action, NULL);
182#else
183 signal(SIGTERM, SIG_IGN);
184#endif /* HAVE_SIGSET */
185 }
4e6f60f0
MS
186 else if (print_fd < 0)
187 {
188 /*
189 * Copy print data from stdin, but don't mess with the signal handlers...
190 */
191
192 print_fd = 0;
193 }
ed486911 194
195 /*
196 * Figure out the maximum file descriptor value to use with select()...
197 */
198
199 nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
200
201 /*
202 * Now loop until we are out of data from print_fd...
203 */
204
b94498cf 205 for (print_bytes = 0, print_ptr = print_buffer, offline = -1,
206 paperout = -1, total_bytes = 0;;)
ed486911 207 {
208 /*
209 * Use select() to determine whether we have data to copy around...
210 */
211
212 FD_ZERO(&input);
213 if (!print_bytes)
214 FD_SET(print_fd, &input);
215 if (use_bc)
216 FD_SET(device_fd, &input);
dd1abb6b 217 if (!print_bytes && side_cb)
f7deaa1a 218 FD_SET(CUPS_SC_FD, &input);
ed486911 219
220 FD_ZERO(&output);
91c84a35 221 if (print_bytes || (!use_bc && !side_cb))
ed486911 222 FD_SET(device_fd, &output);
223
f7deaa1a 224 if (use_bc || side_cb)
8ca02f3c 225 {
568fa3fa
MS
226 timeout.tv_sec = 5;
227 timeout.tv_usec = 0;
228
229 if (select(nfds, &input, &output, NULL, &timeout) < 0)
8ca02f3c 230 {
231 /*
232 * Pause printing to clear any pending errors...
233 */
234
ef55b745 235 if (errno == ENXIO && offline != 1 && update_state)
8ca02f3c 236 {
c5571a1d 237 fputs("STATE: +offline-report\n", stderr);
0837b7e8 238 _cupsLangPrintFilter(stderr, "INFO",
f3c17241 239 _("The printer is not connected."));
8ca02f3c 240 offline = 1;
241 }
b94498cf 242 else if (errno == EINTR && total_bytes == 0)
243 {
244 fputs("DEBUG: Received an interrupt before any bytes were "
c8fef167 245 "written, aborting.\n", stderr);
b94498cf 246 return (0);
247 }
8ca02f3c 248
249 sleep(1);
250 continue;
251 }
252 }
ed486911 253
f7deaa1a 254 /*
255 * Check if we have a side-channel request ready...
256 */
257
258 if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
dd1abb6b
MS
259 {
260 /*
261 * Do the side-channel request, then start back over in the select
262 * loop since it may have read from print_fd...
263 */
264
18ecb428
MS
265 if ((*side_cb)(print_fd, device_fd, snmp_fd, addr, use_bc))
266 side_cb = NULL;
dd1abb6b
MS
267 continue;
268 }
f7deaa1a 269
ed486911 270 /*
271 * Check if we have back-channel data ready...
272 */
273
274 if (FD_ISSET(device_fd, &input))
275 {
276 if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
277 {
278 fprintf(stderr,
4d301e69 279 "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
ed486911 280 CUPS_LLCAST bc_bytes);
7e86f2f6 281 cupsBackChannelWrite(bc_buffer, (size_t)bc_bytes, 1.0);
ed486911 282 }
4b3f67ff
MS
283 else if (bc_bytes < 0 && errno != EAGAIN && errno != EINTR)
284 {
285 fprintf(stderr, "DEBUG: Error reading back-channel data: %s\n",
286 strerror(errno));
287 use_bc = 0;
288 }
7cf5915e
MS
289 else if (bc_bytes == 0)
290 use_bc = 0;
ed486911 291 }
292
293 /*
294 * Check if we have print data ready...
295 */
296
297 if (FD_ISSET(print_fd, &input))
298 {
299 if ((print_bytes = read(print_fd, print_buffer,
300 sizeof(print_buffer))) < 0)
301 {
302 /*
303 * Read error - bail if we don't see EAGAIN or EINTR...
304 */
305
0b1399a2 306 if (errno != EAGAIN && errno != EINTR)
ed486911 307 {
f3c17241
MS
308 fprintf(stderr, "DEBUG: Read failed: %s\n", strerror(errno));
309 _cupsLangPrintFilter(stderr, "ERROR",
310 _("Unable to read print data."));
ed486911 311 return (-1);
312 }
313
314 print_bytes = 0;
315 }
316 else if (print_bytes == 0)
317 {
318 /*
319 * End of file, break out of the loop...
320 */
321
322 break;
323 }
324
325 print_ptr = print_buffer;
8ca02f3c 326
327 fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
328 (int)print_bytes);
ed486911 329 }
330
331 /*
332 * Check if the device is ready to receive data and we have data to
333 * send...
334 */
335
336 if (print_bytes && FD_ISSET(device_fd, &output))
337 {
7e86f2f6 338 if ((bytes = write(device_fd, print_ptr, (size_t)print_bytes)) < 0)
ed486911 339 {
340 /*
341 * Write error - bail if we don't see an error we can retry...
342 */
343
344 if (errno == ENOSPC)
345 {
ef55b745 346 if (paperout != 1 && update_state)
ed486911 347 {
c5571a1d 348 fputs("STATE: +media-empty-warning\n", stderr);
0837b7e8 349 fputs("DEBUG: Out of paper\n", stderr);
ed486911 350 paperout = 1;
351 }
352 }
8ca02f3c 353 else if (errno == ENXIO)
354 {
ef55b745 355 if (offline != 1 && update_state)
8ca02f3c 356 {
c5571a1d 357 fputs("STATE: +offline-report\n", stderr);
0837b7e8 358 _cupsLangPrintFilter(stderr, "INFO",
f3c17241 359 _("The printer is not connected."));
8ca02f3c 360 offline = 1;
361 }
362 }
ed486911 363 else if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
364 {
0837b7e8 365 _cupsLangPrintError("ERROR", _("Unable to write print data"));
ed486911 366 return (-1);
367 }
368 }
369 else
370 {
ef55b745 371 if (paperout && update_state)
ed486911 372 {
c5571a1d 373 fputs("STATE: -media-empty-warning\n", stderr);
ed486911 374 paperout = 0;
375 }
376
ef55b745 377 if (offline && update_state)
8ca02f3c 378 {
c5571a1d 379 fputs("STATE: -offline-report\n", stderr);
f3c17241
MS
380 _cupsLangPrintFilter(stderr, "INFO",
381 _("The printer is now connected."));
8ca02f3c 382 offline = 0;
383 }
384
385 fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
ed486911 386
387 print_bytes -= bytes;
388 print_ptr += bytes;
389 total_bytes += bytes;
390 }
391 }
568fa3fa
MS
392
393 /*
394 * Do SNMP updates periodically...
395 */
396
397 if (snmp_fd >= 0 && time(&curtime) >= snmp_update)
398 {
399 if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
400 snmp_update = INT_MAX;
401 else
402 snmp_update = curtime + 5;
403 }
ed486911 404 }
405
406 /*
407 * Return with success...
408 */
409
410 return (total_bytes);
411}
412
413
414/*
c8fef167
MS
415 * 'backendWaitLoop()' - Wait for input from stdin while handling side-channel
416 * queries.
417 */
418
419int /* O - 1 if data is ready, 0 if not */
420backendWaitLoop(
421 int snmp_fd, /* I - SNMP socket or -1 if none */
422 http_addr_t *addr, /* I - Address of device */
f14324a7 423 int use_bc, /* I - Use back-channel? */
c8fef167
MS
424 _cups_sccb_t side_cb) /* I - Side-channel callback */
425{
82cc1f9a
MS
426 int nfds; /* Number of file descriptors */
427 fd_set input; /* Input set for reading */
428 time_t curtime = 0, /* Current time */
429 snmp_update = 0;/* Last SNMP status update */
430 struct timeval timeout; /* Timeout for select() */
c8fef167
MS
431
432
433 fprintf(stderr, "DEBUG: backendWaitLoop(snmp_fd=%d, addr=%p, side_cb=%p)\n",
434 snmp_fd, addr, side_cb);
435
436 /*
437 * Now loop until we receive data from stdin...
438 */
439
82cc1f9a
MS
440 if (snmp_fd >= 0)
441 snmp_update = time(NULL) + 5;
442
c8fef167
MS
443 for (;;)
444 {
445 /*
446 * Use select() to determine whether we have data to copy around...
447 */
448
449 FD_ZERO(&input);
450 FD_SET(0, &input);
451 if (side_cb)
452 FD_SET(CUPS_SC_FD, &input);
453
82cc1f9a
MS
454 if (snmp_fd >= 0)
455 {
456 curtime = time(NULL);
457 timeout.tv_sec = curtime >= snmp_update ? 0 : snmp_update - curtime;
458 timeout.tv_usec = 0;
459
460 nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout);
461 }
462 else
463 nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL);
464
465 if (nfds < 0)
c8fef167
MS
466 {
467 /*
468 * Pause printing to clear any pending errors...
469 */
470
471 if (errno == EINTR)
472 {
473 fputs("DEBUG: Received an interrupt before any bytes were "
474 "written, aborting.\n", stderr);
475 return (0);
476 }
477
478 sleep(1);
479 continue;
480 }
481
482 /*
483 * Check for input on stdin...
484 */
485
486 if (FD_ISSET(0, &input))
487 break;
488
489 /*
490 * Check if we have a side-channel request ready...
491 */
492
493 if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
494 {
495 /*
496 * Do the side-channel request, then start back over in the select
497 * loop since it may have read from print_fd...
498 */
499
f14324a7 500 if ((*side_cb)(0, -1, snmp_fd, addr, use_bc))
c8fef167
MS
501 side_cb = NULL;
502 continue;
503 }
504
505 /*
506 * Do SNMP updates periodically...
507 */
508
82cc1f9a 509 if (snmp_fd >= 0 && curtime >= snmp_update)
c8fef167
MS
510 {
511 if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
82cc1f9a 512 snmp_fd = -1;
c8fef167
MS
513 else
514 snmp_update = curtime + 5;
515 }
516 }
517
518 /*
519 * Return with success...
520 */
521
522 return (1);
523}