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