xref: /aosp_15_r20/external/libcups/cups/sidechannel.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * Side-channel API code for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2007-2019 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2006 by Easy Software Products.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8*5e7646d2SAndroid Build Coastguard Worker  * information.
9*5e7646d2SAndroid Build Coastguard Worker  */
10*5e7646d2SAndroid Build Coastguard Worker 
11*5e7646d2SAndroid Build Coastguard Worker /*
12*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
13*5e7646d2SAndroid Build Coastguard Worker  */
14*5e7646d2SAndroid Build Coastguard Worker 
15*5e7646d2SAndroid Build Coastguard Worker #include "sidechannel.h"
16*5e7646d2SAndroid Build Coastguard Worker #include "cups-private.h"
17*5e7646d2SAndroid Build Coastguard Worker #include "debug-internal.h"
18*5e7646d2SAndroid Build Coastguard Worker #ifdef _WIN32
19*5e7646d2SAndroid Build Coastguard Worker #  include <io.h>
20*5e7646d2SAndroid Build Coastguard Worker #else
21*5e7646d2SAndroid Build Coastguard Worker #  include <unistd.h>
22*5e7646d2SAndroid Build Coastguard Worker #  include <sys/select.h>
23*5e7646d2SAndroid Build Coastguard Worker #  include <sys/time.h>
24*5e7646d2SAndroid Build Coastguard Worker #endif /* _WIN32 */
25*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_POLL
26*5e7646d2SAndroid Build Coastguard Worker #  include <poll.h>
27*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_POLL */
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker 
30*5e7646d2SAndroid Build Coastguard Worker /*
31*5e7646d2SAndroid Build Coastguard Worker  * Buffer size for side-channel requests...
32*5e7646d2SAndroid Build Coastguard Worker  */
33*5e7646d2SAndroid Build Coastguard Worker 
34*5e7646d2SAndroid Build Coastguard Worker #define _CUPS_SC_MAX_DATA	65535
35*5e7646d2SAndroid Build Coastguard Worker #define _CUPS_SC_MAX_BUFFER	65540
36*5e7646d2SAndroid Build Coastguard Worker 
37*5e7646d2SAndroid Build Coastguard Worker 
38*5e7646d2SAndroid Build Coastguard Worker /*
39*5e7646d2SAndroid Build Coastguard Worker  * 'cupsSideChannelDoRequest()' - Send a side-channel command to a backend and wait for a response.
40*5e7646d2SAndroid Build Coastguard Worker  *
41*5e7646d2SAndroid Build Coastguard Worker  * This function is normally only called by filters, drivers, or port
42*5e7646d2SAndroid Build Coastguard Worker  * monitors in order to communicate with the backend used by the current
43*5e7646d2SAndroid Build Coastguard Worker  * printer.  Programs must be prepared to handle timeout or "not
44*5e7646d2SAndroid Build Coastguard Worker  * implemented" status codes, which indicate that the backend or device
45*5e7646d2SAndroid Build Coastguard Worker  * do not support the specified side-channel command.
46*5e7646d2SAndroid Build Coastguard Worker  *
47*5e7646d2SAndroid Build Coastguard Worker  * The "datalen" parameter must be initialized to the size of the buffer
48*5e7646d2SAndroid Build Coastguard Worker  * pointed to by the "data" parameter.  cupsSideChannelDoRequest() will
49*5e7646d2SAndroid Build Coastguard Worker  * update the value to contain the number of data bytes in the buffer.
50*5e7646d2SAndroid Build Coastguard Worker  *
51*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.3/macOS 10.5@
52*5e7646d2SAndroid Build Coastguard Worker  */
53*5e7646d2SAndroid Build Coastguard Worker 
54*5e7646d2SAndroid Build Coastguard Worker cups_sc_status_t			/* O  - Status of command */
cupsSideChannelDoRequest(cups_sc_command_t command,char * data,int * datalen,double timeout)55*5e7646d2SAndroid Build Coastguard Worker cupsSideChannelDoRequest(
56*5e7646d2SAndroid Build Coastguard Worker     cups_sc_command_t command,		/* I  - Command to send */
57*5e7646d2SAndroid Build Coastguard Worker     char              *data,		/* O  - Response data buffer pointer */
58*5e7646d2SAndroid Build Coastguard Worker     int               *datalen,		/* IO - Size of data buffer on entry, number of bytes in buffer on return */
59*5e7646d2SAndroid Build Coastguard Worker     double            timeout)		/* I  - Timeout in seconds */
60*5e7646d2SAndroid Build Coastguard Worker {
61*5e7646d2SAndroid Build Coastguard Worker   cups_sc_status_t	status;		/* Status of command */
62*5e7646d2SAndroid Build Coastguard Worker   cups_sc_command_t	rcommand;	/* Response command */
63*5e7646d2SAndroid Build Coastguard Worker 
64*5e7646d2SAndroid Build Coastguard Worker 
65*5e7646d2SAndroid Build Coastguard Worker   if (cupsSideChannelWrite(command, CUPS_SC_STATUS_NONE, NULL, 0, timeout))
66*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_TIMEOUT);
67*5e7646d2SAndroid Build Coastguard Worker 
68*5e7646d2SAndroid Build Coastguard Worker   if (cupsSideChannelRead(&rcommand, &status, data, datalen, timeout))
69*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_TIMEOUT);
70*5e7646d2SAndroid Build Coastguard Worker 
71*5e7646d2SAndroid Build Coastguard Worker   if (rcommand != command)
72*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_BAD_MESSAGE);
73*5e7646d2SAndroid Build Coastguard Worker 
74*5e7646d2SAndroid Build Coastguard Worker   return (status);
75*5e7646d2SAndroid Build Coastguard Worker }
76*5e7646d2SAndroid Build Coastguard Worker 
77*5e7646d2SAndroid Build Coastguard Worker 
78*5e7646d2SAndroid Build Coastguard Worker /*
79*5e7646d2SAndroid Build Coastguard Worker  * 'cupsSideChannelRead()' - Read a side-channel message.
80*5e7646d2SAndroid Build Coastguard Worker  *
81*5e7646d2SAndroid Build Coastguard Worker  * This function is normally only called by backend programs to read
82*5e7646d2SAndroid Build Coastguard Worker  * commands from a filter, driver, or port monitor program.  The
83*5e7646d2SAndroid Build Coastguard Worker  * caller must be prepared to handle incomplete or invalid messages
84*5e7646d2SAndroid Build Coastguard Worker  * and return the corresponding status codes.
85*5e7646d2SAndroid Build Coastguard Worker  *
86*5e7646d2SAndroid Build Coastguard Worker  * The "datalen" parameter must be initialized to the size of the buffer
87*5e7646d2SAndroid Build Coastguard Worker  * pointed to by the "data" parameter.  cupsSideChannelDoRequest() will
88*5e7646d2SAndroid Build Coastguard Worker  * update the value to contain the number of data bytes in the buffer.
89*5e7646d2SAndroid Build Coastguard Worker  *
90*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.3/macOS 10.5@
91*5e7646d2SAndroid Build Coastguard Worker  */
92*5e7646d2SAndroid Build Coastguard Worker 
93*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on error */
cupsSideChannelRead(cups_sc_command_t * command,cups_sc_status_t * status,char * data,int * datalen,double timeout)94*5e7646d2SAndroid Build Coastguard Worker cupsSideChannelRead(
95*5e7646d2SAndroid Build Coastguard Worker     cups_sc_command_t *command,		/* O - Command code */
96*5e7646d2SAndroid Build Coastguard Worker     cups_sc_status_t  *status,		/* O - Status code */
97*5e7646d2SAndroid Build Coastguard Worker     char              *data,		/* O - Data buffer pointer */
98*5e7646d2SAndroid Build Coastguard Worker     int               *datalen,		/* IO - Size of data buffer on entry, number of bytes in buffer on return */
99*5e7646d2SAndroid Build Coastguard Worker     double            timeout)		/* I  - Timeout in seconds */
100*5e7646d2SAndroid Build Coastguard Worker {
101*5e7646d2SAndroid Build Coastguard Worker   char		*buffer;		/* Message buffer */
102*5e7646d2SAndroid Build Coastguard Worker   ssize_t	bytes;			/* Bytes read */
103*5e7646d2SAndroid Build Coastguard Worker   int		templen;		/* Data length from message */
104*5e7646d2SAndroid Build Coastguard Worker   int		nfds;			/* Number of file descriptors */
105*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_POLL
106*5e7646d2SAndroid Build Coastguard Worker   struct pollfd	pfd;			/* Poll structure for poll() */
107*5e7646d2SAndroid Build Coastguard Worker #else /* select() */
108*5e7646d2SAndroid Build Coastguard Worker   fd_set	input_set;		/* Input set for select() */
109*5e7646d2SAndroid Build Coastguard Worker   struct timeval stimeout;		/* Timeout value for select() */
110*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_POLL */
111*5e7646d2SAndroid Build Coastguard Worker 
112*5e7646d2SAndroid Build Coastguard Worker 
113*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsSideChannelRead(command=%p, status=%p, data=%p, "
114*5e7646d2SAndroid Build Coastguard Worker                 "datalen=%p(%d), timeout=%.3f)", command, status, data,
115*5e7646d2SAndroid Build Coastguard Worker 		datalen, datalen ? *datalen : -1, timeout));
116*5e7646d2SAndroid Build Coastguard Worker 
117*5e7646d2SAndroid Build Coastguard Worker  /*
118*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
119*5e7646d2SAndroid Build Coastguard Worker   */
120*5e7646d2SAndroid Build Coastguard Worker 
121*5e7646d2SAndroid Build Coastguard Worker   if (!command || !status)
122*5e7646d2SAndroid Build Coastguard Worker     return (-1);
123*5e7646d2SAndroid Build Coastguard Worker 
124*5e7646d2SAndroid Build Coastguard Worker  /*
125*5e7646d2SAndroid Build Coastguard Worker   * See if we have pending data on the side-channel socket...
126*5e7646d2SAndroid Build Coastguard Worker   */
127*5e7646d2SAndroid Build Coastguard Worker 
128*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_POLL
129*5e7646d2SAndroid Build Coastguard Worker   pfd.fd     = CUPS_SC_FD;
130*5e7646d2SAndroid Build Coastguard Worker   pfd.events = POLLIN;
131*5e7646d2SAndroid Build Coastguard Worker 
132*5e7646d2SAndroid Build Coastguard Worker   while ((nfds = poll(&pfd, 1,
133*5e7646d2SAndroid Build Coastguard Worker 		      timeout < 0.0 ? -1 : (int)(timeout * 1000))) < 0 &&
134*5e7646d2SAndroid Build Coastguard Worker 	 (errno == EINTR || errno == EAGAIN))
135*5e7646d2SAndroid Build Coastguard Worker     ;
136*5e7646d2SAndroid Build Coastguard Worker 
137*5e7646d2SAndroid Build Coastguard Worker #else /* select() */
138*5e7646d2SAndroid Build Coastguard Worker   FD_ZERO(&input_set);
139*5e7646d2SAndroid Build Coastguard Worker   FD_SET(CUPS_SC_FD, &input_set);
140*5e7646d2SAndroid Build Coastguard Worker 
141*5e7646d2SAndroid Build Coastguard Worker   stimeout.tv_sec  = (int)timeout;
142*5e7646d2SAndroid Build Coastguard Worker   stimeout.tv_usec = (int)(timeout * 1000000) % 1000000;
143*5e7646d2SAndroid Build Coastguard Worker 
144*5e7646d2SAndroid Build Coastguard Worker   while ((nfds = select(CUPS_SC_FD + 1, &input_set, NULL, NULL,
145*5e7646d2SAndroid Build Coastguard Worker 			timeout < 0.0 ? NULL : &stimeout)) < 0 &&
146*5e7646d2SAndroid Build Coastguard Worker 	 (errno == EINTR || errno == EAGAIN))
147*5e7646d2SAndroid Build Coastguard Worker     ;
148*5e7646d2SAndroid Build Coastguard Worker 
149*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_POLL */
150*5e7646d2SAndroid Build Coastguard Worker 
151*5e7646d2SAndroid Build Coastguard Worker   if (nfds < 1)
152*5e7646d2SAndroid Build Coastguard Worker   {
153*5e7646d2SAndroid Build Coastguard Worker     *command = CUPS_SC_CMD_NONE;
154*5e7646d2SAndroid Build Coastguard Worker     *status  = nfds==0 ? CUPS_SC_STATUS_TIMEOUT : CUPS_SC_STATUS_IO_ERROR;
155*5e7646d2SAndroid Build Coastguard Worker     return (-1);
156*5e7646d2SAndroid Build Coastguard Worker   }
157*5e7646d2SAndroid Build Coastguard Worker 
158*5e7646d2SAndroid Build Coastguard Worker  /*
159*5e7646d2SAndroid Build Coastguard Worker   * Read a side-channel message for the format:
160*5e7646d2SAndroid Build Coastguard Worker   *
161*5e7646d2SAndroid Build Coastguard Worker   * Byte(s)  Description
162*5e7646d2SAndroid Build Coastguard Worker   * -------  -------------------------------------------
163*5e7646d2SAndroid Build Coastguard Worker   * 0        Command code
164*5e7646d2SAndroid Build Coastguard Worker   * 1        Status code
165*5e7646d2SAndroid Build Coastguard Worker   * 2-3      Data length (network byte order)
166*5e7646d2SAndroid Build Coastguard Worker   * 4-N      Data
167*5e7646d2SAndroid Build Coastguard Worker   */
168*5e7646d2SAndroid Build Coastguard Worker 
169*5e7646d2SAndroid Build Coastguard Worker   if ((buffer = _cupsBufferGet(_CUPS_SC_MAX_BUFFER)) == NULL)
170*5e7646d2SAndroid Build Coastguard Worker   {
171*5e7646d2SAndroid Build Coastguard Worker     *command = CUPS_SC_CMD_NONE;
172*5e7646d2SAndroid Build Coastguard Worker     *status  = CUPS_SC_STATUS_TOO_BIG;
173*5e7646d2SAndroid Build Coastguard Worker 
174*5e7646d2SAndroid Build Coastguard Worker     return (-1);
175*5e7646d2SAndroid Build Coastguard Worker   }
176*5e7646d2SAndroid Build Coastguard Worker 
177*5e7646d2SAndroid Build Coastguard Worker   while ((bytes = read(CUPS_SC_FD, buffer, _CUPS_SC_MAX_BUFFER)) < 0)
178*5e7646d2SAndroid Build Coastguard Worker     if (errno != EINTR && errno != EAGAIN)
179*5e7646d2SAndroid Build Coastguard Worker     {
180*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("1cupsSideChannelRead: Read error: %s", strerror(errno)));
181*5e7646d2SAndroid Build Coastguard Worker 
182*5e7646d2SAndroid Build Coastguard Worker       _cupsBufferRelease(buffer);
183*5e7646d2SAndroid Build Coastguard Worker 
184*5e7646d2SAndroid Build Coastguard Worker       *command = CUPS_SC_CMD_NONE;
185*5e7646d2SAndroid Build Coastguard Worker       *status  = CUPS_SC_STATUS_IO_ERROR;
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker       return (-1);
188*5e7646d2SAndroid Build Coastguard Worker     }
189*5e7646d2SAndroid Build Coastguard Worker 
190*5e7646d2SAndroid Build Coastguard Worker  /*
191*5e7646d2SAndroid Build Coastguard Worker   * Watch for EOF or too few bytes...
192*5e7646d2SAndroid Build Coastguard Worker   */
193*5e7646d2SAndroid Build Coastguard Worker 
194*5e7646d2SAndroid Build Coastguard Worker   if (bytes < 4)
195*5e7646d2SAndroid Build Coastguard Worker   {
196*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1cupsSideChannelRead: Short read of " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
197*5e7646d2SAndroid Build Coastguard Worker 
198*5e7646d2SAndroid Build Coastguard Worker     _cupsBufferRelease(buffer);
199*5e7646d2SAndroid Build Coastguard Worker 
200*5e7646d2SAndroid Build Coastguard Worker     *command = CUPS_SC_CMD_NONE;
201*5e7646d2SAndroid Build Coastguard Worker     *status  = CUPS_SC_STATUS_BAD_MESSAGE;
202*5e7646d2SAndroid Build Coastguard Worker 
203*5e7646d2SAndroid Build Coastguard Worker     return (-1);
204*5e7646d2SAndroid Build Coastguard Worker   }
205*5e7646d2SAndroid Build Coastguard Worker 
206*5e7646d2SAndroid Build Coastguard Worker  /*
207*5e7646d2SAndroid Build Coastguard Worker   * Validate the command code in the message...
208*5e7646d2SAndroid Build Coastguard Worker   */
209*5e7646d2SAndroid Build Coastguard Worker 
210*5e7646d2SAndroid Build Coastguard Worker   if (buffer[0] < CUPS_SC_CMD_SOFT_RESET ||
211*5e7646d2SAndroid Build Coastguard Worker       buffer[0] >= CUPS_SC_CMD_MAX)
212*5e7646d2SAndroid Build Coastguard Worker   {
213*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1cupsSideChannelRead: Bad command %d!", buffer[0]));
214*5e7646d2SAndroid Build Coastguard Worker 
215*5e7646d2SAndroid Build Coastguard Worker     _cupsBufferRelease(buffer);
216*5e7646d2SAndroid Build Coastguard Worker 
217*5e7646d2SAndroid Build Coastguard Worker     *command = CUPS_SC_CMD_NONE;
218*5e7646d2SAndroid Build Coastguard Worker     *status  = CUPS_SC_STATUS_BAD_MESSAGE;
219*5e7646d2SAndroid Build Coastguard Worker 
220*5e7646d2SAndroid Build Coastguard Worker     return (-1);
221*5e7646d2SAndroid Build Coastguard Worker   }
222*5e7646d2SAndroid Build Coastguard Worker 
223*5e7646d2SAndroid Build Coastguard Worker   *command = (cups_sc_command_t)buffer[0];
224*5e7646d2SAndroid Build Coastguard Worker 
225*5e7646d2SAndroid Build Coastguard Worker  /*
226*5e7646d2SAndroid Build Coastguard Worker   * Validate the data length in the message...
227*5e7646d2SAndroid Build Coastguard Worker   */
228*5e7646d2SAndroid Build Coastguard Worker 
229*5e7646d2SAndroid Build Coastguard Worker   templen = ((buffer[2] & 255) << 8) | (buffer[3] & 255);
230*5e7646d2SAndroid Build Coastguard Worker 
231*5e7646d2SAndroid Build Coastguard Worker   if (templen > 0 && (!data || !datalen))
232*5e7646d2SAndroid Build Coastguard Worker   {
233*5e7646d2SAndroid Build Coastguard Worker    /*
234*5e7646d2SAndroid Build Coastguard Worker     * Either the response is bigger than the provided buffer or the
235*5e7646d2SAndroid Build Coastguard Worker     * response is bigger than we've read...
236*5e7646d2SAndroid Build Coastguard Worker     */
237*5e7646d2SAndroid Build Coastguard Worker 
238*5e7646d2SAndroid Build Coastguard Worker     *status = CUPS_SC_STATUS_TOO_BIG;
239*5e7646d2SAndroid Build Coastguard Worker   }
240*5e7646d2SAndroid Build Coastguard Worker   else if (!datalen || templen > *datalen || templen > (bytes - 4))
241*5e7646d2SAndroid Build Coastguard Worker   {
242*5e7646d2SAndroid Build Coastguard Worker    /*
243*5e7646d2SAndroid Build Coastguard Worker     * Either the response is bigger than the provided buffer or the
244*5e7646d2SAndroid Build Coastguard Worker     * response is bigger than we've read...
245*5e7646d2SAndroid Build Coastguard Worker     */
246*5e7646d2SAndroid Build Coastguard Worker 
247*5e7646d2SAndroid Build Coastguard Worker     *status = CUPS_SC_STATUS_TOO_BIG;
248*5e7646d2SAndroid Build Coastguard Worker   }
249*5e7646d2SAndroid Build Coastguard Worker   else
250*5e7646d2SAndroid Build Coastguard Worker   {
251*5e7646d2SAndroid Build Coastguard Worker    /*
252*5e7646d2SAndroid Build Coastguard Worker     * The response data will fit, copy it over and provide the actual
253*5e7646d2SAndroid Build Coastguard Worker     * length...
254*5e7646d2SAndroid Build Coastguard Worker     */
255*5e7646d2SAndroid Build Coastguard Worker 
256*5e7646d2SAndroid Build Coastguard Worker     *status  = (cups_sc_status_t)buffer[1];
257*5e7646d2SAndroid Build Coastguard Worker     *datalen = templen;
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker     memcpy(data, buffer + 4, (size_t)templen);
260*5e7646d2SAndroid Build Coastguard Worker   }
261*5e7646d2SAndroid Build Coastguard Worker 
262*5e7646d2SAndroid Build Coastguard Worker   _cupsBufferRelease(buffer);
263*5e7646d2SAndroid Build Coastguard Worker 
264*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1cupsSideChannelRead: Returning status=%d", *status));
265*5e7646d2SAndroid Build Coastguard Worker 
266*5e7646d2SAndroid Build Coastguard Worker   return (0);
267*5e7646d2SAndroid Build Coastguard Worker }
268*5e7646d2SAndroid Build Coastguard Worker 
269*5e7646d2SAndroid Build Coastguard Worker 
270*5e7646d2SAndroid Build Coastguard Worker /*
271*5e7646d2SAndroid Build Coastguard Worker  * 'cupsSideChannelSNMPGet()' - Query a SNMP OID's value.
272*5e7646d2SAndroid Build Coastguard Worker  *
273*5e7646d2SAndroid Build Coastguard Worker  * This function asks the backend to do a SNMP OID query on behalf of the
274*5e7646d2SAndroid Build Coastguard Worker  * filter, port monitor, or backend using the default community name.
275*5e7646d2SAndroid Build Coastguard Worker  *
276*5e7646d2SAndroid Build Coastguard Worker  * "oid" contains a numeric OID consisting of integers separated by periods,
277*5e7646d2SAndroid Build Coastguard Worker  * for example ".1.3.6.1.2.1.43".  Symbolic names from SNMP MIBs are not
278*5e7646d2SAndroid Build Coastguard Worker  * supported and must be converted to their numeric forms.
279*5e7646d2SAndroid Build Coastguard Worker  *
280*5e7646d2SAndroid Build Coastguard Worker  * On input, "data" and "datalen" provide the location and size of the
281*5e7646d2SAndroid Build Coastguard Worker  * buffer to hold the OID value as a string. HEX-String (binary) values are
282*5e7646d2SAndroid Build Coastguard Worker  * converted to hexadecimal strings representing the binary data, while
283*5e7646d2SAndroid Build Coastguard Worker  * NULL-Value and unknown OID types are returned as the empty string.
284*5e7646d2SAndroid Build Coastguard Worker  * The returned "datalen" does not include the trailing nul.
285*5e7646d2SAndroid Build Coastguard Worker  *
286*5e7646d2SAndroid Build Coastguard Worker  * @code CUPS_SC_STATUS_NOT_IMPLEMENTED@ is returned by backends that do not
287*5e7646d2SAndroid Build Coastguard Worker  * support SNMP queries.  @code CUPS_SC_STATUS_NO_RESPONSE@ is returned when
288*5e7646d2SAndroid Build Coastguard Worker  * the printer does not respond to the SNMP query.
289*5e7646d2SAndroid Build Coastguard Worker  *
290*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.4/macOS 10.6@
291*5e7646d2SAndroid Build Coastguard Worker  */
292*5e7646d2SAndroid Build Coastguard Worker 
293*5e7646d2SAndroid Build Coastguard Worker cups_sc_status_t			/* O  - Query status */
cupsSideChannelSNMPGet(const char * oid,char * data,int * datalen,double timeout)294*5e7646d2SAndroid Build Coastguard Worker cupsSideChannelSNMPGet(
295*5e7646d2SAndroid Build Coastguard Worker     const char *oid,			/* I  - OID to query */
296*5e7646d2SAndroid Build Coastguard Worker     char       *data,			/* I  - Buffer for OID value */
297*5e7646d2SAndroid Build Coastguard Worker     int        *datalen,		/* IO - Size of OID buffer on entry, size of value on return */
298*5e7646d2SAndroid Build Coastguard Worker     double     timeout)			/* I  - Timeout in seconds */
299*5e7646d2SAndroid Build Coastguard Worker {
300*5e7646d2SAndroid Build Coastguard Worker   cups_sc_status_t	status;		/* Status of command */
301*5e7646d2SAndroid Build Coastguard Worker   cups_sc_command_t	rcommand;	/* Response command */
302*5e7646d2SAndroid Build Coastguard Worker   char			*real_data;	/* Real data buffer for response */
303*5e7646d2SAndroid Build Coastguard Worker   int			real_datalen,	/* Real length of data buffer */
304*5e7646d2SAndroid Build Coastguard Worker 			real_oidlen;	/* Length of returned OID string */
305*5e7646d2SAndroid Build Coastguard Worker 
306*5e7646d2SAndroid Build Coastguard Worker 
307*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsSideChannelSNMPGet(oid=\"%s\", data=%p, datalen=%p(%d), "
308*5e7646d2SAndroid Build Coastguard Worker                 "timeout=%.3f)", oid, data, datalen, datalen ? *datalen : -1,
309*5e7646d2SAndroid Build Coastguard Worker 		timeout));
310*5e7646d2SAndroid Build Coastguard Worker 
311*5e7646d2SAndroid Build Coastguard Worker  /*
312*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
313*5e7646d2SAndroid Build Coastguard Worker   */
314*5e7646d2SAndroid Build Coastguard Worker 
315*5e7646d2SAndroid Build Coastguard Worker   if (!oid || !*oid || !data || !datalen || *datalen < 2)
316*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_BAD_MESSAGE);
317*5e7646d2SAndroid Build Coastguard Worker 
318*5e7646d2SAndroid Build Coastguard Worker   *data = '\0';
319*5e7646d2SAndroid Build Coastguard Worker 
320*5e7646d2SAndroid Build Coastguard Worker  /*
321*5e7646d2SAndroid Build Coastguard Worker   * Send the request to the backend and wait for a response...
322*5e7646d2SAndroid Build Coastguard Worker   */
323*5e7646d2SAndroid Build Coastguard Worker 
324*5e7646d2SAndroid Build Coastguard Worker   if (cupsSideChannelWrite(CUPS_SC_CMD_SNMP_GET, CUPS_SC_STATUS_NONE, oid,
325*5e7646d2SAndroid Build Coastguard Worker                            (int)strlen(oid) + 1, timeout))
326*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_TIMEOUT);
327*5e7646d2SAndroid Build Coastguard Worker 
328*5e7646d2SAndroid Build Coastguard Worker   if ((real_data = _cupsBufferGet(_CUPS_SC_MAX_BUFFER)) == NULL)
329*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_TOO_BIG);
330*5e7646d2SAndroid Build Coastguard Worker 
331*5e7646d2SAndroid Build Coastguard Worker   real_datalen = _CUPS_SC_MAX_BUFFER;
332*5e7646d2SAndroid Build Coastguard Worker   if (cupsSideChannelRead(&rcommand, &status, real_data, &real_datalen, timeout))
333*5e7646d2SAndroid Build Coastguard Worker   {
334*5e7646d2SAndroid Build Coastguard Worker     _cupsBufferRelease(real_data);
335*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_TIMEOUT);
336*5e7646d2SAndroid Build Coastguard Worker   }
337*5e7646d2SAndroid Build Coastguard Worker 
338*5e7646d2SAndroid Build Coastguard Worker   if (rcommand != CUPS_SC_CMD_SNMP_GET)
339*5e7646d2SAndroid Build Coastguard Worker   {
340*5e7646d2SAndroid Build Coastguard Worker     _cupsBufferRelease(real_data);
341*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_BAD_MESSAGE);
342*5e7646d2SAndroid Build Coastguard Worker   }
343*5e7646d2SAndroid Build Coastguard Worker 
344*5e7646d2SAndroid Build Coastguard Worker   if (status == CUPS_SC_STATUS_OK)
345*5e7646d2SAndroid Build Coastguard Worker   {
346*5e7646d2SAndroid Build Coastguard Worker    /*
347*5e7646d2SAndroid Build Coastguard Worker     * Parse the response of the form "oid\0value"...
348*5e7646d2SAndroid Build Coastguard Worker     */
349*5e7646d2SAndroid Build Coastguard Worker 
350*5e7646d2SAndroid Build Coastguard Worker     real_oidlen  = (int)strlen(real_data) + 1;
351*5e7646d2SAndroid Build Coastguard Worker     real_datalen -= real_oidlen;
352*5e7646d2SAndroid Build Coastguard Worker 
353*5e7646d2SAndroid Build Coastguard Worker     if ((real_datalen + 1) > *datalen)
354*5e7646d2SAndroid Build Coastguard Worker     {
355*5e7646d2SAndroid Build Coastguard Worker       _cupsBufferRelease(real_data);
356*5e7646d2SAndroid Build Coastguard Worker       return (CUPS_SC_STATUS_TOO_BIG);
357*5e7646d2SAndroid Build Coastguard Worker     }
358*5e7646d2SAndroid Build Coastguard Worker 
359*5e7646d2SAndroid Build Coastguard Worker     memcpy(data, real_data + real_oidlen, (size_t)real_datalen);
360*5e7646d2SAndroid Build Coastguard Worker     data[real_datalen] = '\0';
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker     *datalen = real_datalen;
363*5e7646d2SAndroid Build Coastguard Worker   }
364*5e7646d2SAndroid Build Coastguard Worker 
365*5e7646d2SAndroid Build Coastguard Worker   _cupsBufferRelease(real_data);
366*5e7646d2SAndroid Build Coastguard Worker 
367*5e7646d2SAndroid Build Coastguard Worker   return (status);
368*5e7646d2SAndroid Build Coastguard Worker }
369*5e7646d2SAndroid Build Coastguard Worker 
370*5e7646d2SAndroid Build Coastguard Worker 
371*5e7646d2SAndroid Build Coastguard Worker /*
372*5e7646d2SAndroid Build Coastguard Worker  * 'cupsSideChannelSNMPWalk()' - Query multiple SNMP OID values.
373*5e7646d2SAndroid Build Coastguard Worker  *
374*5e7646d2SAndroid Build Coastguard Worker  * This function asks the backend to do multiple SNMP OID queries on behalf
375*5e7646d2SAndroid Build Coastguard Worker  * of the filter, port monitor, or backend using the default community name.
376*5e7646d2SAndroid Build Coastguard Worker  * All OIDs under the "parent" OID are queried and the results are sent to
377*5e7646d2SAndroid Build Coastguard Worker  * the callback function you provide.
378*5e7646d2SAndroid Build Coastguard Worker  *
379*5e7646d2SAndroid Build Coastguard Worker  * "oid" contains a numeric OID consisting of integers separated by periods,
380*5e7646d2SAndroid Build Coastguard Worker  * for example ".1.3.6.1.2.1.43".  Symbolic names from SNMP MIBs are not
381*5e7646d2SAndroid Build Coastguard Worker  * supported and must be converted to their numeric forms.
382*5e7646d2SAndroid Build Coastguard Worker  *
383*5e7646d2SAndroid Build Coastguard Worker  * "timeout" specifies the timeout for each OID query. The total amount of
384*5e7646d2SAndroid Build Coastguard Worker  * time will depend on the number of OID values found and the time required
385*5e7646d2SAndroid Build Coastguard Worker  * for each query.
386*5e7646d2SAndroid Build Coastguard Worker  *
387*5e7646d2SAndroid Build Coastguard Worker  * "cb" provides a function to call for every value that is found. "context"
388*5e7646d2SAndroid Build Coastguard Worker  * is an application-defined pointer that is sent to the callback function
389*5e7646d2SAndroid Build Coastguard Worker  * along with the OID and current data. The data passed to the callback is the
390*5e7646d2SAndroid Build Coastguard Worker  * same as returned by @link cupsSideChannelSNMPGet@.
391*5e7646d2SAndroid Build Coastguard Worker  *
392*5e7646d2SAndroid Build Coastguard Worker  * @code CUPS_SC_STATUS_NOT_IMPLEMENTED@ is returned by backends that do not
393*5e7646d2SAndroid Build Coastguard Worker  * support SNMP queries.  @code CUPS_SC_STATUS_NO_RESPONSE@ is returned when
394*5e7646d2SAndroid Build Coastguard Worker  * the printer does not respond to the first SNMP query.
395*5e7646d2SAndroid Build Coastguard Worker  *
396*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.4/macOS 10.6@
397*5e7646d2SAndroid Build Coastguard Worker  */
398*5e7646d2SAndroid Build Coastguard Worker 
399*5e7646d2SAndroid Build Coastguard Worker cups_sc_status_t			/* O - Status of first query of @code CUPS_SC_STATUS_OK@ on success */
cupsSideChannelSNMPWalk(const char * oid,double timeout,cups_sc_walk_func_t cb,void * context)400*5e7646d2SAndroid Build Coastguard Worker cupsSideChannelSNMPWalk(
401*5e7646d2SAndroid Build Coastguard Worker     const char          *oid,		/* I - First numeric OID to query */
402*5e7646d2SAndroid Build Coastguard Worker     double              timeout,	/* I - Timeout for each query in seconds */
403*5e7646d2SAndroid Build Coastguard Worker     cups_sc_walk_func_t cb,		/* I - Function to call with each value */
404*5e7646d2SAndroid Build Coastguard Worker     void                *context)	/* I - Application-defined pointer to send to callback */
405*5e7646d2SAndroid Build Coastguard Worker {
406*5e7646d2SAndroid Build Coastguard Worker   cups_sc_status_t	status;		/* Status of command */
407*5e7646d2SAndroid Build Coastguard Worker   cups_sc_command_t	rcommand;	/* Response command */
408*5e7646d2SAndroid Build Coastguard Worker   char			*real_data;	/* Real data buffer for response */
409*5e7646d2SAndroid Build Coastguard Worker   int			real_datalen;	/* Real length of data buffer */
410*5e7646d2SAndroid Build Coastguard Worker   size_t		real_oidlen,	/* Length of returned OID string */
411*5e7646d2SAndroid Build Coastguard Worker 			oidlen;		/* Length of first OID */
412*5e7646d2SAndroid Build Coastguard Worker   const char		*current_oid;	/* Current OID */
413*5e7646d2SAndroid Build Coastguard Worker   char			last_oid[2048];	/* Last OID */
414*5e7646d2SAndroid Build Coastguard Worker 
415*5e7646d2SAndroid Build Coastguard Worker 
416*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsSideChannelSNMPWalk(oid=\"%s\", timeout=%.3f, cb=%p, "
417*5e7646d2SAndroid Build Coastguard Worker                 "context=%p)", oid, timeout, cb, context));
418*5e7646d2SAndroid Build Coastguard Worker 
419*5e7646d2SAndroid Build Coastguard Worker  /*
420*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
421*5e7646d2SAndroid Build Coastguard Worker   */
422*5e7646d2SAndroid Build Coastguard Worker 
423*5e7646d2SAndroid Build Coastguard Worker   if (!oid || !*oid || !cb)
424*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_BAD_MESSAGE);
425*5e7646d2SAndroid Build Coastguard Worker 
426*5e7646d2SAndroid Build Coastguard Worker   if ((real_data = _cupsBufferGet(_CUPS_SC_MAX_BUFFER)) == NULL)
427*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_SC_STATUS_TOO_BIG);
428*5e7646d2SAndroid Build Coastguard Worker 
429*5e7646d2SAndroid Build Coastguard Worker  /*
430*5e7646d2SAndroid Build Coastguard Worker   * Loop until the OIDs don't match...
431*5e7646d2SAndroid Build Coastguard Worker   */
432*5e7646d2SAndroid Build Coastguard Worker 
433*5e7646d2SAndroid Build Coastguard Worker   current_oid = oid;
434*5e7646d2SAndroid Build Coastguard Worker   oidlen      = strlen(oid);
435*5e7646d2SAndroid Build Coastguard Worker   last_oid[0] = '\0';
436*5e7646d2SAndroid Build Coastguard Worker 
437*5e7646d2SAndroid Build Coastguard Worker   do
438*5e7646d2SAndroid Build Coastguard Worker   {
439*5e7646d2SAndroid Build Coastguard Worker    /*
440*5e7646d2SAndroid Build Coastguard Worker     * Send the request to the backend and wait for a response...
441*5e7646d2SAndroid Build Coastguard Worker     */
442*5e7646d2SAndroid Build Coastguard Worker 
443*5e7646d2SAndroid Build Coastguard Worker     if (cupsSideChannelWrite(CUPS_SC_CMD_SNMP_GET_NEXT, CUPS_SC_STATUS_NONE,
444*5e7646d2SAndroid Build Coastguard Worker                              current_oid, (int)strlen(current_oid) + 1, timeout))
445*5e7646d2SAndroid Build Coastguard Worker     {
446*5e7646d2SAndroid Build Coastguard Worker       _cupsBufferRelease(real_data);
447*5e7646d2SAndroid Build Coastguard Worker       return (CUPS_SC_STATUS_TIMEOUT);
448*5e7646d2SAndroid Build Coastguard Worker     }
449*5e7646d2SAndroid Build Coastguard Worker 
450*5e7646d2SAndroid Build Coastguard Worker     real_datalen = _CUPS_SC_MAX_BUFFER;
451*5e7646d2SAndroid Build Coastguard Worker     if (cupsSideChannelRead(&rcommand, &status, real_data, &real_datalen,
452*5e7646d2SAndroid Build Coastguard Worker                             timeout))
453*5e7646d2SAndroid Build Coastguard Worker     {
454*5e7646d2SAndroid Build Coastguard Worker       _cupsBufferRelease(real_data);
455*5e7646d2SAndroid Build Coastguard Worker       return (CUPS_SC_STATUS_TIMEOUT);
456*5e7646d2SAndroid Build Coastguard Worker     }
457*5e7646d2SAndroid Build Coastguard Worker 
458*5e7646d2SAndroid Build Coastguard Worker     if (rcommand != CUPS_SC_CMD_SNMP_GET_NEXT)
459*5e7646d2SAndroid Build Coastguard Worker     {
460*5e7646d2SAndroid Build Coastguard Worker       _cupsBufferRelease(real_data);
461*5e7646d2SAndroid Build Coastguard Worker       return (CUPS_SC_STATUS_BAD_MESSAGE);
462*5e7646d2SAndroid Build Coastguard Worker     }
463*5e7646d2SAndroid Build Coastguard Worker 
464*5e7646d2SAndroid Build Coastguard Worker     if (status == CUPS_SC_STATUS_OK)
465*5e7646d2SAndroid Build Coastguard Worker     {
466*5e7646d2SAndroid Build Coastguard Worker      /*
467*5e7646d2SAndroid Build Coastguard Worker       * Parse the response of the form "oid\0value"...
468*5e7646d2SAndroid Build Coastguard Worker       */
469*5e7646d2SAndroid Build Coastguard Worker 
470*5e7646d2SAndroid Build Coastguard Worker       if (strncmp(real_data, oid, oidlen) || real_data[oidlen] != '.' ||
471*5e7646d2SAndroid Build Coastguard Worker           !strcmp(real_data, last_oid))
472*5e7646d2SAndroid Build Coastguard Worker       {
473*5e7646d2SAndroid Build Coastguard Worker        /*
474*5e7646d2SAndroid Build Coastguard Worker         * Done with this set of OIDs...
475*5e7646d2SAndroid Build Coastguard Worker 	*/
476*5e7646d2SAndroid Build Coastguard Worker 
477*5e7646d2SAndroid Build Coastguard Worker 	_cupsBufferRelease(real_data);
478*5e7646d2SAndroid Build Coastguard Worker         return (CUPS_SC_STATUS_OK);
479*5e7646d2SAndroid Build Coastguard Worker       }
480*5e7646d2SAndroid Build Coastguard Worker 
481*5e7646d2SAndroid Build Coastguard Worker       if ((size_t)real_datalen < sizeof(real_data))
482*5e7646d2SAndroid Build Coastguard Worker         real_data[real_datalen] = '\0';
483*5e7646d2SAndroid Build Coastguard Worker 
484*5e7646d2SAndroid Build Coastguard Worker       real_oidlen  = strlen(real_data) + 1;
485*5e7646d2SAndroid Build Coastguard Worker       real_datalen -= (int)real_oidlen;
486*5e7646d2SAndroid Build Coastguard Worker 
487*5e7646d2SAndroid Build Coastguard Worker      /*
488*5e7646d2SAndroid Build Coastguard Worker       * Call the callback with the OID and data...
489*5e7646d2SAndroid Build Coastguard Worker       */
490*5e7646d2SAndroid Build Coastguard Worker 
491*5e7646d2SAndroid Build Coastguard Worker       (*cb)(real_data, real_data + real_oidlen, real_datalen, context);
492*5e7646d2SAndroid Build Coastguard Worker 
493*5e7646d2SAndroid Build Coastguard Worker      /*
494*5e7646d2SAndroid Build Coastguard Worker       * Update the current OID...
495*5e7646d2SAndroid Build Coastguard Worker       */
496*5e7646d2SAndroid Build Coastguard Worker 
497*5e7646d2SAndroid Build Coastguard Worker       current_oid = real_data;
498*5e7646d2SAndroid Build Coastguard Worker       strlcpy(last_oid, current_oid, sizeof(last_oid));
499*5e7646d2SAndroid Build Coastguard Worker     }
500*5e7646d2SAndroid Build Coastguard Worker   }
501*5e7646d2SAndroid Build Coastguard Worker   while (status == CUPS_SC_STATUS_OK);
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker   _cupsBufferRelease(real_data);
504*5e7646d2SAndroid Build Coastguard Worker 
505*5e7646d2SAndroid Build Coastguard Worker   return (status);
506*5e7646d2SAndroid Build Coastguard Worker }
507*5e7646d2SAndroid Build Coastguard Worker 
508*5e7646d2SAndroid Build Coastguard Worker 
509*5e7646d2SAndroid Build Coastguard Worker /*
510*5e7646d2SAndroid Build Coastguard Worker  * 'cupsSideChannelWrite()' - Write a side-channel message.
511*5e7646d2SAndroid Build Coastguard Worker  *
512*5e7646d2SAndroid Build Coastguard Worker  * This function is normally only called by backend programs to send
513*5e7646d2SAndroid Build Coastguard Worker  * responses to a filter, driver, or port monitor program.
514*5e7646d2SAndroid Build Coastguard Worker  *
515*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.3/macOS 10.5@
516*5e7646d2SAndroid Build Coastguard Worker  */
517*5e7646d2SAndroid Build Coastguard Worker 
518*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on error */
cupsSideChannelWrite(cups_sc_command_t command,cups_sc_status_t status,const char * data,int datalen,double timeout)519*5e7646d2SAndroid Build Coastguard Worker cupsSideChannelWrite(
520*5e7646d2SAndroid Build Coastguard Worker     cups_sc_command_t command,		/* I - Command code */
521*5e7646d2SAndroid Build Coastguard Worker     cups_sc_status_t  status,		/* I - Status code */
522*5e7646d2SAndroid Build Coastguard Worker     const char        *data,		/* I - Data buffer pointer */
523*5e7646d2SAndroid Build Coastguard Worker     int               datalen,		/* I - Number of bytes of data */
524*5e7646d2SAndroid Build Coastguard Worker     double            timeout)		/* I - Timeout in seconds */
525*5e7646d2SAndroid Build Coastguard Worker {
526*5e7646d2SAndroid Build Coastguard Worker   char		*buffer;		/* Message buffer */
527*5e7646d2SAndroid Build Coastguard Worker   ssize_t	bytes;			/* Bytes written */
528*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_POLL
529*5e7646d2SAndroid Build Coastguard Worker   struct pollfd	pfd;			/* Poll structure for poll() */
530*5e7646d2SAndroid Build Coastguard Worker #else /* select() */
531*5e7646d2SAndroid Build Coastguard Worker   fd_set	output_set;		/* Output set for select() */
532*5e7646d2SAndroid Build Coastguard Worker   struct timeval stimeout;		/* Timeout value for select() */
533*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_POLL */
534*5e7646d2SAndroid Build Coastguard Worker 
535*5e7646d2SAndroid Build Coastguard Worker 
536*5e7646d2SAndroid Build Coastguard Worker  /*
537*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
538*5e7646d2SAndroid Build Coastguard Worker   */
539*5e7646d2SAndroid Build Coastguard Worker 
540*5e7646d2SAndroid Build Coastguard Worker   if (command < CUPS_SC_CMD_SOFT_RESET || command >= CUPS_SC_CMD_MAX ||
541*5e7646d2SAndroid Build Coastguard Worker       datalen < 0 || datalen > _CUPS_SC_MAX_DATA || (datalen > 0 && !data))
542*5e7646d2SAndroid Build Coastguard Worker     return (-1);
543*5e7646d2SAndroid Build Coastguard Worker 
544*5e7646d2SAndroid Build Coastguard Worker  /*
545*5e7646d2SAndroid Build Coastguard Worker   * See if we can safely write to the side-channel socket...
546*5e7646d2SAndroid Build Coastguard Worker   */
547*5e7646d2SAndroid Build Coastguard Worker 
548*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_POLL
549*5e7646d2SAndroid Build Coastguard Worker   pfd.fd     = CUPS_SC_FD;
550*5e7646d2SAndroid Build Coastguard Worker   pfd.events = POLLOUT;
551*5e7646d2SAndroid Build Coastguard Worker 
552*5e7646d2SAndroid Build Coastguard Worker   if (timeout < 0.0)
553*5e7646d2SAndroid Build Coastguard Worker   {
554*5e7646d2SAndroid Build Coastguard Worker     if (poll(&pfd, 1, -1) < 1)
555*5e7646d2SAndroid Build Coastguard Worker       return (-1);
556*5e7646d2SAndroid Build Coastguard Worker   }
557*5e7646d2SAndroid Build Coastguard Worker   else if (poll(&pfd, 1, (int)(timeout * 1000)) < 1)
558*5e7646d2SAndroid Build Coastguard Worker     return (-1);
559*5e7646d2SAndroid Build Coastguard Worker 
560*5e7646d2SAndroid Build Coastguard Worker #else /* select() */
561*5e7646d2SAndroid Build Coastguard Worker   FD_ZERO(&output_set);
562*5e7646d2SAndroid Build Coastguard Worker   FD_SET(CUPS_SC_FD, &output_set);
563*5e7646d2SAndroid Build Coastguard Worker 
564*5e7646d2SAndroid Build Coastguard Worker   if (timeout < 0.0)
565*5e7646d2SAndroid Build Coastguard Worker   {
566*5e7646d2SAndroid Build Coastguard Worker     if (select(CUPS_SC_FD + 1, NULL, &output_set, NULL, NULL) < 1)
567*5e7646d2SAndroid Build Coastguard Worker       return (-1);
568*5e7646d2SAndroid Build Coastguard Worker   }
569*5e7646d2SAndroid Build Coastguard Worker   else
570*5e7646d2SAndroid Build Coastguard Worker   {
571*5e7646d2SAndroid Build Coastguard Worker     stimeout.tv_sec  = (int)timeout;
572*5e7646d2SAndroid Build Coastguard Worker     stimeout.tv_usec = (int)(timeout * 1000000) % 1000000;
573*5e7646d2SAndroid Build Coastguard Worker 
574*5e7646d2SAndroid Build Coastguard Worker     if (select(CUPS_SC_FD + 1, NULL, &output_set, NULL, &stimeout) < 1)
575*5e7646d2SAndroid Build Coastguard Worker       return (-1);
576*5e7646d2SAndroid Build Coastguard Worker   }
577*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_POLL */
578*5e7646d2SAndroid Build Coastguard Worker 
579*5e7646d2SAndroid Build Coastguard Worker  /*
580*5e7646d2SAndroid Build Coastguard Worker   * Write a side-channel message in the format:
581*5e7646d2SAndroid Build Coastguard Worker   *
582*5e7646d2SAndroid Build Coastguard Worker   * Byte(s)  Description
583*5e7646d2SAndroid Build Coastguard Worker   * -------  -------------------------------------------
584*5e7646d2SAndroid Build Coastguard Worker   * 0        Command code
585*5e7646d2SAndroid Build Coastguard Worker   * 1        Status code
586*5e7646d2SAndroid Build Coastguard Worker   * 2-3      Data length (network byte order) <= 16384
587*5e7646d2SAndroid Build Coastguard Worker   * 4-N      Data
588*5e7646d2SAndroid Build Coastguard Worker   */
589*5e7646d2SAndroid Build Coastguard Worker 
590*5e7646d2SAndroid Build Coastguard Worker   if ((buffer = _cupsBufferGet((size_t)datalen + 4)) == NULL)
591*5e7646d2SAndroid Build Coastguard Worker     return (-1);
592*5e7646d2SAndroid Build Coastguard Worker 
593*5e7646d2SAndroid Build Coastguard Worker   buffer[0] = (char)command;
594*5e7646d2SAndroid Build Coastguard Worker   buffer[1] = (char)status;
595*5e7646d2SAndroid Build Coastguard Worker   buffer[2] = (char)(datalen >> 8);
596*5e7646d2SAndroid Build Coastguard Worker   buffer[3] = (char)(datalen & 255);
597*5e7646d2SAndroid Build Coastguard Worker 
598*5e7646d2SAndroid Build Coastguard Worker   bytes = 4;
599*5e7646d2SAndroid Build Coastguard Worker 
600*5e7646d2SAndroid Build Coastguard Worker   if (datalen > 0)
601*5e7646d2SAndroid Build Coastguard Worker   {
602*5e7646d2SAndroid Build Coastguard Worker     memcpy(buffer + 4, data, (size_t)datalen);
603*5e7646d2SAndroid Build Coastguard Worker     bytes += datalen;
604*5e7646d2SAndroid Build Coastguard Worker   }
605*5e7646d2SAndroid Build Coastguard Worker 
606*5e7646d2SAndroid Build Coastguard Worker   while (write(CUPS_SC_FD, buffer, (size_t)bytes) < 0)
607*5e7646d2SAndroid Build Coastguard Worker     if (errno != EINTR && errno != EAGAIN)
608*5e7646d2SAndroid Build Coastguard Worker     {
609*5e7646d2SAndroid Build Coastguard Worker       _cupsBufferRelease(buffer);
610*5e7646d2SAndroid Build Coastguard Worker       return (-1);
611*5e7646d2SAndroid Build Coastguard Worker     }
612*5e7646d2SAndroid Build Coastguard Worker 
613*5e7646d2SAndroid Build Coastguard Worker   _cupsBufferRelease(buffer);
614*5e7646d2SAndroid Build Coastguard Worker 
615*5e7646d2SAndroid Build Coastguard Worker   return (0);
616*5e7646d2SAndroid Build Coastguard Worker }
617