2 * Common backend network APIs for CUPS.
4 * Copyright © 2007-2016 by Apple Inc.
5 * Copyright © 2006-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * Include necessary headers.
15 #include "backend-private.h"
17 #include <sys/select.h>
21 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
25 backendCheckSideChannel(
26 int snmp_fd
, /* I - SNMP socket */
27 http_addr_t
*addr
) /* I - Address of device */
29 fd_set input
; /* Select input set */
30 struct timeval timeout
; /* Select timeout */
34 FD_SET(CUPS_SC_FD
, &input
);
36 timeout
.tv_sec
= timeout
.tv_usec
= 0;
38 if (select(CUPS_SC_FD
+ 1, &input
, NULL
, NULL
, &timeout
) > 0)
39 backendNetworkSideCB(-1, -1, snmp_fd
, addr
, 0);
44 * 'backendLookup()' - Lookup the given host and log addresses.
47 http_addrlist_t
* /* O - List of addresses or NULL */
48 backendLookup(const char *hostname
, /* I - Hostname */
49 int port
, /* I - Port number */
50 int *cancel
) /* I - Variable to watch for job cancel */
52 char portname
[32], /* Port number as string */
53 addrname
[256]; /* Address as string */
54 http_addrlist_t
*addrlist
, /* List of addresses */
55 *current
; /* Current address */
59 * Lookup the address for the named host...
62 snprintf(portname
, sizeof(portname
), "%d", port
);
64 fputs("STATE: +connecting-to-device\n", stderr
);
65 fprintf(stderr
, "DEBUG: Looking up \"%s\"...\n", hostname
);
67 while ((addrlist
= httpAddrGetList(hostname
, AF_UNSPEC
, portname
)) == NULL
)
69 _cupsLangPrintFilter(stderr
, "INFO", _("Unable to locate printer \"%s\"."), hostname
);
72 if (getenv("CLASS") != NULL
)
74 fputs("STATE: -connecting-to-device\n", stderr
);
75 exit(CUPS_BACKEND_STOP
);
78 if (cancel
&& *cancel
)
80 fputs("STATE: -connecting-to-device\n", stderr
);
81 exit(CUPS_BACKEND_OK
);
85 fputs("STATE: -connecting-to-device\n", stderr
);
88 * Log the addresses we got...
91 for (current
= addrlist
; current
; current
= current
->next
)
92 fprintf(stderr
, "DEBUG: %s=%s\n", hostname
, httpAddrString(¤t
->addr
, addrname
, sizeof(addrname
)));
103 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
106 int /* O - -1 on error, 0 on success */
107 backendNetworkSideCB(
108 int print_fd
, /* I - Print file or -1 */
109 int device_fd
, /* I - Device file or -1 */
110 int snmp_fd
, /* I - SNMP socket */
111 http_addr_t
*addr
, /* I - Address of device */
112 int use_bc
) /* I - Use back-channel data? */
114 cups_sc_command_t command
; /* Request command */
115 cups_sc_status_t status
; /* Request/response status */
116 char data
[65536]; /* Request/response data */
117 int datalen
; /* Request/response data size */
118 const char *device_id
; /* 1284DEVICEID env var */
121 datalen
= sizeof(data
);
123 if (cupsSideChannelRead(&command
, &status
, data
, &datalen
, 1.0))
128 case CUPS_SC_CMD_DRAIN_OUTPUT
:
130 * Our sockets disable the Nagle algorithm and data is sent immediately.
134 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
135 else if (backendDrainOutput(print_fd
, device_fd
))
136 status
= CUPS_SC_STATUS_IO_ERROR
;
138 status
= CUPS_SC_STATUS_OK
;
143 case CUPS_SC_CMD_GET_BIDI
:
144 status
= CUPS_SC_STATUS_OK
;
145 data
[0] = (char)use_bc
;
149 case CUPS_SC_CMD_SNMP_GET
:
150 case CUPS_SC_CMD_SNMP_GET_NEXT
:
151 fprintf(stderr
, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n",
152 command
== CUPS_SC_CMD_SNMP_GET
? "GET" : "GET_NEXT", datalen
,
157 status
= CUPS_SC_STATUS_BAD_MESSAGE
;
164 char *dataptr
; /* Pointer into data */
165 cups_snmp_t packet
; /* Packet from printer */
166 const char *snmp_value
; /* CUPS_SNMP_VALUE env var */
168 if ((snmp_value
= getenv("CUPS_SNMP_VALUE")) != NULL
)
170 const char *snmp_count
; /* CUPS_SNMP_COUNT env var */
171 int count
; /* Repetition count */
173 if ((snmp_count
= getenv("CUPS_SNMP_COUNT")) != NULL
)
175 if ((count
= atoi(snmp_count
)) <= 0)
181 for (dataptr
= data
+ strlen(data
) + 1;
182 count
> 0 && dataptr
< (data
+ sizeof(data
) - 1);
183 count
--, dataptr
+= strlen(dataptr
))
184 strlcpy(dataptr
, snmp_value
, sizeof(data
) - (size_t)(dataptr
- data
));
186 fprintf(stderr
, "DEBUG: Returning %s %s\n", data
,
187 data
+ strlen(data
) + 1);
189 status
= CUPS_SC_STATUS_OK
;
190 datalen
= (int)(dataptr
- data
);
194 if (!_cupsSNMPStringToOID(data
, packet
.object_name
, CUPS_SNMP_MAX_OID
))
196 status
= CUPS_SC_STATUS_BAD_MESSAGE
;
201 status
= CUPS_SC_STATUS_IO_ERROR
;
204 if (_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
205 _cupsSNMPDefaultCommunity(),
206 command
== CUPS_SC_CMD_SNMP_GET
?
207 CUPS_ASN1_GET_REQUEST
:
208 CUPS_ASN1_GET_NEXT_REQUEST
, 1,
211 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0))
213 size_t i
; /* Looping var */
216 if (!_cupsSNMPOIDToString(packet
.object_name
, data
, sizeof(data
)))
218 fputs("DEBUG: Bad OID returned!\n", stderr
);
222 datalen
= (int)strlen(data
) + 1;
223 dataptr
= data
+ datalen
;
225 switch (packet
.object_type
)
227 case CUPS_ASN1_BOOLEAN
:
228 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%d", packet
.object_value
.boolean
);
229 datalen
+= (int)strlen(dataptr
);
232 case CUPS_ASN1_INTEGER
:
233 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%d",
234 packet
.object_value
.integer
);
235 datalen
+= (int)strlen(dataptr
);
238 case CUPS_ASN1_BIT_STRING
:
239 case CUPS_ASN1_OCTET_STRING
:
240 if (packet
.object_value
.string
.num_bytes
< (sizeof(data
) - (size_t)(dataptr
- data
)))
241 i
= packet
.object_value
.string
.num_bytes
;
243 i
= sizeof(data
) - (size_t)(dataptr
- data
);
245 memcpy(dataptr
, packet
.object_value
.string
.bytes
, i
);
251 _cupsSNMPOIDToString(packet
.object_value
.oid
, dataptr
,
252 sizeof(data
) - (size_t)(dataptr
- data
));
253 datalen
+= (int)strlen(dataptr
);
256 case CUPS_ASN1_HEX_STRING
:
258 i
< packet
.object_value
.string
.num_bytes
&&
259 dataptr
< (data
+ sizeof(data
) - 3);
261 sprintf(dataptr
, "%02X", packet
.object_value
.string
.bytes
[i
]);
262 datalen
+= (int)strlen(dataptr
);
265 case CUPS_ASN1_COUNTER
:
266 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.counter
);
267 datalen
+= (int)strlen(dataptr
);
270 case CUPS_ASN1_GAUGE
:
271 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.gauge
);
272 datalen
+= (int)strlen(dataptr
);
275 case CUPS_ASN1_TIMETICKS
:
276 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.timeticks
);
277 datalen
+= (int)strlen(dataptr
);
281 fprintf(stderr
, "DEBUG: Unknown OID value type %02X.\n", packet
.object_type
);
283 case CUPS_ASN1_NULL_VALUE
:
288 fprintf(stderr
, "DEBUG: Returning %s %s\n", data
, data
+ datalen
);
290 status
= CUPS_SC_STATUS_OK
;
293 fputs("DEBUG: SNMP read error...\n", stderr
);
296 fputs("DEBUG: SNMP write error...\n", stderr
);
300 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
304 case CUPS_SC_CMD_GET_CONNECTED
:
305 status
= CUPS_SC_STATUS_OK
;
306 data
[0] = device_fd
!= -1;
310 case CUPS_SC_CMD_GET_DEVICE_ID
:
313 cups_snmp_t packet
; /* Packet from printer */
314 static const int ppmPrinterIEEE1284DeviceId
[] =
315 { CUPS_OID_ppmPrinterIEEE1284DeviceId
,1,-1 };
318 status
= CUPS_SC_STATUS_IO_ERROR
;
321 if (_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
322 _cupsSNMPDefaultCommunity(),
323 CUPS_ASN1_GET_REQUEST
, 1,
324 ppmPrinterIEEE1284DeviceId
))
326 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0) &&
327 packet
.object_type
== CUPS_ASN1_OCTET_STRING
)
329 strlcpy(data
, (char *)packet
.object_value
.string
.bytes
,
331 datalen
= (int)strlen(data
);
332 status
= CUPS_SC_STATUS_OK
;
339 if ((device_id
= getenv("1284DEVICEID")) != NULL
)
341 strlcpy(data
, device_id
, sizeof(data
));
342 datalen
= (int)strlen(data
);
343 status
= CUPS_SC_STATUS_OK
;
348 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
353 return (cupsSideChannelWrite(command
, status
, data
, datalen
, 1.0));