]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/sidechannel.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / sidechannel.c
1 /*
2 * "$Id: sidechannel.c 6319 2007-03-06 18:51:40Z mike $"
3 *
4 * Side-channel API code for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2006 by Easy Software Products.
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 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsSideChannelDoRequest() - Send a side-channel command to a backend
29 * and wait for a response.
30 * cupsSideChannelRead() - Read a side-channel message.
31 * cupsSideChannelWrite() - Write a side-channel message.
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "sidechannel.h"
39 #include "string.h"
40 #include <unistd.h>
41 #include <errno.h>
42 #ifdef __hpux
43 # include <sys/time.h>
44 #else
45 # include <sys/select.h>
46 #endif /* __hpux */
47 #ifndef WIN32
48 # include <sys/time.h>
49 #endif /* !WIN32 */
50 #ifdef HAVE_POLL
51 # include <sys/poll.h>
52 #endif /* HAVE_POLL */
53
54
55 /*
56 * 'cupsSideChannelDoRequest()' - Send a side-channel command to a backend and wait for a response.
57 *
58 * This function is normally only called by filters, drivers, or port
59 * monitors in order to communicate with the backend used by the current
60 * printer. Programs must be prepared to handle timeout or "not
61 * implemented" status codes, which indicate that the backend or device
62 * do not support the specified side-channel command.
63 *
64 * The "datalen" parameter must be initialized to the size of the buffer
65 * pointed to by the "data" parameter. cupsSideChannelDoRequest() will
66 * update the value to contain the number of data bytes in the buffer.
67 *
68 * @since CUPS 1.3@
69 */
70
71 cups_sc_status_t /* O - Status of command */
72 cupsSideChannelDoRequest(
73 cups_sc_command_t command, /* I - Command to send */
74 char *data, /* O - Response data buffer pointer */
75 int *datalen, /* IO - Size of data buffer on entry, number of bytes in buffer on return */
76 double timeout) /* I - Timeout in seconds */
77 {
78 cups_sc_status_t status; /* Status of command */
79 cups_sc_command_t rcommand; /* Response command */
80
81
82 if (cupsSideChannelWrite(command, CUPS_SC_STATUS_NONE, NULL, 0, timeout))
83 return (CUPS_SC_STATUS_TIMEOUT);
84
85 if (cupsSideChannelRead(&rcommand, &status, data, datalen, timeout))
86 return (CUPS_SC_STATUS_TIMEOUT);
87
88 if (rcommand != command)
89 return (CUPS_SC_STATUS_BAD_MESSAGE);
90
91 return (status);
92 }
93
94
95 /*
96 * 'cupsSideChannelRead()' - Read a side-channel message.
97 *
98 * This function is normally only called by backend programs to read
99 * commands from a filter, driver, or port monitor program. The
100 * caller must be prepared to handle incomplete or invalid messages
101 * and return the corresponding status codes.
102 *
103 * The "datalen" parameter must be initialized to the size of the buffer
104 * pointed to by the "data" parameter. cupsSideChannelDoRequest() will
105 * update the value to contain the number of data bytes in the buffer.
106 *
107 * @since CUPS 1.3@
108 */
109
110 int /* O - 0 on success, -1 on error */
111 cupsSideChannelRead(
112 cups_sc_command_t *command, /* O - Command code */
113 cups_sc_status_t *status, /* O - Status code */
114 char *data, /* O - Data buffer pointer */
115 int *datalen, /* IO - Size of data buffer on entry, number of bytes in buffer on return */
116 double timeout) /* I - Timeout in seconds */
117 {
118 char buffer[16388]; /* Message buffer */
119 int bytes; /* Bytes read */
120 int templen; /* Data length from message */
121 #ifdef HAVE_POLL
122 struct pollfd pfd; /* Poll structure for poll() */
123 #else /* select() */
124 fd_set input_set; /* Input set for select() */
125 struct timeval stimeout; /* Timeout value for select() */
126 #endif /* HAVE_POLL */
127
128
129 /*
130 * Range check input...
131 */
132
133 if (!command || !status)
134 return (-1);
135
136 /*
137 * See if we have pending data on the side-channel socket...
138 */
139
140 #ifdef HAVE_POLL
141 pfd.fd = CUPS_SC_FD;
142 pfd.events = POLLIN;
143
144 if (timeout < 0.0)
145 {
146 if (poll(&pfd, 1, -1) < 1)
147 return (-1);
148 }
149 else if (poll(&pfd, 1, (long)(timeout * 1000)) < 1)
150 return (-1);
151
152 #else /* select() */
153 FD_ZERO(&input_set);
154 FD_SET(CUPS_SC_FD, &input_set);
155
156 if (timeout < 0.0)
157 {
158 if (select(CUPS_SC_FD + 1, &input_set, NULL, NULL, NULL) < 1)
159 return (-1);
160 }
161 else
162 {
163 stimeout.tv_sec = (int)timeout;
164 stimeout.tv_usec = (int)(timeout * 1000000) % 1000000;
165
166 if (select(CUPS_SC_FD + 1, &input_set, NULL, NULL, &stimeout) < 1)
167 return (-1);
168 }
169 #endif /* HAVE_POLL */
170
171 /*
172 * Read a side-channel message for the format:
173 *
174 * Byte(s) Description
175 * ------- -------------------------------------------
176 * 0 Command code
177 * 1 Status code
178 * 2-3 Data length (network byte order) <= 16384
179 * 4-N Data
180 */
181
182 while ((bytes = read(CUPS_SC_FD, buffer, sizeof(buffer))) < 0)
183 if (errno != EINTR && errno != EAGAIN)
184 return (-1);
185
186 /*
187 * Validate the command code in the message...
188 */
189
190 if (buffer[0] < CUPS_SC_CMD_SOFT_RESET || buffer[0] > CUPS_SC_CMD_GET_STATE)
191 return (-1);
192
193 *command = (cups_sc_command_t)buffer[0];
194
195 /*
196 * Validate the data length in the message...
197 */
198
199 templen = ((buffer[2] & 255) << 8) | (buffer[3] & 255);
200
201 if (templen > 0 && (!data || !datalen))
202 {
203 /*
204 * Either the response is bigger than the provided buffer or the
205 * response is bigger than we've read...
206 */
207
208 *status = CUPS_SC_STATUS_TOO_BIG;
209 }
210 else if (templen > *datalen || templen > (bytes - 4))
211 {
212 /*
213 * Either the response is bigger than the provided buffer or the
214 * response is bigger than we've read...
215 */
216
217 *status = CUPS_SC_STATUS_TOO_BIG;
218 }
219 else
220 {
221 /*
222 * The response data will fit, copy it over and provide the actual
223 * length...
224 */
225
226 *status = (cups_sc_status_t)buffer[1];
227 *datalen = templen;
228
229 memcpy(data, buffer + 4, templen);
230 }
231
232 return (0);
233 }
234
235
236 /*
237 * 'cupsSideChannelWrite()' - Write a side-channel message.
238 *
239 * This function is normally only called by backend programs to send
240 * responses to a filter, driver, or port monitor program.
241 *
242 * @since CUPS 1.3@
243 */
244
245 int /* O - 0 on success, -1 on error */
246 cupsSideChannelWrite(
247 cups_sc_command_t command, /* I - Command code */
248 cups_sc_status_t status, /* I - Status code */
249 const char *data, /* I - Data buffer pointer */
250 int datalen, /* I - Number of bytes of data */
251 double timeout) /* I - Timeout in seconds */
252 {
253 char buffer[16388]; /* Message buffer */
254 int bytes; /* Bytes written */
255 #ifdef HAVE_POLL
256 struct pollfd pfd; /* Poll structure for poll() */
257 #else /* select() */
258 fd_set output_set; /* Output set for select() */
259 struct timeval stimeout; /* Timeout value for select() */
260 #endif /* HAVE_POLL */
261
262
263 /*
264 * Range check input...
265 */
266
267 if (command < CUPS_SC_CMD_SOFT_RESET || command > CUPS_SC_CMD_GET_STATE ||
268 datalen < 0 || datalen > 16384 || (datalen > 0 && !data))
269 return (-1);
270
271 /*
272 * See if we can safely write to the side-channel socket...
273 */
274
275 #ifdef HAVE_POLL
276 pfd.fd = CUPS_SC_FD;
277 pfd.events = POLLOUT;
278
279 if (timeout < 0.0)
280 {
281 if (poll(&pfd, 1, -1) < 1)
282 return (-1);
283 }
284 else if (poll(&pfd, 1, (long)(timeout * 1000)) < 1)
285 return (-1);
286
287 #else /* select() */
288 FD_ZERO(&output_set);
289 FD_SET(CUPS_SC_FD, &output_set);
290
291 if (timeout < 0.0)
292 {
293 if (select(CUPS_SC_FD + 1, NULL, &output_set, NULL, NULL) < 1)
294 return (-1);
295 }
296 else
297 {
298 stimeout.tv_sec = (int)timeout;
299 stimeout.tv_usec = (int)(timeout * 1000000) % 1000000;
300
301 if (select(CUPS_SC_FD + 1, NULL, &output_set, NULL, &stimeout) < 1)
302 return (-1);
303 }
304 #endif /* HAVE_POLL */
305
306 /*
307 * Write a side-channel message in the format:
308 *
309 * Byte(s) Description
310 * ------- -------------------------------------------
311 * 0 Command code
312 * 1 Status code
313 * 2-3 Data length (network byte order) <= 16384
314 * 4-N Data
315 */
316
317 buffer[0] = command;
318 buffer[1] = status;
319 buffer[2] = datalen >> 8;
320 buffer[3] = datalen & 255;
321
322 bytes = 4;
323
324 if (datalen > 0)
325 {
326 memcpy(buffer + 4, data, datalen);
327 bytes += datalen;
328 }
329
330 while (write(CUPS_SC_FD, buffer, bytes) < 0)
331 if (errno != EINTR && errno != EAGAIN)
332 return (-1);
333
334 return (0);
335 }
336
337
338 /*
339 * End of "$Id: sidechannel.c 6319 2007-03-06 18:51:40Z mike $".
340 */