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 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * "LICENSE" which should have been included with this file. If this
11 * file is missing or damaged, see the license at "http://www.cups.org/".
13 * This file is subject to the Apple OS-Developed Software exception.
17 * Include necessary headers.
20 #include "backend-private.h"
22 #include <sys/select.h>
26 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
30 backendCheckSideChannel(
31 int snmp_fd
, /* I - SNMP socket */
32 http_addr_t
*addr
) /* I - Address of device */
34 fd_set input
; /* Select input set */
35 struct timeval timeout
; /* Select timeout */
39 FD_SET(CUPS_SC_FD
, &input
);
41 timeout
.tv_sec
= timeout
.tv_usec
= 0;
43 if (select(CUPS_SC_FD
+ 1, &input
, NULL
, NULL
, &timeout
) > 0)
44 backendNetworkSideCB(-1, -1, snmp_fd
, addr
, 0);
49 * 'backendLookup()' - Lookup the given host and log addresses.
52 http_addrlist_t
* /* O - List of addresses or NULL */
53 backendLookup(const char *hostname
, /* I - Hostname */
54 int port
, /* I - Port number */
55 int *cancel
) /* I - Variable to watch for job cancel */
57 char portname
[32], /* Port number as string */
58 addrname
[256]; /* Address as string */
59 http_addrlist_t
*addrlist
, /* List of addresses */
60 *current
; /* Current address */
64 * Lookup the address for the named host...
67 snprintf(portname
, sizeof(portname
), "%d", port
);
69 fputs("STATE: +connecting-to-device\n", stderr
);
70 fprintf(stderr
, "DEBUG: Looking up \"%s\"...\n", hostname
);
72 while ((addrlist
= httpAddrGetList(hostname
, AF_UNSPEC
, portname
)) == NULL
)
74 _cupsLangPrintFilter(stderr
, "INFO", _("Unable to locate printer \"%s\"."), hostname
);
77 if (getenv("CLASS") != NULL
)
79 fputs("STATE: -connecting-to-device\n", stderr
);
80 exit(CUPS_BACKEND_STOP
);
83 if (cancel
&& *cancel
)
85 fputs("STATE: -connecting-to-device\n", stderr
);
86 exit(CUPS_BACKEND_OK
);
90 fputs("STATE: -connecting-to-device\n", stderr
);
93 * Log the addresses we got...
96 for (current
= addrlist
; current
; current
= current
->next
)
97 fprintf(stderr
, "DEBUG: %s=%s\n", hostname
, httpAddrString(¤t
->addr
, addrname
, sizeof(addrname
)));
108 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
111 int /* O - -1 on error, 0 on success */
112 backendNetworkSideCB(
113 int print_fd
, /* I - Print file or -1 */
114 int device_fd
, /* I - Device file or -1 */
115 int snmp_fd
, /* I - SNMP socket */
116 http_addr_t
*addr
, /* I - Address of device */
117 int use_bc
) /* I - Use back-channel data? */
119 cups_sc_command_t command
; /* Request command */
120 cups_sc_status_t status
; /* Request/response status */
121 char data
[65536]; /* Request/response data */
122 int datalen
; /* Request/response data size */
123 const char *device_id
; /* 1284DEVICEID env var */
126 datalen
= sizeof(data
);
128 if (cupsSideChannelRead(&command
, &status
, data
, &datalen
, 1.0))
133 case CUPS_SC_CMD_DRAIN_OUTPUT
:
135 * Our sockets disable the Nagle algorithm and data is sent immediately.
139 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
140 else if (backendDrainOutput(print_fd
, device_fd
))
141 status
= CUPS_SC_STATUS_IO_ERROR
;
143 status
= CUPS_SC_STATUS_OK
;
148 case CUPS_SC_CMD_GET_BIDI
:
149 status
= CUPS_SC_STATUS_OK
;
150 data
[0] = (char)use_bc
;
154 case CUPS_SC_CMD_SNMP_GET
:
155 case CUPS_SC_CMD_SNMP_GET_NEXT
:
156 fprintf(stderr
, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n",
157 command
== CUPS_SC_CMD_SNMP_GET
? "GET" : "GET_NEXT", datalen
,
162 status
= CUPS_SC_STATUS_BAD_MESSAGE
;
169 char *dataptr
; /* Pointer into data */
170 cups_snmp_t packet
; /* Packet from printer */
171 const char *snmp_value
; /* CUPS_SNMP_VALUE env var */
173 if ((snmp_value
= getenv("CUPS_SNMP_VALUE")) != NULL
)
175 const char *snmp_count
; /* CUPS_SNMP_COUNT env var */
176 int count
; /* Repetition count */
178 if ((snmp_count
= getenv("CUPS_SNMP_COUNT")) != NULL
)
180 if ((count
= atoi(snmp_count
)) <= 0)
186 for (dataptr
= data
+ strlen(data
) + 1;
187 count
> 0 && dataptr
< (data
+ sizeof(data
) - 1);
188 count
--, dataptr
+= strlen(dataptr
))
189 strlcpy(dataptr
, snmp_value
, sizeof(data
) - (size_t)(dataptr
- data
));
191 fprintf(stderr
, "DEBUG: Returning %s %s\n", data
,
192 data
+ strlen(data
) + 1);
194 status
= CUPS_SC_STATUS_OK
;
195 datalen
= (int)(dataptr
- data
);
199 if (!_cupsSNMPStringToOID(data
, packet
.object_name
, CUPS_SNMP_MAX_OID
))
201 status
= CUPS_SC_STATUS_BAD_MESSAGE
;
206 status
= CUPS_SC_STATUS_IO_ERROR
;
209 if (_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
210 _cupsSNMPDefaultCommunity(),
211 command
== CUPS_SC_CMD_SNMP_GET
?
212 CUPS_ASN1_GET_REQUEST
:
213 CUPS_ASN1_GET_NEXT_REQUEST
, 1,
216 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0))
218 size_t i
; /* Looping var */
221 if (!_cupsSNMPOIDToString(packet
.object_name
, data
, sizeof(data
)))
223 fputs("DEBUG: Bad OID returned!\n", stderr
);
227 datalen
= (int)strlen(data
) + 1;
228 dataptr
= data
+ datalen
;
230 switch (packet
.object_type
)
232 case CUPS_ASN1_BOOLEAN
:
233 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%d", packet
.object_value
.boolean
);
234 datalen
+= (int)strlen(dataptr
);
237 case CUPS_ASN1_INTEGER
:
238 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%d",
239 packet
.object_value
.integer
);
240 datalen
+= (int)strlen(dataptr
);
243 case CUPS_ASN1_BIT_STRING
:
244 case CUPS_ASN1_OCTET_STRING
:
245 if (packet
.object_value
.string
.num_bytes
< (sizeof(data
) - (size_t)(dataptr
- data
)))
246 i
= packet
.object_value
.string
.num_bytes
;
248 i
= sizeof(data
) - (size_t)(dataptr
- data
);
250 memcpy(dataptr
, packet
.object_value
.string
.bytes
, i
);
256 _cupsSNMPOIDToString(packet
.object_value
.oid
, dataptr
,
257 sizeof(data
) - (size_t)(dataptr
- data
));
258 datalen
+= (int)strlen(dataptr
);
261 case CUPS_ASN1_HEX_STRING
:
263 i
< packet
.object_value
.string
.num_bytes
&&
264 dataptr
< (data
+ sizeof(data
) - 3);
266 sprintf(dataptr
, "%02X", packet
.object_value
.string
.bytes
[i
]);
267 datalen
+= (int)strlen(dataptr
);
270 case CUPS_ASN1_COUNTER
:
271 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.counter
);
272 datalen
+= (int)strlen(dataptr
);
275 case CUPS_ASN1_GAUGE
:
276 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.gauge
);
277 datalen
+= (int)strlen(dataptr
);
280 case CUPS_ASN1_TIMETICKS
:
281 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.timeticks
);
282 datalen
+= (int)strlen(dataptr
);
286 fprintf(stderr
, "DEBUG: Unknown OID value type %02X.\n", packet
.object_type
);
288 case CUPS_ASN1_NULL_VALUE
:
293 fprintf(stderr
, "DEBUG: Returning %s %s\n", data
, data
+ datalen
);
295 status
= CUPS_SC_STATUS_OK
;
298 fputs("DEBUG: SNMP read error...\n", stderr
);
301 fputs("DEBUG: SNMP write error...\n", stderr
);
305 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
309 case CUPS_SC_CMD_GET_CONNECTED
:
310 status
= CUPS_SC_STATUS_OK
;
311 data
[0] = device_fd
!= -1;
315 case CUPS_SC_CMD_GET_DEVICE_ID
:
318 cups_snmp_t packet
; /* Packet from printer */
319 static const int ppmPrinterIEEE1284DeviceId
[] =
320 { CUPS_OID_ppmPrinterIEEE1284DeviceId
,1,-1 };
323 status
= CUPS_SC_STATUS_IO_ERROR
;
326 if (_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
327 _cupsSNMPDefaultCommunity(),
328 CUPS_ASN1_GET_REQUEST
, 1,
329 ppmPrinterIEEE1284DeviceId
))
331 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0) &&
332 packet
.object_type
== CUPS_ASN1_OCTET_STRING
)
334 strlcpy(data
, (char *)packet
.object_value
.string
.bytes
,
336 datalen
= (int)strlen(data
);
337 status
= CUPS_SC_STATUS_OK
;
344 if ((device_id
= getenv("1284DEVICEID")) != NULL
)
346 strlcpy(data
, device_id
, sizeof(data
));
347 datalen
= (int)strlen(data
);
348 status
= CUPS_SC_STATUS_OK
;
353 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
358 return (cupsSideChannelWrite(command
, status
, data
, datalen
, 1.0));