/*
- * "$Id$"
+ * Common backend network APIs for CUPS.
*
- * Common network APIs for the Common UNIX Printing System (CUPS).
+ * Copyright © 2007-2016 by Apple Inc.
+ * Copyright © 2006-2007 by Easy Software Products, all rights reserved.
*
- * Copyright 2007-2008 by Apple Inc.
- * Copyright 2006-2007 by Easy Software Products, all rights reserved.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * "LICENSE" which should have been included with this file. If this
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * backendCheckSideChannel() - Check the side-channel for pending requests.
- * backendNetworkSideCB() - Handle common network side-channel commands.
- * backendResolveURI() - Get the device URI, resolving as needed.
- * resolve_callback() - Build a device URI for the given service name.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
#include "backend-private.h"
#include <limits.h>
-#ifdef __hpux
-# include <sys/time.h>
-#else
-# include <sys/select.h>
-#endif /* __hpux */
-#ifdef HAVE_DNSSD
-# include <dns_sd.h>
-#endif /* HAVE_DNSSD */
-
-
-/*
- * Local functions...
- */
-
-#ifdef HAVE_DNSSD
-static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullName, const char *hostTarget,
- uint16_t port, uint16_t txtLen,
- const unsigned char *txtRecord, void *context);
-#endif /* HAVE_DNSSD */
+#include <sys/select.h>
/*
* 'backendCheckSideChannel()' - Check the side-channel for pending requests.
*/
-
void
backendCheckSideChannel(
int snmp_fd, /* I - SNMP socket */
}
+/*
+ * 'backendLookup()' - Lookup the given host and log addresses.
+ */
+
+http_addrlist_t * /* O - List of addresses or NULL */
+backendLookup(const char *hostname, /* I - Hostname */
+ int port, /* I - Port number */
+ int *cancel) /* I - Variable to watch for job cancel */
+{
+ char portname[32], /* Port number as string */
+ addrname[256]; /* Address as string */
+ http_addrlist_t *addrlist, /* List of addresses */
+ *current; /* Current address */
+
+
+ /*
+ * Lookup the address for the named host...
+ */
+
+ snprintf(portname, sizeof(portname), "%d", port);
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+ fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
+
+ while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer \"%s\"."), hostname);
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ {
+ fputs("STATE: -connecting-to-device\n", stderr);
+ exit(CUPS_BACKEND_STOP);
+ }
+
+ if (cancel && *cancel)
+ {
+ fputs("STATE: -connecting-to-device\n", stderr);
+ exit(CUPS_BACKEND_OK);
+ }
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /*
+ * Log the addresses we got...
+ */
+
+ for (current = addrlist; current; current = current->next)
+ fprintf(stderr, "DEBUG: %s=%s\n", hostname, httpAddrString(¤t->addr, addrname, sizeof(addrname)));
+
+ /*
+ * Return...
+ */
+
+ return (addrlist);
+}
+
+
/*
* 'backendNetworkSideCB()' - Handle common network side-channel commands.
*/
-void
+int /* O - -1 on error, 0 on success */
backendNetworkSideCB(
int print_fd, /* I - Print file or -1 */
int device_fd, /* I - Device file or -1 */
{
cups_sc_command_t command; /* Request command */
cups_sc_status_t status; /* Request/response status */
- char data[2048]; /* Request/response data */
+ char data[65536]; /* Request/response data */
int datalen; /* Request/response data size */
const char *device_id; /* 1284DEVICEID env var */
datalen = sizeof(data);
if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
- {
- _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
- return;
- }
+ return (-1);
switch (command)
{
status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
else if (backendDrainOutput(print_fd, device_fd))
status = CUPS_SC_STATUS_IO_ERROR;
- else
+ else
status = CUPS_SC_STATUS_OK;
datalen = 0;
break;
case CUPS_SC_CMD_GET_BIDI :
- data[0] = use_bc;
+ status = CUPS_SC_STATUS_OK;
+ data[0] = (char)use_bc;
+ datalen = 1;
+ break;
+
+ case CUPS_SC_CMD_SNMP_GET :
+ case CUPS_SC_CMD_SNMP_GET_NEXT :
+ fprintf(stderr, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n",
+ command == CUPS_SC_CMD_SNMP_GET ? "GET" : "GET_NEXT", datalen,
+ data);
+
+ if (datalen < 2)
+ {
+ status = CUPS_SC_STATUS_BAD_MESSAGE;
+ datalen = 0;
+ break;
+ }
+
+ if (snmp_fd >= 0)
+ {
+ char *dataptr; /* Pointer into data */
+ cups_snmp_t packet; /* Packet from printer */
+ const char *snmp_value; /* CUPS_SNMP_VALUE env var */
+
+ if ((snmp_value = getenv("CUPS_SNMP_VALUE")) != NULL)
+ {
+ const char *snmp_count; /* CUPS_SNMP_COUNT env var */
+ int count; /* Repetition count */
+
+ if ((snmp_count = getenv("CUPS_SNMP_COUNT")) != NULL)
+ {
+ if ((count = atoi(snmp_count)) <= 0)
+ count = 1;
+ }
+ else
+ count = 1;
+
+ for (dataptr = data + strlen(data) + 1;
+ count > 0 && dataptr < (data + sizeof(data) - 1);
+ count --, dataptr += strlen(dataptr))
+ strlcpy(dataptr, snmp_value, sizeof(data) - (size_t)(dataptr - data));
+
+ fprintf(stderr, "DEBUG: Returning %s %s\n", data,
+ data + strlen(data) + 1);
+
+ status = CUPS_SC_STATUS_OK;
+ datalen = (int)(dataptr - data);
+ break;
+ }
+
+ if (!_cupsSNMPStringToOID(data, packet.object_name, CUPS_SNMP_MAX_OID))
+ {
+ status = CUPS_SC_STATUS_BAD_MESSAGE;
+ datalen = 0;
+ break;
+ }
+
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
+
+ if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(),
+ command == CUPS_SC_CMD_SNMP_GET ?
+ CUPS_ASN1_GET_REQUEST :
+ CUPS_ASN1_GET_NEXT_REQUEST, 1,
+ packet.object_name))
+ {
+ if (_cupsSNMPRead(snmp_fd, &packet, 1.0))
+ {
+ size_t i; /* Looping var */
+
+
+ if (!_cupsSNMPOIDToString(packet.object_name, data, sizeof(data)))
+ {
+ fputs("DEBUG: Bad OID returned!\n", stderr);
+ break;
+ }
+
+ datalen = (int)strlen(data) + 1;
+ dataptr = data + datalen;
+
+ switch (packet.object_type)
+ {
+ case CUPS_ASN1_BOOLEAN :
+ snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d", packet.object_value.boolean);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d",
+ packet.object_value.integer);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_BIT_STRING :
+ case CUPS_ASN1_OCTET_STRING :
+ if (packet.object_value.string.num_bytes < (sizeof(data) - (size_t)(dataptr - data)))
+ i = packet.object_value.string.num_bytes;
+ else
+ i = sizeof(data) - (size_t)(dataptr - data);
+
+ memcpy(dataptr, packet.object_value.string.bytes, i);
+
+ datalen += (int)i;
+ break;
+
+ case CUPS_ASN1_OID :
+ _cupsSNMPOIDToString(packet.object_value.oid, dataptr,
+ sizeof(data) - (size_t)(dataptr - data));
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_HEX_STRING :
+ for (i = 0;
+ i < packet.object_value.string.num_bytes &&
+ dataptr < (data + sizeof(data) - 3);
+ i ++, dataptr += 2)
+ snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%02X", packet.object_value.string.bytes[i]);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_COUNTER :
+ snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.counter);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_GAUGE :
+ snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.gauge);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_TIMETICKS :
+ snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.timeticks);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ default :
+ fprintf(stderr, "DEBUG: Unknown OID value type %02X.\n", packet.object_type);
+
+ case CUPS_ASN1_NULL_VALUE :
+ dataptr[0] = '\0';
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen);
+
+ status = CUPS_SC_STATUS_OK;
+ }
+ else
+ fputs("DEBUG: SNMP read error...\n", stderr);
+ }
+ else
+ fputs("DEBUG: SNMP write error...\n", stderr);
+ break;
+ }
+
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_CONNECTED :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = device_fd != -1;
datalen = 1;
break;
static const int ppmPrinterIEEE1284DeviceId[] =
{ CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };
- if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(),
+
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
+
+ if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(),
CUPS_ASN1_GET_REQUEST, 1,
ppmPrinterIEEE1284DeviceId))
{
if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
packet.object_type == CUPS_ASN1_OCTET_STRING)
{
- strlcpy(data, packet.object_value.string, sizeof(data));
+ strlcpy(data, (char *)packet.object_value.string.bytes,
+ sizeof(data));
datalen = (int)strlen(data);
- break;
+ status = CUPS_SC_STATUS_OK;
}
}
+
+ break;
}
if ((device_id = getenv("1284DEVICEID")) != NULL)
{
strlcpy(data, device_id, sizeof(data));
datalen = (int)strlen(data);
+ status = CUPS_SC_STATUS_OK;
break;
}
break;
}
- cupsSideChannelWrite(command, status, data, datalen, 1.0);
+ return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
}
-
-
-/*
- * 'backendResolveURI()' - Get the device URI, resolving as needed.
- */
-
-const char * /* O - Device URI */
-backendResolveURI(char **argv) /* I - Command-line arguments */
-{
- const char *uri; /* Device URI */
- char scheme[32], /* URI components... */
- userpass[256],
- hostname[1024],
- resource[1024];
- int port;
- http_uri_status_t status; /* URI decode status */
-
- /*
- * Get the device URI...
- */
-
- uri = cupsBackendDeviceURI(argv);
-
- if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
- sizeof(scheme), userpass, sizeof(userpass),
- hostname, sizeof(hostname), &port,
- resource, sizeof(resource))) < HTTP_URI_OK)
- {
- fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status);
- exit (CUPS_BACKEND_STOP);
- }
-
- /*
- * Resolve it as needed...
- */
-
- if (strstr(resource, "._tcp") || strstr(hostname, "._tcp"))
- {
-#ifdef HAVE_DNSSD
- DNSServiceRef ref; /* DNS-SD service reference */
- char *full_name, /* Full (service) name */
- *regtype, /* Pointer to type in hostname */
- *domain; /* Pointer to domain in hostname */
- static char resolved_uri[HTTP_MAX_URI];
- /* Resolved device URI */
-
- /*
- * Separate the hostname into service name, registration type, and domain...
- */
-
- if (strstr(resource, "._tcp"))
- full_name = resource + 1;
- else
- full_name = hostname;
-
- regtype = strchr(full_name, '.');
- *regtype++ = '\0';
-
- domain = regtype + strlen(regtype) - 1;
- if (domain > regtype && *domain == '.')
- *domain = '\0';
-
- for (domain = strchr(regtype, '.');
- domain;
- domain = strchr(domain + 1, '.'))
- if (domain[1] != '_')
- break;
-
- if (domain)
- *domain++ = '\0';
-
- fprintf(stderr,
- "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
- full_name, regtype, domain ? domain : "(null)");
-
- if (DNSServiceResolve(&ref, 0, 0, full_name, regtype, domain,
- resolve_callback,
- resolved_uri) == kDNSServiceErr_NoError)
- {
- if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError)
- uri = NULL;
- else
- uri = resolved_uri;
-
- DNSServiceRefDeallocate(ref);
- }
- else
-#endif /* HAVE_DNSSD */
-
- uri = NULL;
-
- if (!uri)
- {
- fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri);
- exit(CUPS_BACKEND_STOP);
- }
- }
-
- return (uri);
-}
-
-
-#ifdef HAVE_DNSSD
-/*
- * 'resolve_callback()' - Build a device URI for the given service name.
- */
-
-static void
-resolve_callback(
- DNSServiceRef sdRef, /* I - Service reference */
- DNSServiceFlags flags, /* I - Results flags */
- uint32_t interfaceIndex, /* I - Interface number */
- DNSServiceErrorType errorCode, /* I - Error, if any */
- const char *fullName, /* I - Full service name */
- const char *hostTarget, /* I - Hostname */
- uint16_t port, /* I - Port number */
- uint16_t txtLen, /* I - Length of TXT record */
- const unsigned char *txtRecord, /* I - TXT record data */
- void *context) /* I - Pointer to URI buffer */
-{
- const char *scheme; /* URI scheme */
- char rp[257]; /* Remote printer */
- const void *value; /* Value from TXT record */
- uint8_t valueLen; /* Length of value */
-
-
- fprintf(stderr,
- "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
- "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
- "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
- interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
- txtRecord, context);
-
- /*
- * Figure out the scheme from the full name...
- */
-
- if (strstr(fullName, "._ipp"))
- scheme = "ipp";
- else if (strstr(fullName, "._printer."))
- scheme = "lpd";
- else if (strstr(fullName, "._pdl-datastream."))
- scheme = "socket";
- else
- scheme = "riousbprint";
-
- /*
- * Extract the "remote printer" key from the TXT record...
- */
-
- if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
- &valueLen)) != NULL)
- {
- /*
- * Convert to resource by concatenating with a leading "/"...
- */
-
- rp[0] = '/';
- memcpy(rp + 1, value, valueLen);
- rp[valueLen + 1] = '\0';
- }
- else
- rp[0] = '\0';
-
- /*
- * Assemble the final device URI...
- */
-
- httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme,
- NULL, hostTarget, ntohs(port), rp);
-
- fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context);
-}
-#endif /* HAVE_DNSSD */
-
-
-/*
- * End of "$Id$".
- */