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/".
15 * Include necessary headers.
18 #include "backend-private.h"
20 #include <sys/select.h>
24 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
28 backendCheckSideChannel(
29 int snmp_fd
, /* I - SNMP socket */
30 http_addr_t
*addr
) /* I - Address of device */
32 fd_set input
; /* Select input set */
33 struct timeval timeout
; /* Select timeout */
37 FD_SET(CUPS_SC_FD
, &input
);
39 timeout
.tv_sec
= timeout
.tv_usec
= 0;
41 if (select(CUPS_SC_FD
+ 1, &input
, NULL
, NULL
, &timeout
) > 0)
42 backendNetworkSideCB(-1, -1, snmp_fd
, addr
, 0);
47 * 'backendLookup()' - Lookup the given host and log addresses.
50 http_addrlist_t
* /* O - List of addresses or NULL */
51 backendLookup(const char *hostname
, /* I - Hostname */
52 int port
, /* I - Port number */
53 int *cancel
) /* I - Variable to watch for job cancel */
55 char portname
[32], /* Port number as string */
56 addrname
[256]; /* Address as string */
57 http_addrlist_t
*addrlist
, /* List of addresses */
58 *current
; /* Current address */
62 * Lookup the address for the named host...
65 snprintf(portname
, sizeof(portname
), "%d", port
);
67 fputs("STATE: +connecting-to-device\n", stderr
);
68 fprintf(stderr
, "DEBUG: Looking up \"%s\"...\n", hostname
);
70 while ((addrlist
= httpAddrGetList(hostname
, AF_UNSPEC
, portname
)) == NULL
)
72 _cupsLangPrintFilter(stderr
, "INFO", _("Unable to locate printer \"%s\"."), hostname
);
75 if (getenv("CLASS") != NULL
)
77 fputs("STATE: -connecting-to-device\n", stderr
);
78 exit(CUPS_BACKEND_STOP
);
81 if (cancel
&& *cancel
)
83 fputs("STATE: -connecting-to-device\n", stderr
);
84 exit(CUPS_BACKEND_OK
);
88 fputs("STATE: -connecting-to-device\n", stderr
);
91 * Log the addresses we got...
94 for (current
= addrlist
; current
; current
= current
->next
)
95 fprintf(stderr
, "DEBUG: %s=%s\n", hostname
, httpAddrString(¤t
->addr
, addrname
, sizeof(addrname
)));
106 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
109 int /* O - -1 on error, 0 on success */
110 backendNetworkSideCB(
111 int print_fd
, /* I - Print file or -1 */
112 int device_fd
, /* I - Device file or -1 */
113 int snmp_fd
, /* I - SNMP socket */
114 http_addr_t
*addr
, /* I - Address of device */
115 int use_bc
) /* I - Use back-channel data? */
117 cups_sc_command_t command
; /* Request command */
118 cups_sc_status_t status
; /* Request/response status */
119 char data
[65536]; /* Request/response data */
120 int datalen
; /* Request/response data size */
121 const char *device_id
; /* 1284DEVICEID env var */
124 datalen
= sizeof(data
);
126 if (cupsSideChannelRead(&command
, &status
, data
, &datalen
, 1.0))
131 case CUPS_SC_CMD_DRAIN_OUTPUT
:
133 * Our sockets disable the Nagle algorithm and data is sent immediately.
137 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
138 else if (backendDrainOutput(print_fd
, device_fd
))
139 status
= CUPS_SC_STATUS_IO_ERROR
;
141 status
= CUPS_SC_STATUS_OK
;
146 case CUPS_SC_CMD_GET_BIDI
:
147 status
= CUPS_SC_STATUS_OK
;
148 data
[0] = (char)use_bc
;
152 case CUPS_SC_CMD_SNMP_GET
:
153 case CUPS_SC_CMD_SNMP_GET_NEXT
:
154 fprintf(stderr
, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n",
155 command
== CUPS_SC_CMD_SNMP_GET
? "GET" : "GET_NEXT", datalen
,
160 status
= CUPS_SC_STATUS_BAD_MESSAGE
;
167 char *dataptr
; /* Pointer into data */
168 cups_snmp_t packet
; /* Packet from printer */
169 const char *snmp_value
; /* CUPS_SNMP_VALUE env var */
171 if ((snmp_value
= getenv("CUPS_SNMP_VALUE")) != NULL
)
173 const char *snmp_count
; /* CUPS_SNMP_COUNT env var */
174 int count
; /* Repetition count */
176 if ((snmp_count
= getenv("CUPS_SNMP_COUNT")) != NULL
)
178 if ((count
= atoi(snmp_count
)) <= 0)
184 for (dataptr
= data
+ strlen(data
) + 1;
185 count
> 0 && dataptr
< (data
+ sizeof(data
) - 1);
186 count
--, dataptr
+= strlen(dataptr
))
187 strlcpy(dataptr
, snmp_value
, sizeof(data
) - (size_t)(dataptr
- data
));
189 fprintf(stderr
, "DEBUG: Returning %s %s\n", data
,
190 data
+ strlen(data
) + 1);
192 status
= CUPS_SC_STATUS_OK
;
193 datalen
= (int)(dataptr
- data
);
197 if (!_cupsSNMPStringToOID(data
, packet
.object_name
, CUPS_SNMP_MAX_OID
))
199 status
= CUPS_SC_STATUS_BAD_MESSAGE
;
204 status
= CUPS_SC_STATUS_IO_ERROR
;
207 if (_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
208 _cupsSNMPDefaultCommunity(),
209 command
== CUPS_SC_CMD_SNMP_GET
?
210 CUPS_ASN1_GET_REQUEST
:
211 CUPS_ASN1_GET_NEXT_REQUEST
, 1,
214 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0))
216 size_t i
; /* Looping var */
219 if (!_cupsSNMPOIDToString(packet
.object_name
, data
, sizeof(data
)))
221 fputs("DEBUG: Bad OID returned!\n", stderr
);
225 datalen
= (int)strlen(data
) + 1;
226 dataptr
= data
+ datalen
;
228 switch (packet
.object_type
)
230 case CUPS_ASN1_BOOLEAN
:
231 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%d", packet
.object_value
.boolean
);
232 datalen
+= (int)strlen(dataptr
);
235 case CUPS_ASN1_INTEGER
:
236 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%d",
237 packet
.object_value
.integer
);
238 datalen
+= (int)strlen(dataptr
);
241 case CUPS_ASN1_BIT_STRING
:
242 case CUPS_ASN1_OCTET_STRING
:
243 if (packet
.object_value
.string
.num_bytes
< (sizeof(data
) - (size_t)(dataptr
- data
)))
244 i
= packet
.object_value
.string
.num_bytes
;
246 i
= sizeof(data
) - (size_t)(dataptr
- data
);
248 memcpy(dataptr
, packet
.object_value
.string
.bytes
, i
);
254 _cupsSNMPOIDToString(packet
.object_value
.oid
, dataptr
,
255 sizeof(data
) - (size_t)(dataptr
- data
));
256 datalen
+= (int)strlen(dataptr
);
259 case CUPS_ASN1_HEX_STRING
:
261 i
< packet
.object_value
.string
.num_bytes
&&
262 dataptr
< (data
+ sizeof(data
) - 3);
264 sprintf(dataptr
, "%02X", packet
.object_value
.string
.bytes
[i
]);
265 datalen
+= (int)strlen(dataptr
);
268 case CUPS_ASN1_COUNTER
:
269 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.counter
);
270 datalen
+= (int)strlen(dataptr
);
273 case CUPS_ASN1_GAUGE
:
274 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.gauge
);
275 datalen
+= (int)strlen(dataptr
);
278 case CUPS_ASN1_TIMETICKS
:
279 snprintf(dataptr
, sizeof(data
) - (size_t)(dataptr
- data
), "%u", packet
.object_value
.timeticks
);
280 datalen
+= (int)strlen(dataptr
);
284 fprintf(stderr
, "DEBUG: Unknown OID value type %02X.\n", packet
.object_type
);
286 case CUPS_ASN1_NULL_VALUE
:
291 fprintf(stderr
, "DEBUG: Returning %s %s\n", data
, data
+ datalen
);
293 status
= CUPS_SC_STATUS_OK
;
296 fputs("DEBUG: SNMP read error...\n", stderr
);
299 fputs("DEBUG: SNMP write error...\n", stderr
);
303 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
307 case CUPS_SC_CMD_GET_CONNECTED
:
308 status
= CUPS_SC_STATUS_OK
;
309 data
[0] = device_fd
!= -1;
313 case CUPS_SC_CMD_GET_DEVICE_ID
:
316 cups_snmp_t packet
; /* Packet from printer */
317 static const int ppmPrinterIEEE1284DeviceId
[] =
318 { CUPS_OID_ppmPrinterIEEE1284DeviceId
,1,-1 };
321 status
= CUPS_SC_STATUS_IO_ERROR
;
324 if (_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
325 _cupsSNMPDefaultCommunity(),
326 CUPS_ASN1_GET_REQUEST
, 1,
327 ppmPrinterIEEE1284DeviceId
))
329 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0) &&
330 packet
.object_type
== CUPS_ASN1_OCTET_STRING
)
332 strlcpy(data
, (char *)packet
.object_value
.string
.bytes
,
334 datalen
= (int)strlen(data
);
335 status
= CUPS_SC_STATUS_OK
;
342 if ((device_id
= getenv("1284DEVICEID")) != NULL
)
344 strlcpy(data
, device_id
, sizeof(data
));
345 datalen
= (int)strlen(data
);
346 status
= CUPS_SC_STATUS_OK
;
351 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
356 return (cupsSideChannelWrite(command
, status
, data
, datalen
, 1.0));