2 * "$Id: sidechannel.c 6649 2007-07-11 21:46:42Z mike $"
4 * Side-channel API code for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * cupsSideChannelDoRequest() - Send a side-channel command to a backend
20 * and wait for a response.
21 * cupsSideChannelRead() - Read a side-channel message.
22 * cupsSideChannelWrite() - Write a side-channel message.
26 * Include necessary headers...
29 #include "sidechannel.h"
34 # include <sys/time.h>
36 # include <sys/select.h>
39 # include <sys/time.h>
42 # include <sys/poll.h>
43 #endif /* HAVE_POLL */
47 * 'cupsSideChannelDoRequest()' - Send a side-channel command to a backend and wait for a response.
49 * This function is normally only called by filters, drivers, or port
50 * monitors in order to communicate with the backend used by the current
51 * printer. Programs must be prepared to handle timeout or "not
52 * implemented" status codes, which indicate that the backend or device
53 * do not support the specified side-channel command.
55 * The "datalen" parameter must be initialized to the size of the buffer
56 * pointed to by the "data" parameter. cupsSideChannelDoRequest() will
57 * update the value to contain the number of data bytes in the buffer.
62 cups_sc_status_t
/* O - Status of command */
63 cupsSideChannelDoRequest(
64 cups_sc_command_t command
, /* I - Command to send */
65 char *data
, /* O - Response data buffer pointer */
66 int *datalen
, /* IO - Size of data buffer on entry, number of bytes in buffer on return */
67 double timeout
) /* I - Timeout in seconds */
69 cups_sc_status_t status
; /* Status of command */
70 cups_sc_command_t rcommand
; /* Response command */
73 if (cupsSideChannelWrite(command
, CUPS_SC_STATUS_NONE
, NULL
, 0, timeout
))
74 return (CUPS_SC_STATUS_TIMEOUT
);
76 if (cupsSideChannelRead(&rcommand
, &status
, data
, datalen
, timeout
))
77 return (CUPS_SC_STATUS_TIMEOUT
);
79 if (rcommand
!= command
)
80 return (CUPS_SC_STATUS_BAD_MESSAGE
);
87 * 'cupsSideChannelRead()' - Read a side-channel message.
89 * This function is normally only called by backend programs to read
90 * commands from a filter, driver, or port monitor program. The
91 * caller must be prepared to handle incomplete or invalid messages
92 * and return the corresponding status codes.
94 * The "datalen" parameter must be initialized to the size of the buffer
95 * pointed to by the "data" parameter. cupsSideChannelDoRequest() will
96 * update the value to contain the number of data bytes in the buffer.
101 int /* O - 0 on success, -1 on error */
103 cups_sc_command_t
*command
, /* O - Command code */
104 cups_sc_status_t
*status
, /* O - Status code */
105 char *data
, /* O - Data buffer pointer */
106 int *datalen
, /* IO - Size of data buffer on entry, number of bytes in buffer on return */
107 double timeout
) /* I - Timeout in seconds */
109 char buffer
[16388]; /* Message buffer */
110 int bytes
; /* Bytes read */
111 int templen
; /* Data length from message */
113 struct pollfd pfd
; /* Poll structure for poll() */
115 fd_set input_set
; /* Input set for select() */
116 struct timeval stimeout
; /* Timeout value for select() */
117 #endif /* HAVE_POLL */
121 * Range check input...
124 if (!command
|| !status
)
128 * See if we have pending data on the side-channel socket...
137 if (poll(&pfd
, 1, -1) < 1)
140 else if (poll(&pfd
, 1, (long)(timeout
* 1000)) < 1)
145 FD_SET(CUPS_SC_FD
, &input_set
);
149 if (select(CUPS_SC_FD
+ 1, &input_set
, NULL
, NULL
, NULL
) < 1)
154 stimeout
.tv_sec
= (int)timeout
;
155 stimeout
.tv_usec
= (int)(timeout
* 1000000) % 1000000;
157 if (select(CUPS_SC_FD
+ 1, &input_set
, NULL
, NULL
, &stimeout
) < 1)
160 #endif /* HAVE_POLL */
163 * Read a side-channel message for the format:
165 * Byte(s) Description
166 * ------- -------------------------------------------
169 * 2-3 Data length (network byte order) <= 16384
173 while ((bytes
= read(CUPS_SC_FD
, buffer
, sizeof(buffer
))) < 0)
174 if (errno
!= EINTR
&& errno
!= EAGAIN
)
178 * Validate the command code in the message...
181 if (buffer
[0] < CUPS_SC_CMD_SOFT_RESET
|| buffer
[0] > CUPS_SC_CMD_GET_STATE
)
184 *command
= (cups_sc_command_t
)buffer
[0];
187 * Validate the data length in the message...
190 templen
= ((buffer
[2] & 255) << 8) | (buffer
[3] & 255);
192 if (templen
> 0 && (!data
|| !datalen
))
195 * Either the response is bigger than the provided buffer or the
196 * response is bigger than we've read...
199 *status
= CUPS_SC_STATUS_TOO_BIG
;
201 else if (templen
> *datalen
|| templen
> (bytes
- 4))
204 * Either the response is bigger than the provided buffer or the
205 * response is bigger than we've read...
208 *status
= CUPS_SC_STATUS_TOO_BIG
;
213 * The response data will fit, copy it over and provide the actual
217 *status
= (cups_sc_status_t
)buffer
[1];
220 memcpy(data
, buffer
+ 4, templen
);
228 * 'cupsSideChannelWrite()' - Write a side-channel message.
230 * This function is normally only called by backend programs to send
231 * responses to a filter, driver, or port monitor program.
236 int /* O - 0 on success, -1 on error */
237 cupsSideChannelWrite(
238 cups_sc_command_t command
, /* I - Command code */
239 cups_sc_status_t status
, /* I - Status code */
240 const char *data
, /* I - Data buffer pointer */
241 int datalen
, /* I - Number of bytes of data */
242 double timeout
) /* I - Timeout in seconds */
244 char buffer
[16388]; /* Message buffer */
245 int bytes
; /* Bytes written */
247 struct pollfd pfd
; /* Poll structure for poll() */
249 fd_set output_set
; /* Output set for select() */
250 struct timeval stimeout
; /* Timeout value for select() */
251 #endif /* HAVE_POLL */
255 * Range check input...
258 if (command
< CUPS_SC_CMD_SOFT_RESET
|| command
> CUPS_SC_CMD_GET_STATE
||
259 datalen
< 0 || datalen
> 16384 || (datalen
> 0 && !data
))
263 * See if we can safely write to the side-channel socket...
268 pfd
.events
= POLLOUT
;
272 if (poll(&pfd
, 1, -1) < 1)
275 else if (poll(&pfd
, 1, (long)(timeout
* 1000)) < 1)
279 FD_ZERO(&output_set
);
280 FD_SET(CUPS_SC_FD
, &output_set
);
284 if (select(CUPS_SC_FD
+ 1, NULL
, &output_set
, NULL
, NULL
) < 1)
289 stimeout
.tv_sec
= (int)timeout
;
290 stimeout
.tv_usec
= (int)(timeout
* 1000000) % 1000000;
292 if (select(CUPS_SC_FD
+ 1, NULL
, &output_set
, NULL
, &stimeout
) < 1)
295 #endif /* HAVE_POLL */
298 * Write a side-channel message in the format:
300 * Byte(s) Description
301 * ------- -------------------------------------------
304 * 2-3 Data length (network byte order) <= 16384
310 buffer
[2] = datalen
>> 8;
311 buffer
[3] = datalen
& 255;
317 memcpy(buffer
+ 4, data
, datalen
);
321 while (write(CUPS_SC_FD
, buffer
, bytes
) < 0)
322 if (errno
!= EINTR
&& errno
!= EAGAIN
)
330 * End of "$Id: sidechannel.c 6649 2007-07-11 21:46:42Z mike $".