1 /*
2 * Backchannel functions for CUPS.
3 *
4 * Copyright © 2020-2024 by OpenPrinting.
5 * Copyright 2007-2014 by Apple Inc.
6 * Copyright 1997-2007 by Easy Software Products.
7 *
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "cups.h"
16 #include "sidechannel.h"
17 #include <errno.h>
18 #ifdef _WIN32
19 # include <io.h>
20 # include <fcntl.h>
21 #else
22 # include <sys/time.h>
23 #endif /* _WIN32 */
24
25
26 /*
27 * Local functions...
28 */
29
30 static void cups_setup(fd_set *set, struct timeval *tval,
31 double timeout);
32
33
34 /*
35 * 'cupsBackChannelRead()' - Read data from the backchannel.
36 *
37 * Reads up to "bytes" bytes from the backchannel/backend. The "timeout"
38 * parameter controls how many seconds to wait for the data - use 0.0 to
39 * return immediately if there is no data, -1.0 to wait for data indefinitely.
40 *
41 * @since CUPS 1.2/macOS 10.5@
42 */
43
44 ssize_t /* O - Bytes read or -1 on error */
cupsBackChannelRead(char * buffer,size_t bytes,double timeout)45 cupsBackChannelRead(char *buffer, /* I - Buffer to read into */
46 size_t bytes, /* I - Bytes to read */
47 double timeout) /* I - Timeout in seconds, typically 0.0 to poll */
48 {
49 fd_set input; /* Input set */
50 struct timeval tval; /* Timeout value */
51 int status; /* Select status */
52
53
54 /*
55 * Wait for input ready.
56 */
57
58 do
59 {
60 cups_setup(&input, &tval, timeout);
61
62 if (timeout < 0.0)
63 status = select(4, &input, NULL, NULL, NULL);
64 else
65 status = select(4, &input, NULL, NULL, &tval);
66 }
67 while (status < 0 && errno != EINTR && errno != EAGAIN);
68
69 if (status <= 0)
70 return (-1); /* Timeout! */
71
72 /*
73 * Read bytes from the pipe...
74 */
75
76 #ifdef _WIN32
77 return ((ssize_t)_read(3, buffer, (unsigned)bytes));
78 #else
79 return (read(3, buffer, bytes));
80 #endif /* _WIN32 */
81 }
82
83
84 /*
85 * 'cupsBackChannelWrite()' - Write data to the backchannel.
86 *
87 * Writes "bytes" bytes to the backchannel/filter. The "timeout" parameter
88 * controls how many seconds to wait for the data to be written - use
89 * 0.0 to return immediately if the data cannot be written, -1.0 to wait
90 * indefinitely.
91 *
92 * @since CUPS 1.2/macOS 10.5@
93 */
94
95 ssize_t /* O - Bytes written or -1 on error */
cupsBackChannelWrite(const char * buffer,size_t bytes,double timeout)96 cupsBackChannelWrite(
97 const char *buffer, /* I - Buffer to write */
98 size_t bytes, /* I - Bytes to write */
99 double timeout) /* I - Timeout in seconds, typically 1.0 */
100 {
101 fd_set output; /* Output set */
102 struct timeval tval; /* Timeout value */
103 int status; /* Select status */
104 ssize_t count; /* Current bytes */
105 size_t total; /* Total bytes */
106
107
108 /*
109 * Write all bytes...
110 */
111
112 total = 0;
113
114 while (total < bytes)
115 {
116 /*
117 * Wait for write-ready...
118 */
119
120 do
121 {
122 cups_setup(&output, &tval, timeout);
123
124 if (timeout < 0.0)
125 status = select(4, NULL, &output, NULL, NULL);
126 else
127 status = select(4, NULL, &output, NULL, &tval);
128 }
129 while (status < 0 && errno != EINTR && errno != EAGAIN);
130
131 if (status <= 0)
132 return (-1); /* Timeout! */
133
134 /*
135 * Write bytes to the pipe...
136 */
137
138 #ifdef _WIN32
139 count = (ssize_t)_write(3, buffer, (unsigned)(bytes - total));
140 #else
141 count = write(3, buffer, bytes - total);
142 #endif /* _WIN32 */
143
144 if (count < 0)
145 {
146 /*
147 * Write error - abort on fatal errors...
148 */
149
150 if (errno != EINTR && errno != EAGAIN)
151 return (-1);
152 }
153 else
154 {
155 /*
156 * Write succeeded, update buffer pointer and total count...
157 */
158
159 buffer += count;
160 total += (size_t)count;
161 }
162 }
163
164 return ((ssize_t)bytes);
165 }
166
167
168 /*
169 * 'cups_setup()' - Setup select()
170 */
171
172 static void
cups_setup(fd_set * set,struct timeval * tval,double timeout)173 cups_setup(fd_set *set, /* I - Set for select() */
174 struct timeval *tval, /* I - Timer value */
175 double timeout) /* I - Timeout in seconds */
176 {
177 tval->tv_sec = (time_t)timeout;
178 tval->tv_usec = (suseconds_t)(1000000.0 * (timeout - tval->tv_sec));
179
180 FD_ZERO(set);
181 FD_SET(3, set);
182 }
183