2 * "$Id: sidechannel.c 6319 2007-03-06 18:51:40Z mike $"
4 * Side-channel API code for the Common UNIX Printing System (CUPS).
6 * Copyright 2006 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
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.
35 * Include necessary headers...
38 #include "sidechannel.h"
43 # include <sys/time.h>
45 # include <sys/select.h>
48 # include <sys/time.h>
51 # include <sys/poll.h>
52 #endif /* HAVE_POLL */
56 * 'cupsSideChannelDoRequest()' - Send a side-channel command to a backend and wait for a response.
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.
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.
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 */
78 cups_sc_status_t status
; /* Status of command */
79 cups_sc_command_t rcommand
; /* Response command */
82 if (cupsSideChannelWrite(command
, CUPS_SC_STATUS_NONE
, NULL
, 0, timeout
))
83 return (CUPS_SC_STATUS_TIMEOUT
);
85 if (cupsSideChannelRead(&rcommand
, &status
, data
, datalen
, timeout
))
86 return (CUPS_SC_STATUS_TIMEOUT
);
88 if (rcommand
!= command
)
89 return (CUPS_SC_STATUS_BAD_MESSAGE
);
96 * 'cupsSideChannelRead()' - Read a side-channel message.
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.
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.
110 int /* O - 0 on success, -1 on error */
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 */
118 char buffer
[16388]; /* Message buffer */
119 int bytes
; /* Bytes read */
120 int templen
; /* Data length from message */
122 struct pollfd pfd
; /* Poll structure for poll() */
124 fd_set input_set
; /* Input set for select() */
125 struct timeval stimeout
; /* Timeout value for select() */
126 #endif /* HAVE_POLL */
130 * Range check input...
133 if (!command
|| !status
)
137 * See if we have pending data on the side-channel socket...
146 if (poll(&pfd
, 1, -1) < 1)
149 else if (poll(&pfd
, 1, (long)(timeout
* 1000)) < 1)
154 FD_SET(CUPS_SC_FD
, &input_set
);
158 if (select(CUPS_SC_FD
+ 1, &input_set
, NULL
, NULL
, NULL
) < 1)
163 stimeout
.tv_sec
= (int)timeout
;
164 stimeout
.tv_usec
= (int)(timeout
* 1000000) % 1000000;
166 if (select(CUPS_SC_FD
+ 1, &input_set
, NULL
, NULL
, &stimeout
) < 1)
169 #endif /* HAVE_POLL */
172 * Read a side-channel message for the format:
174 * Byte(s) Description
175 * ------- -------------------------------------------
178 * 2-3 Data length (network byte order) <= 16384
182 while ((bytes
= read(CUPS_SC_FD
, buffer
, sizeof(buffer
))) < 0)
183 if (errno
!= EINTR
&& errno
!= EAGAIN
)
187 * Validate the command code in the message...
190 if (buffer
[0] < CUPS_SC_CMD_SOFT_RESET
|| buffer
[0] > CUPS_SC_CMD_GET_STATE
)
193 *command
= (cups_sc_command_t
)buffer
[0];
196 * Validate the data length in the message...
199 templen
= ((buffer
[2] & 255) << 8) | (buffer
[3] & 255);
201 if (templen
> 0 && (!data
|| !datalen
))
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
;
210 else if (templen
> *datalen
|| templen
> (bytes
- 4))
213 * Either the response is bigger than the provided buffer or the
214 * response is bigger than we've read...
217 *status
= CUPS_SC_STATUS_TOO_BIG
;
222 * The response data will fit, copy it over and provide the actual
226 *status
= (cups_sc_status_t
)buffer
[1];
229 memcpy(data
, buffer
+ 4, templen
);
237 * 'cupsSideChannelWrite()' - Write a side-channel message.
239 * This function is normally only called by backend programs to send
240 * responses to a filter, driver, or port monitor program.
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 */
253 char buffer
[16388]; /* Message buffer */
254 int bytes
; /* Bytes written */
256 struct pollfd pfd
; /* Poll structure for poll() */
258 fd_set output_set
; /* Output set for select() */
259 struct timeval stimeout
; /* Timeout value for select() */
260 #endif /* HAVE_POLL */
264 * Range check input...
267 if (command
< CUPS_SC_CMD_SOFT_RESET
|| command
> CUPS_SC_CMD_GET_STATE
||
268 datalen
< 0 || datalen
> 16384 || (datalen
> 0 && !data
))
272 * See if we can safely write to the side-channel socket...
277 pfd
.events
= POLLOUT
;
281 if (poll(&pfd
, 1, -1) < 1)
284 else if (poll(&pfd
, 1, (long)(timeout
* 1000)) < 1)
288 FD_ZERO(&output_set
);
289 FD_SET(CUPS_SC_FD
, &output_set
);
293 if (select(CUPS_SC_FD
+ 1, NULL
, &output_set
, NULL
, NULL
) < 1)
298 stimeout
.tv_sec
= (int)timeout
;
299 stimeout
.tv_usec
= (int)(timeout
* 1000000) % 1000000;
301 if (select(CUPS_SC_FD
+ 1, NULL
, &output_set
, NULL
, &stimeout
) < 1)
304 #endif /* HAVE_POLL */
307 * Write a side-channel message in the format:
309 * Byte(s) Description
310 * ------- -------------------------------------------
313 * 2-3 Data length (network byte order) <= 16384
319 buffer
[2] = datalen
>> 8;
320 buffer
[3] = datalen
& 255;
326 memcpy(buffer
+ 4, data
, datalen
);
330 while (write(CUPS_SC_FD
, buffer
, bytes
) < 0)
331 if (errno
!= EINTR
&& errno
!= EAGAIN
)
339 * End of "$Id: sidechannel.c 6319 2007-03-06 18:51:40Z mike $".