/*
- * "$Id: snmp.c 5898 2006-08-28 18:54:10Z mike $"
+ * "$Id$"
*
- * SNMP discovery backend for the Common UNIX Printing System (CUPS).
+ * SNMP discovery backend for CUPS.
*
- * Copyright 2006 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2012 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
+ * 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 please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* This file is subject to the Apple OS-Developed Software exception.
*
* main() - Discover printers via SNMP.
* add_array() - Add a string to an array.
* add_cache() - Add a cached device...
+ * add_device_uri() - Add a device URI to the cache.
* alarm_handler() - Handle alarm signals...
- * asn1_decode_snmp() - Decode a SNMP packet.
- * asn1_debug() - Decode an ASN1-encoded message.
- * asn1_encode_snmp() - Encode a SNMP packet.
- * asn1_get_integer() - Get an integer value.
- * asn1_get_length() - Get a value length.
- * asn1_get_oid() - Get an OID value.
- * asn1_get_packed() - Get a packed integer value.
- * asn1_get_string() - Get a string value.
- * asn1_get_type() - Get a value type.
- * asn1_set_integer() - Set an integer value.
- * asn1_set_length() - Set a value length.
- * asn1_set_oid() - Set an OID value.
- * asn1_set_packed() - Set a packed integer value.
- * asn1_size_integer() - Figure out the number of bytes needed for an
- * integer value.
- * asn1_size_length() - Figure out the number of bytes needed for a
- * length value.
- * asn1_size_oid() - Figure out the numebr of bytes needed for an
- * OID value.
- * asn1_size_packed() - Figure out the number of bytes needed for a
- * packed integer value.
* compare_cache() - Compare two cache entries.
* debug_printf() - Display some debugging information.
- * do_request() - Do a non-blocking IPP request.
* fix_make_model() - Fix common problems in the make-and-model
* string.
* free_array() - Free an array of strings.
* free_cache() - Free the array of cached devices.
- * get_interface_addresses() - Get the broadcast address(es) associated
- * with an interface.
- * hex_debug() - Output hex debugging data...
+ * get_interface_addresses() - Get the broadcast address(es) associated with
+ * an interface.
* list_device() - List a device we found...
- * open_snmp_socket() - Open the SNMP broadcast socket.
* password_cb() - Handle authentication requests.
* probe_device() - Probe a device to discover whether it is a
* printer.
* read_snmp_response() - Read and parse a SNMP response...
* run_time() - Return the total running time...
* scan_devices() - Scan for devices using SNMP.
- * send_snmp_query() - Send an SNMP query packet.
* try_connect() - Try connecting on a port...
* update_cache() - Update a cached device...
*/
* Include necessary headers.
*/
-#include <cups/http-private.h>
#include "backend-private.h"
#include <cups/array.h>
#include <cups/file.h>
+#include <cups/http-private.h>
+#include <regex.h>
/*
* This backend implements SNMP printer discovery. It uses a broadcast-
- * based approach to get SNMP response packets from potential printers
- * and then interrogates each responder by trying to connect on port
- * 631, 9100, and 515.
+ * based approach to get SNMP response packets from potential printers,
+ * requesting OIDs from the Host and Port Monitor MIBs, does a URI
+ * lookup based on the device description string, and finally a probe of
+ * port 9100 (AppSocket) and 515 (LPD).
*
* The current focus is on printers with internal network cards, although
- * the code also works with many external print servers as well. Future
- * versions will support scanning for vendor-specific SNMP OIDs and the
- * new PWG Port Monitor MIB and not just the Host MIB OIDs.
+ * the code also works with many external print servers as well.
*
* The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
* which can contain comments, blank lines, or any number of the following
* Address @IF(name)
* Community name
* DebugLevel N
+ * DeviceURI "regex pattern" uri
* HostNameLookups on
* HostNameLookups off
+ * MaxRunTime N
*
* The default is to use:
*
* Community public
* DebugLevel 0
* HostNameLookups off
+ * MaxRunTime 120
*
* This backend is known to work with the following network printers and
* print servers:
*
* Axis OfficeBasic, 5400, 5600
+ * Brother
* EPSON
* Genicom
* HP JetDirect
* (for all of these, they do not support the Host MIB)
*/
-/*
- * Constants...
- */
-
-#define SNMP_PORT 161 /* SNMP well-known port */
-#define SNMP_MAX_OID 64 /* Maximum number of OID numbers */
-#define SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */
-#define SNMP_MAX_STRING 512 /* Maximum size of string */
-#define SNMP_VERSION_1 0 /* SNMPv1 */
-
-#define ASN1_END_OF_CONTENTS 0x00 /* End-of-contents */
-#define ASN1_BOOLEAN 0x01 /* BOOLEAN */
-#define ASN1_INTEGER 0x02 /* INTEGER or ENUMERATION */
-#define ASN1_BIT_STRING 0x03 /* BIT STRING */
-#define ASN1_OCTET_STRING 0x04 /* OCTET STRING */
-#define ASN1_NULL_VALUE 0x05 /* NULL VALUE */
-#define ASN1_OID 0x06 /* OBJECT IDENTIFIER */
-#define ASN1_SEQUENCE 0x30 /* SEQUENCE */
-#define ASN1_GET_REQUEST 0xa0 /* Get-Request-PDU */
-#define ASN1_GET_RESPONSE 0xa2 /* Get-Response-PDU */
-
-
/*
* Types...
*/
+enum /**** Request IDs for each field ****/
+{
+ DEVICE_TYPE = 1,
+ DEVICE_DESCRIPTION,
+ DEVICE_LOCATION,
+ DEVICE_ID,
+ DEVICE_URI,
+ DEVICE_PRODUCT
+};
+
+typedef struct device_uri_s /**** DeviceURI values ****/
+{
+ regex_t re; /* Regular expression to match */
+ cups_array_t *uris; /* URIs */
+} device_uri_t;
+
typedef struct snmp_cache_s /**** SNMP scan cache ****/
{
http_addr_t address; /* Address of device */
char *addrname, /* Name of device */
*uri, /* device-uri */
*id, /* device-id */
+ *info, /* device-info */
+ *location, /* device-location */
*make_and_model; /* device-make-and-model */
+ int sent; /* Has this device been listed? */
} snmp_cache_t;
-typedef struct snmp_packet_s /**** SNMP packet ****/
-{
- const char *error; /* Encode/decode error */
- int version; /* Version number */
- char community[SNMP_MAX_STRING];
- /* Community name */
- int request_type; /* Request type */
- int request_id; /* request-id value */
- int error_status; /* error-status value */
- int error_index; /* error-index value */
- int object_name[SNMP_MAX_OID];
- /* object-name value */
- int object_type; /* object-value type */
- union
- {
- int boolean; /* Boolean value */
- int integer; /* Integer value */
- int oid[SNMP_MAX_OID]; /* OID value */
- char string[SNMP_MAX_STRING];/* String value */
- } object_value; /* object-value value */
-} snmp_packet_t;
-
-
-/*
- * Private CUPS API to set the last error...
- */
-
-extern void _cupsSetError(ipp_status_t status, const char *message);
-
/*
* Local functions...
static void add_cache(http_addr_t *addr, const char *addrname,
const char *uri, const char *id,
const char *make_and_model);
+static device_uri_t *add_device_uri(char *value);
static void alarm_handler(int sig);
-static int asn1_decode_snmp(unsigned char *buffer, size_t len,
- snmp_packet_t *packet);
-static void asn1_debug(unsigned char *buffer, size_t len,
- int indent);
-static int asn1_encode_snmp(unsigned char *buffer, size_t len,
- snmp_packet_t *packet);
-static int asn1_get_integer(unsigned char **buffer,
- unsigned char *bufend,
- int length);
-static int asn1_get_oid(unsigned char **buffer,
- unsigned char *bufend,
- int length, int *oid, int oidsize);
-static int asn1_get_packed(unsigned char **buffer,
- unsigned char *bufend);
-static char *asn1_get_string(unsigned char **buffer,
- unsigned char *bufend,
- int length, char *string,
- int strsize);
-static int asn1_get_length(unsigned char **buffer,
- unsigned char *bufend);
-static int asn1_get_type(unsigned char **buffer,
- unsigned char *bufend);
-static void asn1_set_integer(unsigned char **buffer,
- int integer);
-static void asn1_set_length(unsigned char **buffer,
- int length);
-static void asn1_set_oid(unsigned char **buffer,
- const int *oid);
-static void asn1_set_packed(unsigned char **buffer,
- int integer);
-static int asn1_size_integer(int integer);
-static int asn1_size_length(int length);
-static int asn1_size_oid(const int *oid);
-static int asn1_size_packed(int integer);
static int compare_cache(snmp_cache_t *a, snmp_cache_t *b);
static void debug_printf(const char *format, ...);
-static ipp_t *do_request(http_t *http, ipp_t *request,
- const char *resource);
static void fix_make_model(char *make_model,
const char *old_make_model,
int make_model_size);
static void free_array(cups_array_t *a);
static void free_cache(void);
static http_addrlist_t *get_interface_addresses(const char *ifname);
-static void hex_debug(unsigned char *buffer, size_t len);
static void list_device(snmp_cache_t *cache);
-static int open_snmp_socket(void);
static const char *password_cb(const char *prompt);
static void probe_device(snmp_cache_t *device);
static void read_snmp_conf(const char *address);
static void read_snmp_response(int fd);
static double run_time(void);
-static void scan_devices(int fd);
-static void send_snmp_query(int fd, http_addr_t *addr, int version,
- const char *community,
- const unsigned request_id,
- const int *oid);
+static void scan_devices(int ipv4, int ipv6);
static int try_connect(http_addr_t *addr, const char *addrname,
int port);
static void update_cache(snmp_cache_t *device, const char *uri,
static cups_array_t *Communities = NULL;
static cups_array_t *Devices = NULL;
static int DebugLevel = 0;
-static int DeviceTypeOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
- 2, 1, 2, 1, 0 };
-static int DeviceDescOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
- 2, 1, 3, 1, 0 };
-static unsigned DeviceTypeRequest;
-static unsigned DeviceDescRequest;
+static const int DescriptionOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
+static const int LocationOID[] = { CUPS_OID_sysLocation, 0, -1 };
+static const int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
+static const int DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 };
+static const int UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
+static const int LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+static const int LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+static const int LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+static const int XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
+static cups_array_t *DeviceURIs = NULL;
static int HostNameLookups = 0;
-static int MaxRunTime = 10;
+static int MaxRunTime = 120;
static struct timeval StartTime;
main(int argc, /* I - Number of command-line arguments (6 or 7) */
char *argv[]) /* I - Command-line arguments */
{
- int fd; /* SNMP socket */
+ int ipv4, /* SNMP IPv4 socket */
+ ipv6; /* SNMP IPv6 socket */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
if (argc > 2)
{
- fputs("Usage: snmp [host-or-ip-address]\n", stderr);
+ _cupsLangPuts(stderr, _("Usage: snmp [host-or-ip-address]"));
return (1);
}
* Open the SNMP socket...
*/
- if ((fd = open_snmp_socket()) < 0)
+ if ((ipv4 = _cupsSNMPOpen(AF_INET)) < 0)
return (1);
+#ifdef AF_INET6
+ if ((ipv6 = _cupsSNMPOpen(AF_INET6)) < 0)
+ perror("DEBUG: Unable to create IPv6 socket");
+#else
+ ipv6 = -1;
+#endif /* AF_INET6 */
+
/*
* Read the configuration file and any cache data...
*/
read_snmp_conf(argv[1]);
+ _cupsSNMPSetDebug(DebugLevel);
+
Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
/*
* Scan for devices...
*/
- scan_devices(fd);
+ scan_devices(ipv4, ipv6);
/*
* Close, free, and return with no errors...
*/
- close(fd);
+ _cupsSNMPClose(ipv4);
+ if (ipv6 >= 0)
+ _cupsSNMPClose(ipv6);
free_array(Addresses);
free_array(Communities);
/*
- * 'alarm_handler()' - Handle alarm signals...
- */
-
-static void
-alarm_handler(int sig) /* I - Signal number */
-{
- /*
- * Do nothing...
- */
-
- (void)sig;
-
-#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
- signal(SIGALRM, alarm_handler);
-#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
-
- if (DebugLevel)
- write(2, "DEBUG: ALARM!\n", 14);
-}
-
-
-/*
- * 'asn1_decode_snmp()' - Decode a SNMP packet.
+ * 'add_device_uri()' - Add a device URI to the cache.
+ *
+ * The value string is modified (chopped up) as needed.
*/
-static int /* O - 0 on success, -1 on error */
-asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */
- size_t len, /* I - Size of buffer */
- snmp_packet_t *packet) /* I - SNMP packet */
+static device_uri_t * /* O - Device URI */
+add_device_uri(char *value) /* I - Value from snmp.conf */
{
- unsigned char *bufptr, /* Pointer into the data */
- *bufend; /* End of data */
- int length; /* Length of value */
+ device_uri_t *device_uri; /* Device URI */
+ char *start; /* Start of value */
/*
- * Initialize the decoding...
+ * Allocate memory as needed...
*/
- memset(packet, 0, sizeof(snmp_packet_t));
-
- bufptr = buffer;
- bufend = buffer + len;
-
- if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
- packet->error = "Packet does not start with SEQUENCE";
- else if (asn1_get_length(&bufptr, bufend) == 0)
- packet->error = "SEQUENCE uses indefinite length";
- else if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
- packet->error = "No version number";
- else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
- packet->error = "Version uses indefinite length";
- else if ((packet->version = asn1_get_integer(&bufptr, bufend, length))
- != SNMP_VERSION_1)
- packet->error = "Bad SNMP version number";
- else if (asn1_get_type(&bufptr, bufend) != ASN1_OCTET_STRING)
- packet->error = "No community name";
- else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
- packet->error = "Community name uses indefinite length";
- else
- {
- asn1_get_string(&bufptr, bufend, length, packet->community,
- sizeof(packet->community));
-
- if ((packet->request_type = asn1_get_type(&bufptr, bufend))
- != ASN1_GET_RESPONSE)
- packet->error = "Packet does not contain a Get-Response-PDU";
- else if (asn1_get_length(&bufptr, bufend) == 0)
- packet->error = "Get-Response-PDU uses indefinite length";
- else if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
- packet->error = "No request-id";
- else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
- packet->error = "request-id uses indefinite length";
- else
- {
- packet->request_id = asn1_get_integer(&bufptr, bufend, length);
-
- if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
- packet->error = "No error-status";
- else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
- packet->error = "error-status uses indefinite length";
- else
- {
- packet->error_status = asn1_get_integer(&bufptr, bufend, length);
-
- if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
- packet->error = "No error-index";
- else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
- packet->error = "error-index uses indefinite length";
- else
- {
- packet->error_index = asn1_get_integer(&bufptr, bufend, length);
-
- if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
- packet->error = "No variable-bindings SEQUENCE";
- else if (asn1_get_length(&bufptr, bufend) == 0)
- packet->error = "variable-bindings uses indefinite length";
- else if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
- packet->error = "No VarBind SEQUENCE";
- else if (asn1_get_length(&bufptr, bufend) == 0)
- packet->error = "VarBind uses indefinite length";
- else if (asn1_get_type(&bufptr, bufend) != ASN1_OID)
- packet->error = "No name OID";
- else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
- packet->error = "Name OID uses indefinite length";
- else
- {
- asn1_get_oid(&bufptr, bufend, length, packet->object_name,
- SNMP_MAX_OID);
-
- packet->object_type = asn1_get_type(&bufptr, bufend);
-
- if ((length = asn1_get_length(&bufptr, bufend)) == 0 &&
- packet->object_type != ASN1_NULL_VALUE &&
- packet->object_type != ASN1_OCTET_STRING)
- packet->error = "Value uses indefinite length";
- else
- {
- switch (packet->object_type)
- {
- case ASN1_BOOLEAN :
- packet->object_value.boolean =
- asn1_get_integer(&bufptr, bufend, length);
- break;
-
- case ASN1_INTEGER :
- packet->object_value.integer =
- asn1_get_integer(&bufptr, bufend, length);
- break;
-
- case ASN1_NULL_VALUE :
- break;
-
- case ASN1_OCTET_STRING :
- asn1_get_string(&bufptr, bufend, length,
- packet->object_value.string,
- SNMP_MAX_STRING);
- break;
-
- case ASN1_OID :
- asn1_get_oid(&bufptr, bufend, length,
- packet->object_value.oid, SNMP_MAX_OID);
- break;
-
- default :
- packet->error = "Unsupported value type";
- break;
- }
- }
- }
- }
- }
- }
- }
+ if (!DeviceURIs)
+ DeviceURIs = cupsArrayNew(NULL, NULL);
- return (packet->error ? -1 : 0);
-}
+ if (!DeviceURIs)
+ return (NULL);
+ if ((device_uri = calloc(1, sizeof(device_uri_t))) == NULL)
+ return (NULL);
-/*
- * 'asn1_debug()' - Decode an ASN1-encoded message.
- */
+ if ((device_uri->uris = cupsArrayNew(NULL, NULL)) == NULL)
+ {
+ free(device_uri);
+ return (NULL);
+ }
-static void
-asn1_debug(unsigned char *buffer, /* I - Buffer */
- size_t len, /* I - Length of buffer */
- int indent) /* I - Indentation */
-{
- int i; /* Looping var */
- unsigned char *bufend; /* End of buffer */
- int integer; /* Number value */
- int oid[SNMP_MAX_OID]; /* OID value */
- char string[SNMP_MAX_STRING];/* String value */
- unsigned char value_type; /* Type of value */
- int value_length; /* Length of value */
+ /*
+ * Scan the value string for the regular expression and URI(s)...
+ */
+ value ++; /* Skip leading " */
- bufend = buffer + len;
+ for (start = value; *value && *value != '\"'; value ++)
+ if (*value == '\\' && value[1])
+ _cups_strcpy(value, value + 1);
- while (buffer < bufend)
+ if (!*value)
{
- /*
- * Get value type...
- */
+ fputs("ERROR: Missing end quote for DeviceURI!\n", stderr);
- value_type = asn1_get_type(&buffer, bufend);
- value_length = asn1_get_length(&buffer, bufend);
+ cupsArrayDelete(device_uri->uris);
+ free(device_uri);
- switch (value_type)
- {
- case ASN1_BOOLEAN :
- integer = asn1_get_integer(&buffer, bufend, value_length);
-
- fprintf(stderr, "DEBUG: %*sBOOLEAN %d bytes %d\n", indent, "",
- value_length, integer);
- break;
-
- case ASN1_INTEGER :
- integer = asn1_get_integer(&buffer, bufend, value_length);
-
- fprintf(stderr, "DEBUG: %*sINTEGER %d bytes %d\n", indent, "",
- value_length, integer);
- break;
-
- case ASN1_OCTET_STRING :
- fprintf(stderr, "DEBUG: %*sOCTET STRING %d bytes \"%s\"\n", indent, "",
- value_length, asn1_get_string(&buffer, bufend,
- value_length, string,
- sizeof(string)));
- break;
-
- case ASN1_NULL_VALUE :
- fprintf(stderr, "DEBUG: %*sNULL VALUE %d bytes\n", indent, "",
- value_length);
-
- buffer += value_length;
- break;
-
- case ASN1_OID :
- asn1_get_oid(&buffer, bufend, value_length, oid, SNMP_MAX_OID);
-
- fprintf(stderr, "DEBUG: %*sOID %d bytes ", indent, "",
- value_length);
- for (i = 0; oid[i]; i ++)
- fprintf(stderr, ".%d", oid[i]);
- putc('\n', stderr);
- break;
-
- case ASN1_SEQUENCE :
- fprintf(stderr, "DEBUG: %*sSEQUENCE %d bytes\n", indent, "",
- value_length);
- asn1_debug(buffer, value_length, indent + 4);
-
- buffer += value_length;
- break;
-
- case ASN1_GET_REQUEST :
- fprintf(stderr, "DEBUG: %*sGet-Request-PDU %d bytes\n", indent, "",
- value_length);
- asn1_debug(buffer, value_length, indent + 4);
-
- buffer += value_length;
- break;
-
- case ASN1_GET_RESPONSE :
- fprintf(stderr, "DEBUG: %*sGet-Response-PDU %d bytes\n", indent, "",
- value_length);
- asn1_debug(buffer, value_length, indent + 4);
-
- buffer += value_length;
- break;
-
- default :
- fprintf(stderr, "DEBUG: %*sUNKNOWN(%x) %d bytes\n", indent, "",
- value_type, value_length);
-
- buffer += value_length;
- break;
- }
+ return (NULL);
}
-}
-
-
-/*
- * 'asn1_encode_snmp()' - Encode a SNMP packet.
- */
-static int /* O - Length on success, -1 on error */
-asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */
- size_t bufsize, /* I - Size of buffer */
- snmp_packet_t *packet) /* I - SNMP packet */
-{
- unsigned char *bufptr; /* Pointer into buffer */
- int total, /* Total length */
- msglen, /* Length of entire message */
- commlen, /* Length of community string */
- reqlen, /* Length of request */
- listlen, /* Length of variable list */
- varlen, /* Length of variable */
- namelen, /* Length of object name OID */
- valuelen; /* Length of object value */
+ *value++ = '\0';
+ if (regcomp(&(device_uri->re), start, REG_EXTENDED | REG_ICASE))
+ {
+ fputs("ERROR: Bad regular expression for DeviceURI!\n", stderr);
- /*
- * Get the lengths of the community string, OID, and message...
- */
+ cupsArrayDelete(device_uri->uris);
+ free(device_uri);
- namelen = asn1_size_oid(packet->object_name);
+ return (NULL);
+ }
- switch (packet->object_type)
+ while (*value)
{
- case ASN1_NULL_VALUE :
- valuelen = 0;
- break;
-
- case ASN1_BOOLEAN :
- valuelen = asn1_size_integer(packet->object_value.boolean);
- break;
-
- case ASN1_INTEGER :
- valuelen = asn1_size_integer(packet->object_value.integer);
- break;
+ while (isspace(*value & 255))
+ value ++;
- case ASN1_OCTET_STRING :
- valuelen = strlen(packet->object_value.string);
- break;
+ if (!*value)
+ break;
- case ASN1_OID :
- valuelen = asn1_size_oid(packet->object_value.oid);
- break;
+ for (start = value; *value && !isspace(*value & 255); value ++);
- default :
- packet->error = "Unknown object type";
- return (-1);
- }
+ if (*value)
+ *value++ = '\0';
- varlen = 1 + asn1_size_length(namelen) + namelen +
- 1 + asn1_size_length(valuelen) + valuelen;
- listlen = 1 + asn1_size_length(varlen) + varlen;
- reqlen = 2 + asn1_size_integer(packet->request_id) +
- 2 + asn1_size_integer(packet->error_status) +
- 2 + asn1_size_integer(packet->error_index) +
- 1 + asn1_size_length(listlen) + listlen;
- commlen = strlen(packet->community);
- msglen = 2 + asn1_size_integer(packet->version) +
- 1 + asn1_size_length(commlen) + commlen +
- 1 + asn1_size_length(reqlen) + reqlen;
- total = 1 + asn1_size_length(msglen) + msglen;
-
- if (total > bufsize)
- {
- packet->error = "Message too large for buffer";
- return (-1);
+ cupsArrayAdd(device_uri->uris, strdup(start));
}
/*
- * Then format the message...
+ * Add the device URI to the list and return it...
*/
- bufptr = buffer;
-
- *bufptr++ = ASN1_SEQUENCE; /* SNMPv1 message header */
- asn1_set_length(&bufptr, msglen);
-
- asn1_set_integer(&bufptr, packet->version);
- /* version */
+ cupsArrayAdd(DeviceURIs, device_uri);
- *bufptr++ = ASN1_OCTET_STRING; /* community */
- asn1_set_length(&bufptr, commlen);
- memcpy(bufptr, packet->community, commlen);
- bufptr += commlen;
-
- *bufptr++ = packet->request_type; /* Get-Request-PDU */
- asn1_set_length(&bufptr, reqlen);
-
- asn1_set_integer(&bufptr, packet->request_id);
-
- asn1_set_integer(&bufptr, packet->error_status);
-
- asn1_set_integer(&bufptr, packet->error_index);
-
- *bufptr++ = ASN1_SEQUENCE; /* variable-bindings */
- asn1_set_length(&bufptr, listlen);
-
- *bufptr++ = ASN1_SEQUENCE; /* variable */
- asn1_set_length(&bufptr, varlen);
-
- asn1_set_oid(&bufptr, packet->object_name);
- /* ObjectName */
+ return (device_uri);
+}
- switch (packet->object_type)
- {
- case ASN1_NULL_VALUE :
- *bufptr++ = ASN1_NULL_VALUE; /* ObjectValue */
- *bufptr++ = 0; /* Length */
- break;
- case ASN1_BOOLEAN :
- asn1_set_integer(&bufptr, packet->object_value.boolean);
- break;
+/*
+ * 'alarm_handler()' - Handle alarm signals...
+ */
- case ASN1_INTEGER :
- asn1_set_integer(&bufptr, packet->object_value.integer);
- break;
+static void
+alarm_handler(int sig) /* I - Signal number */
+{
+ /*
+ * Do nothing...
+ */
- case ASN1_OCTET_STRING :
- *bufptr++ = ASN1_OCTET_STRING;
- asn1_set_length(&bufptr, valuelen);
- memcpy(bufptr, packet->object_value.string, valuelen);
- bufptr += valuelen;
- break;
+ (void)sig;
- case ASN1_OID :
- asn1_set_oid(&bufptr, packet->object_value.oid);
- break;
- }
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGALRM, alarm_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
- return (bufptr - buffer);
+ if (DebugLevel)
+ write(2, "DEBUG: ALARM!\n", 14);
}
/*
- * 'asn1_get_integer()' - Get an integer value.
+ * 'compare_cache()' - Compare two cache entries.
*/
-static int /* O - Integer value */
-asn1_get_integer(
- unsigned char **buffer, /* IO - Pointer in buffer */
- unsigned char *bufend, /* I - End of buffer */
- int length) /* I - Length of value */
+static int /* O - Result of comparison */
+compare_cache(snmp_cache_t *a, /* I - First cache entry */
+ snmp_cache_t *b) /* I - Second cache entry */
{
- int value; /* Integer value */
-
-
- for (value = 0;
- length > 0 && *buffer < bufend;
- length --, (*buffer) ++)
- value = (value << 8) | **buffer;
-
- return (value);
+ return (_cups_strcasecmp(a->addrname, b->addrname));
}
/*
- * 'asn1_get_length()' - Get a value length.
+ * 'debug_printf()' - Display some debugging information.
*/
-static int /* O - Length */
-asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */
- unsigned char *bufend) /* I - End of buffer */
+static void
+debug_printf(const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
{
- int length; /* Length */
-
+ va_list ap; /* Pointer to arguments */
- length = **buffer;
- (*buffer) ++;
- if (length & 128)
- length = asn1_get_integer(buffer, bufend, length & 127);
+ if (!DebugLevel)
+ return;
- return (length);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
}
/*
- * 'asn1_get_oid()' - Get an OID value.
+ * 'fix_make_model()' - Fix common problems in the make-and-model string.
*/
-static int /* O - Last OID number */
-asn1_get_oid(
- unsigned char **buffer, /* IO - Pointer in buffer */
- unsigned char *bufend, /* I - End of buffer */
- int length, /* I - Length of value */
- int *oid, /* I - OID buffer */
- int oidsize) /* I - Size of OID buffer */
+static void
+fix_make_model(
+ char *make_model, /* I - New make-and-model string */
+ const char *old_make_model, /* I - Old make-and-model string */
+ int make_model_size) /* I - Size of new string buffer */
{
- unsigned char *valend; /* End of value */
- int *oidend; /* End of OID buffer */
- int number; /* OID number */
+ char *mmptr; /* Pointer into make-and-model string */
+
+ /*
+ * Fix some common problems with the make-and-model string so
+ * that printer driver detection works better...
+ */
+
+ if (!_cups_strncasecmp(old_make_model, "Hewlett-Packard", 15))
+ {
+ /*
+ * Strip leading Hewlett-Packard and hp prefixes and replace
+ * with a single HP manufacturer prefix...
+ */
- valend = *buffer + length;
- oidend = oid + oidsize - 1;
+ mmptr = (char *)old_make_model + 15;
- if (valend > bufend)
- valend = bufend;
+ while (isspace(*mmptr & 255))
+ mmptr ++;
- number = asn1_get_packed(buffer, bufend);
+ if (!_cups_strncasecmp(mmptr, "hp", 2))
+ {
+ mmptr += 2;
- if (number < 80)
- {
- *oid++ = number / 40;
- number = number % 40;
- *oid++ = number;
+ while (isspace(*mmptr & 255))
+ mmptr ++;
+ }
+
+ make_model[0] = 'H';
+ make_model[1] = 'P';
+ make_model[2] = ' ';
+ strlcpy(make_model + 3, mmptr, make_model_size - 3);
}
+ else if (!_cups_strncasecmp(old_make_model, "deskjet", 7))
+ snprintf(make_model, make_model_size, "HP DeskJet%s", old_make_model + 7);
+ else if (!_cups_strncasecmp(old_make_model, "officejet", 9))
+ snprintf(make_model, make_model_size, "HP OfficeJet%s", old_make_model + 9);
+ else if (!_cups_strncasecmp(old_make_model, "stylus_pro_", 11))
+ snprintf(make_model, make_model_size, "EPSON Stylus Pro %s",
+ old_make_model + 11);
else
+ strlcpy(make_model, old_make_model, make_model_size);
+
+ if ((mmptr = strstr(make_model, ", Inc.,")) != NULL)
{
- *oid++ = 2;
- number -= 80;
- *oid++ = number;
+ /*
+ * Strip inc. from name, e.g. "Tektronix, Inc., Phaser 560"
+ * becomes "Tektronix Phaser 560"...
+ */
+
+ _cups_strcpy(mmptr, mmptr + 7);
}
- while (*buffer < valend)
+ if ((mmptr = strstr(make_model, " Network")) != NULL)
{
- number = asn1_get_packed(buffer, bufend);
+ /*
+ * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
+ * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
+ */
- if (oid < oidend)
- *oid++ = number;
+ *mmptr = '\0';
}
- *oid = 0;
+ if ((mmptr = strchr(make_model, ',')) != NULL)
+ {
+ /*
+ * Drop anything after a trailing comma...
+ */
- return (number);
+ *mmptr = '\0';
+ }
}
/*
- * 'asn1_get_packed()' - Get a packed integer value.
+ * 'free_array()' - Free an array of strings.
*/
-static int /* O - Value */
-asn1_get_packed(
- unsigned char **buffer, /* IO - Pointer in buffer */
- unsigned char *bufend) /* I - End of buffer */
+static void
+free_array(cups_array_t *a) /* I - Array */
{
- int value; /* Value */
-
-
- value = 0;
+ char *s; /* Current string */
- while ((**buffer & 128) && *buffer < bufend)
- {
- value = (value << 7) | (**buffer & 127);
- (*buffer) ++;
- }
- if (*buffer < bufend)
- {
- value = (value << 7) | **buffer;
- (*buffer) ++;
- }
+ for (s = (char *)cupsArrayFirst(a); s; s = (char *)cupsArrayNext(a))
+ free(s);
- return (value);
+ cupsArrayDelete(a);
}
/*
- * 'asn1_get_string()' - Get a string value.
+ * 'free_cache()' - Free the array of cached devices.
*/
-static char * /* O - String */
-asn1_get_string(
- unsigned char **buffer, /* IO - Pointer in buffer */
- unsigned char *bufend, /* I - End of buffer */
- int length, /* I - Value length */
- char *string, /* I - String buffer */
- int strsize) /* I - String buffer size */
+static void
+free_cache(void)
{
- if (length < strsize)
- {
- memcpy(string, *buffer, length);
- string[length] = '\0';
- }
- else
- {
- memcpy(string, buffer, strsize - 1);
- string[strsize - 1] = '\0';
- }
-
- (*buffer) += length;
-
- return (string);
-}
+ snmp_cache_t *cache; /* Cached device */
-/*
- * 'asn1_get_type()' - Get a value type.
- */
+ for (cache = (snmp_cache_t *)cupsArrayFirst(Devices);
+ cache;
+ cache = (snmp_cache_t *)cupsArrayNext(Devices))
+ {
+ free(cache->addrname);
-static int /* O - Type */
-asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */
- unsigned char *bufend) /* I - End of buffer */
-{
- int type; /* Type */
+ if (cache->uri)
+ free(cache->uri);
+ if (cache->id)
+ free(cache->id);
- type = **buffer;
- (*buffer) ++;
+ if (cache->make_and_model)
+ free(cache->make_and_model);
- if ((type & 31) == 31)
- type = asn1_get_packed(buffer, bufend);
+ free(cache);
+ }
- return (type);
+ cupsArrayDelete(Devices);
+ Devices = NULL;
}
/*
- * 'asn1_set_integer()' - Set an integer value.
- */
-
-static void
-asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */
- int integer) /* I - Integer value */
-{
- **buffer = ASN1_INTEGER;
- (*buffer) ++;
-
- if (integer > 0x7fffff || integer < -0x800000)
- {
- **buffer = 4;
- (*buffer) ++;
- **buffer = integer >> 24;
- (*buffer) ++;
- **buffer = integer >> 16;
- (*buffer) ++;
- **buffer = integer >> 8;
- (*buffer) ++;
- **buffer = integer;
- (*buffer) ++;
- }
- else if (integer > 0x7fff || integer < -0x8000)
- {
- **buffer = 3;
- (*buffer) ++;
- **buffer = integer >> 16;
- (*buffer) ++;
- **buffer = integer >> 8;
- (*buffer) ++;
- **buffer = integer;
- (*buffer) ++;
- }
- else if (integer > 0x7f || integer < -0x80)
- {
- **buffer = 2;
- (*buffer) ++;
- **buffer = integer >> 8;
- (*buffer) ++;
- **buffer = integer;
- (*buffer) ++;
- }
- else
- {
- **buffer = 1;
- (*buffer) ++;
- **buffer = integer;
- (*buffer) ++;
- }
-}
-
-
-/*
- * 'asn1_set_length()' - Set a value length.
- */
-
-static void
-asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */
- int length) /* I - Length value */
-{
- if (length > 255)
- {
- **buffer = 0x82; /* 2-byte length */
- (*buffer) ++;
- **buffer = length >> 8;
- (*buffer) ++;
- **buffer = length;
- (*buffer) ++;
- }
- else if (length > 127)
- {
- **buffer = 0x81; /* 1-byte length */
- (*buffer) ++;
- **buffer = length;
- (*buffer) ++;
- }
- else
- {
- **buffer = length; /* Length */
- (*buffer) ++;
- }
-}
-
-
-/*
- * 'asn1_set_oid()' - Set an OID value.
- */
-
-static void
-asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */
- const int *oid) /* I - OID value */
-{
- **buffer = ASN1_OID;
- (*buffer) ++;
-
- asn1_set_length(buffer, asn1_size_oid(oid));
-
- asn1_set_packed(buffer, oid[0] * 40 + oid[1]);
-
- for (oid += 2; *oid; oid ++)
- asn1_set_packed(buffer, *oid);
-}
-
-
-/*
- * 'asn1_set_packed()' - Set a packed integer value.
- */
-
-static void
-asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */
- int integer) /* I - Integer value */
-{
- if (integer > 0xfffffff)
- {
- **buffer = (integer >> 14) & 0x7f;
- (*buffer) ++;
- }
-
- if (integer > 0x1fffff)
- {
- **buffer = (integer >> 21) & 0x7f;
- (*buffer) ++;
- }
-
- if (integer > 0x3fff)
- {
- **buffer = (integer >> 14) & 0x7f;
- (*buffer) ++;
- }
-
- if (integer > 0x7f)
- {
- **buffer = (integer >> 7) & 0x7f;
- (*buffer) ++;
- }
-
- **buffer = integer & 0x7f;
- (*buffer) ++;
-}
-
-/*
- * 'asn1_size_integer()' - Figure out the number of bytes needed for an
- * integer value.
- */
-
-static int /* O - Size in bytes */
-asn1_size_integer(int integer) /* I - Integer value */
-{
- if (integer > 0x7fffff || integer < -0x800000)
- return (4);
- else if (integer > 0x7fff || integer < -0x8000)
- return (3);
- else if (integer > 0x7f || integer < -0x80)
- return (2);
- else
- return (1);
-}
-
-
-/*
- * 'asn1_size_length()' - Figure out the number of bytes needed for a
- * length value.
- */
-
-static int /* O - Size in bytes */
-asn1_size_length(int length) /* I - Length value */
-{
- if (length > 0xff)
- return (3);
- else if (length > 0x7f)
- return (2);
- else
- return (1);
-}
-
-
-/*
- * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an
- * OID value.
- */
-
-static int /* O - Size in bytes */
-asn1_size_oid(const int *oid) /* I - OID value */
-{
- int length; /* Length of value */
-
-
- for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2; *oid; oid ++)
- length += asn1_size_packed(*oid);
-
- return (length);
-}
-
-
-/*
- * 'asn1_size_packed()' - Figure out the number of bytes needed for a
- * packed integer value.
- */
-
-static int /* O - Size in bytes */
-asn1_size_packed(int integer) /* I - Integer value */
-{
- if (integer > 0xfffffff)
- return (5);
- else if (integer > 0x1fffff)
- return (4);
- else if (integer > 0x3fff)
- return (3);
- else if (integer > 0x7f)
- return (2);
- else
- return (1);
-}
-
-
-/*
- * 'compare_cache()' - Compare two cache entries.
- */
-
-static int /* O - Result of comparison */
-compare_cache(snmp_cache_t *a, /* I - First cache entry */
- snmp_cache_t *b) /* I - Second cache entry */
-{
- return (strcasecmp(a->addrname, b->addrname));
-}
-
-
-/*
- * 'debug_printf()' - Display some debugging information.
- */
-
-static void
-debug_printf(const char *format, /* I - Printf-style format string */
- ...) /* I - Additional arguments as needed */
-{
- va_list ap; /* Pointer to arguments */
-
-
- if (!DebugLevel)
- return;
-
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- va_end(ap);
-}
-
-
-/*
- * 'do_request()' - Do a non-blocking IPP request.
- */
-
-static ipp_t * /* O - Response data or NULL */
-do_request(http_t *http, /* I - HTTP connection to server */
- ipp_t *request, /* I - IPP request */
- const char *resource) /* I - HTTP resource for POST */
-{
- ipp_t *response; /* IPP response data */
- http_status_t status; /* Status of HTTP request */
- ipp_state_t state; /* State of IPP processing */
-
-
- /*
- * Setup the HTTP variables needed...
- */
-
- httpClearFields(http);
- httpSetLength(http, ippLength(request));
- httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
-
- /*
- * Do the POST request...
- */
-
- debug_printf("DEBUG: %.3f POST %s...\n", run_time(), resource);
-
- if (httpPost(http, resource))
- {
- if (httpReconnect(http))
- {
- _cupsSetError(IPP_DEVICE_ERROR, "Unable to reconnect");
- return (NULL);
- }
- else if (httpPost(http, resource))
- {
- _cupsSetError(IPP_GONE, "Unable to POST");
- return (NULL);
- }
- }
-
- /*
- * Send the IPP data...
- */
-
- request->state = IPP_IDLE;
- status = HTTP_CONTINUE;
-
- while ((state = ippWrite(http, request)) != IPP_DATA)
- if (state == IPP_ERROR)
- {
- status = HTTP_ERROR;
- break;
- }
- else if (httpCheck(http))
- {
- if ((status = httpUpdate(http)) != HTTP_CONTINUE)
- break;
- }
-
- /*
- * Get the server's return status...
- */
-
- debug_printf("DEBUG: %.3f Getting response...\n", run_time());
-
- while (status == HTTP_CONTINUE)
- if (httpWait(http, 1000))
- status = httpUpdate(http);
- else
- {
- status = HTTP_ERROR;
- http->error = ETIMEDOUT;
- }
-
- if (status != HTTP_OK)
- {
- /*
- * Flush any error message...
- */
-
- httpFlush(http);
- response = NULL;
- }
- else
- {
- /*
- * Read the response...
- */
-
- response = ippNew();
-
- while ((state = ippRead(http, response)) != IPP_DATA)
- if (state == IPP_ERROR)
- {
- /*
- * Delete the response...
- */
-
- ippDelete(response);
- response = NULL;
-
- _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
- break;
- }
- }
-
- /*
- * Delete the original request and return the response...
- */
-
- ippDelete(request);
-
- if (response)
- {
- ipp_attribute_t *attr; /* status-message attribute */
-
-
- attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
-
- _cupsSetError(response->request.status.status_code,
- attr ? attr->values[0].string.text :
- ippErrorString(response->request.status.status_code));
- }
- else if (status != HTTP_OK)
- {
- switch (status)
- {
- case HTTP_NOT_FOUND :
- _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
- break;
-
- case HTTP_UNAUTHORIZED :
- _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
- break;
-
- case HTTP_FORBIDDEN :
- _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
- break;
-
- case HTTP_BAD_REQUEST :
- _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
- break;
-
- case HTTP_REQUEST_TOO_LARGE :
- _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
- break;
-
- case HTTP_NOT_IMPLEMENTED :
- _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
- break;
-
- case HTTP_NOT_SUPPORTED :
- _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
- break;
-
- default :
- _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
- break;
- }
- }
-
- return (response);
-}
-
-
-/*
- * 'fix_make_model()' - Fix common problems in the make-and-model string.
- */
-
-static void
-fix_make_model(
- char *make_model, /* I - New make-and-model string */
- const char *old_make_model, /* I - Old make-and-model string */
- int make_model_size) /* I - Size of new string buffer */
-{
- char *mmptr; /* Pointer into make-and-model string */
-
-
- /*
- * Fix some common problems with the make-and-model string so
- * that printer driver detection works better...
- */
-
- if (!strncasecmp(old_make_model, "Hewlett-Packard", 15))
- {
- /*
- * Strip leading Hewlett-Packard and hp prefixes and replace
- * with a single HP manufacturer prefix...
- */
-
- mmptr = (char *)old_make_model + 15;
-
- while (isspace(*mmptr & 255))
- mmptr ++;
-
- if (!strncasecmp(mmptr, "hp", 2))
- {
- mmptr += 2;
-
- while (isspace(*mmptr & 255))
- mmptr ++;
- }
-
- make_model[0] = 'H';
- make_model[1] = 'P';
- make_model[2] = ' ';
- strlcpy(make_model + 3, mmptr, make_model_size - 3);
- }
- else if (!strncasecmp(old_make_model, "deskjet", 7))
- snprintf(make_model, make_model_size, "HP DeskJet%s", old_make_model + 7);
- else if (!strncasecmp(old_make_model, "stylus_pro_", 11))
- snprintf(make_model, make_model_size, "EPSON Stylus Pro %s",
- old_make_model + 11);
- else
- strlcpy(make_model, old_make_model, make_model_size);
-
- if ((mmptr = strstr(make_model, ", Inc.,")) != NULL)
- {
- /*
- * Strip inc. from name, e.g. "Tektronix, Inc., Phaser 560"
- * becomes "Tektronix Phaser 560"...
- */
-
- _cups_strcpy(mmptr, mmptr + 7);
- }
-
- if ((mmptr = strstr(make_model, " Network")) != NULL)
- {
- /*
- * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
- * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
- */
-
- *mmptr = '\0';
- }
-
- if ((mmptr = strchr(make_model, ',')) != NULL)
- {
- /*
- * Drop anything after a trailing comma...
- */
-
- *mmptr = '\0';
- }
-}
-
-
-/*
- * 'free_array()' - Free an array of strings.
- */
-
-static void
-free_array(cups_array_t *a) /* I - Array */
-{
- char *s; /* Current string */
-
-
- for (s = (char *)cupsArrayFirst(a); s; s = (char *)cupsArrayNext(a))
- free(s);
-
- cupsArrayDelete(a);
-}
-
-
-/*
- * 'free_cache()' - Free the array of cached devices.
- */
-
-static void
-free_cache(void)
-{
- snmp_cache_t *cache; /* Cached device */
-
-
- for (cache = (snmp_cache_t *)cupsArrayFirst(Devices);
- cache;
- cache = (snmp_cache_t *)cupsArrayNext(Devices))
- {
- free(cache->addrname);
-
- if (cache->uri)
- free(cache->uri);
-
- if (cache->id)
- free(cache->id);
-
- if (cache->make_and_model)
- free(cache->make_and_model);
-
- free(cache);
- }
-
- cupsArrayDelete(Devices);
- Devices = NULL;
-}
-
-
-/*
- * 'get_interface_addresses()' - Get the broadcast address(es) associated
- * with an interface.
+ * 'get_interface_addresses()' - Get the broadcast address(es) associated
+ * with an interface.
*/
static http_addrlist_t * /* O - List of addresses */
{
current = calloc(1, sizeof(http_addrlist_t));
- memcpy(&(current->addr), addr->ifa_broadaddr,
- sizeof(struct sockaddr_in));
-
- if (!last)
- first = current;
- else
- last->next = current;
-
- last = current;
- }
-
- freeifaddrs(addrs);
-
- return (first);
-}
-
-
-/*
- * 'hex_debug()' - Output hex debugging data...
- */
-
-static void
-hex_debug(unsigned char *buffer, /* I - Buffer */
- size_t len) /* I - Number of bytes */
-{
- int col; /* Current column */
-
-
- fputs("DEBUG: Hex dump of packet:\n", stderr);
+ memcpy(&(current->addr), addr->ifa_broadaddr,
+ sizeof(struct sockaddr_in));
- for (col = 0; len > 0; col ++, buffer ++, len --)
- {
- if ((col & 15) == 0)
- fprintf(stderr, "DEBUG: %04X ", col);
+ if (!last)
+ first = current;
+ else
+ last->next = current;
- fprintf(stderr, " %02X", *buffer);
+ last = current;
+ }
- if ((col & 15) == 15)
- putc('\n', stderr);
- }
+ freeifaddrs(addrs);
- if (col & 15)
- putc('\n', stderr);
+ return (first);
}
list_device(snmp_cache_t *cache) /* I - Cached device */
{
if (cache->uri)
- printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
- cache->uri,
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->addrname, cache->id ? cache->id : "");
-}
-
-
-/*
- * 'open_snmp_socket()' - Open the SNMP broadcast socket.
- */
-
-static int /* O - SNMP socket file descriptor */
-open_snmp_socket(void)
-{
- int fd; /* SNMP socket file descriptor */
- int val; /* Socket option value */
-
-
- /*
- * Create the SNMP socket...
- */
-
- if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- fprintf(stderr, "ERROR: Unable to create SNMP socket - %s\n",
- strerror(errno));
-
- return (-1);
- }
-
- /*
- * Set the "broadcast" flag...
- */
-
- val = 1;
-
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
- {
- fprintf(stderr, "ERROR: Unable to set broadcast mode - %s\n",
- strerror(errno));
-
- close(fd);
-
- return (-1);
- }
-
- return (fd);
+ cupsBackendReport("network", cache->uri, cache->make_and_model,
+ cache->info, cache->id, cache->location);
}
static void
probe_device(snmp_cache_t *device) /* I - Device */
{
- int i, j; /* Looping vars */
- http_t *http; /* HTTP connection for IPP */
- char uri[1024]; /* Full device URI */
-
+ char uri[1024], /* Full device URI */
+ *uriptr, /* Pointer into URI */
+ *format; /* Format string for device */
+ device_uri_t *device_uri; /* Current DeviceURI match */
- /*
- * Try connecting via IPP first...
- */
debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);
- if (device->make_and_model &&
- (!strncasecmp(device->make_and_model, "Xerox", 5) ||
- !strncasecmp(device->make_and_model, "Kyocera", 7)))
- {
- /*
- * Xerox and Kyocera printers often lock up on IPP probes, so exclude
- * them from the IPP connection test...
- */
+#ifdef __APPLE__
+ /*
+ * If the printer supports Bonjour/mDNS, don't report it from the SNMP backend.
+ */
- http = NULL;
- }
- else
+ if (!try_connect(&(device->address), device->addrname, 5353))
{
- /*
- * Otherwise, try connecting for up to 1 second...
- */
-
- alarm(1);
- http = httpConnect(device->addrname, 631);
- alarm(0);
+ debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device->addrname);
+ return;
}
+#endif /* __APPLE__ */
- if (http);
- {
- /*
- * IPP is supported...
- */
-
- ipp_t *request, /* IPP request */
- *response; /* IPP response */
- ipp_attribute_t *model, /* printer-make-and-model attribute */
- *info, /* printer-info attribute */
- *supported; /* printer-uri-supported attribute */
- char make_model[256],/* Make and model string to use */
- temp[256]; /* Temporary make/model string */
- int num_uris; /* Number of good URIs */
- static const char * const resources[] =
- { /* Common resource paths for IPP */
- "/ipp",
- "/ipp/port2",
- "/ipp/port3",
- "/EPSON_IPP_Printer",
- "/LPT1",
- "/LPT2",
- "/COM1",
- "/"
- };
-
-
- /*
- * Use non-blocking IO...
- */
-
- httpBlocking(http, 0);
-
- /*
- * Loop through a list of common resources that covers 99% of the
- * IPP-capable printers on the market today...
- */
+ /*
+ * Lookup the device in the match table...
+ */
- for (i = 0, num_uris = 0;
- i < (int)(sizeof(resources) / sizeof(resources[0]));
- i ++)
+ for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs);
+ device_uri;
+ device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs))
+ if (device->make_and_model &&
+ !regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0))
{
/*
- * Stop early if we are out of time...
- */
-
- if (MaxRunTime > 0 && run_time() >= MaxRunTime)
- break;
-
- /*
- * Don't look past /ipp if we have found a working URI...
+ * Found a match, add the URIs...
*/
- if (num_uris > 0 && strncmp(resources[i], "/ipp", 4))
- break;
-
- httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
- device->addrname, 631, resources[i]);
-
- request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
-
- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
- NULL, uri);
-
- response = do_request(http, request, resources[i]);
-
- debug_printf("DEBUG: %.3f %s %s (%s)\n", run_time(), uri,
- ippErrorString(cupsLastError()), cupsLastErrorString());
-
- if (response && response->request.status.status_code == IPP_OK)
+ for (format = (char *)cupsArrayFirst(device_uri->uris);
+ format;
+ format = (char *)cupsArrayNext(device_uri->uris))
{
- model = ippFindAttribute(response, "printer-make-and-model",
- IPP_TAG_TEXT);
- info = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT);
- supported = ippFindAttribute(response, "printer-uri-supported",
- IPP_TAG_URI);
-
- if (!supported)
- {
- fprintf(stderr, "ERROR: Missing printer-uri-supported from %s!\n",
- device->addrname);
-
- httpClose(http);
- return;
- }
-
- debug_printf("DEBUG: printer-info=\"%s\"\n",
- info ? info->values[0].string.text : "(null)");
- debug_printf("DEBUG: printer-make-and-model=\"%s\"\n",
- model ? model->values[0].string.text : "(null)");
-
- /*
- * Don't advertise this port if the printer actually only supports
- * a more generic version...
- */
-
- if (!strncmp(resources[i], "/ipp/", 5))
- {
- for (j = 0; j < supported->num_values; j ++)
- if (strstr(supported->values[j].string.text, "/ipp/"))
- break;
-
- if (j >= supported->num_values)
+ for (uriptr = uri; *format && uriptr < (uri + sizeof(uri) - 1);)
+ if (*format == '%' && format[1] == 's')
{
- ippDelete(response);
- break;
- }
- }
-
- /*
- * Don't use the printer-info attribute if it does not contain the
- * IEEE-1284 device ID data...
- */
-
- if (info &&
- (!strchr(info->values[0].string.text, ':') ||
- !strchr(info->values[0].string.text, ';')))
- info = NULL;
-
- /*
- * Don't use the printer-make-and-model if it contains a generic
- * string like "Ricoh IPP Printer"...
- */
-
- if (model && strstr(model->values[0].string.text, "IPP Printer"))
- model = NULL;
-
- /*
- * If we don't have a printer-make-and-model string from the printer
- * but do have the 1284 device ID string, generate a make-and-model
- * string from the device ID info...
- */
-
- if (model)
- strlcpy(temp, model->values[0].string.text, sizeof(temp));
- else if (info)
- backendGetMakeModel(info->values[0].string.text, temp, sizeof(temp));
- else
- temp[0] = '\0';
+ /*
+ * Insert hostname/address...
+ */
- fix_make_model(make_model, temp, sizeof(make_model));
-
- /*
- * Update the current device or add a new printer to the cache...
- */
+ strlcpy(uriptr, device->addrname, sizeof(uri) - (uriptr - uri));
+ uriptr += strlen(uriptr);
+ format += 2;
+ }
+ else
+ *uriptr++ = *format++;
- if (num_uris == 0)
- update_cache(device, uri,
- info ? info->values[0].string.text : NULL,
- make_model[0] ? make_model : NULL);
- else
- add_cache(&(device->address), device->addrname, uri,
- info ? info->values[0].string.text : NULL,
- make_model[0] ? make_model : NULL);
+ *uriptr = '\0';
- num_uris ++;
+ update_cache(device, uri, NULL, NULL);
}
- ippDelete(response);
-
- if (num_uris > 0 && cupsLastError() != IPP_OK)
- break;
- }
-
- httpClose(http);
-
- if (num_uris > 0)
return;
- }
+ }
/*
- * OK, now try the standard ports...
+ * Then try the standard ports...
*/
if (!try_connect(&(device->address), device->addrname, 9100))
if (!value)
fprintf(stderr, "ERROR: Missing value on line %d of %s!\n", linenum,
filename);
- else if (!strcasecmp(line, "Address"))
+ else if (!_cups_strcasecmp(line, "Address"))
{
if (!address)
add_array(Addresses, value);
}
- else if (!strcasecmp(line, "Community"))
+ else if (!_cups_strcasecmp(line, "Community"))
add_array(Communities, value);
- else if (!strcasecmp(line, "DebugLevel"))
+ else if (!_cups_strcasecmp(line, "DebugLevel"))
DebugLevel = atoi(value);
- else if (!strcasecmp(line, "HostNameLookups"))
- HostNameLookups = !strcasecmp(value, "on") ||
- !strcasecmp(value, "yes") ||
- !strcasecmp(value, "true") ||
- !strcasecmp(value, "double");
- else if (!strcasecmp(line, "MaxRunTime"))
+ else if (!_cups_strcasecmp(line, "DeviceURI"))
+ {
+ if (*value != '\"')
+ fprintf(stderr,
+ "ERROR: Missing double quote for regular expression on "
+ "line %d of %s!\n", linenum, filename);
+ else
+ add_device_uri(value);
+ }
+ else if (!_cups_strcasecmp(line, "HostNameLookups"))
+ HostNameLookups = !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "true") ||
+ !_cups_strcasecmp(value, "double");
+ else if (!_cups_strcasecmp(line, "MaxRunTime"))
MaxRunTime = atoi(value);
else
fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n",
if (cupsArrayCount(Addresses) == 0)
{
- fputs("INFO: Using default SNMP Address @LOCAL\n", stderr);
- add_array(Addresses, "@LOCAL");
+ /*
+ * If we have no addresses, exit immediately...
+ */
+
+ fprintf(stderr,
+ "DEBUG: No address specified and no Address line in %s...\n",
+ filename);
+ exit(0);
}
if (cupsArrayCount(Communities) == 0)
static void
read_snmp_response(int fd) /* I - SNMP socket file descriptor */
{
- unsigned char buffer[SNMP_MAX_PACKET];/* Data packet */
- int bytes; /* Number of bytes received */
- http_addr_t addr; /* Source address */
- socklen_t addrlen; /* Source address length */
char addrname[256]; /* Source address name */
- snmp_packet_t packet; /* Decoded packet */
+ cups_snmp_t packet; /* Decoded packet */
snmp_cache_t key, /* Search key */
*device; /* Matching device */
* Read the response data...
*/
- addrlen = sizeof(addr);
-
- if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (void *)&addr,
- &addrlen)) < 0)
+ if (!_cupsSNMPRead(fd, &packet, -1.0))
{
fprintf(stderr, "ERROR: Unable to read data from socket: %s\n",
strerror(errno));
}
if (HostNameLookups)
- httpAddrLookup(&addr, addrname, sizeof(addrname));
+ httpAddrLookup(&(packet.address), addrname, sizeof(addrname));
else
- httpAddrString(&addr, addrname, sizeof(addrname));
+ httpAddrString(&(packet.address), addrname, sizeof(addrname));
- debug_printf("DEBUG: %.3f Received %d bytes from %s...\n", run_time(),
- bytes, addrname);
+ debug_printf("DEBUG: %.3f Received data from %s...\n", run_time(), addrname);
/*
* Look for the response status code in the SNMP message header...
*/
- if (asn1_decode_snmp(buffer, bytes, &packet))
+ if (packet.error)
{
fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n", addrname,
packet.error);
- asn1_debug(buffer, bytes, 0);
- hex_debug(buffer, bytes);
-
return;
}
debug_printf("DEBUG: request-id=%d\n", packet.request_id);
debug_printf("DEBUG: error-status=%d\n", packet.error_status);
- if (DebugLevel > 1)
- asn1_debug(buffer, bytes, 0);
-
- if (DebugLevel > 2)
- hex_debug(buffer, bytes);
-
- if (packet.error_status)
+ if (packet.error_status && packet.request_id != DEVICE_TYPE)
return;
/*
* Process the message...
*/
- if (packet.request_id == DeviceTypeRequest)
+ switch (packet.request_id)
{
- /*
- * Got the device type response...
- */
+ case DEVICE_TYPE :
+ /*
+ * Got the device type response...
+ */
- if (device)
- {
- debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
- addrname);
- return;
- }
+ if (device)
+ {
+ debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
+ addrname);
+ return;
+ }
- /*
- * Add the device and request the device description...
- */
+ /*
+ * Add the device and request the device data...
+ */
- add_cache(&addr, addrname, NULL, NULL, NULL);
+ add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_DESCRIPTION, DescriptionOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, DeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_URI, UriOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_LOCATION, LocationOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID2);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, LexmarkDeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, XeroxProductOID);
+ break;
- send_snmp_query(fd, &addr, SNMP_VERSION_1, packet.community,
- DeviceDescRequest, DeviceDescOID);
- }
- else if (packet.request_id == DeviceDescRequest &&
- packet.object_type == ASN1_OCTET_STRING)
- {
- /*
- * Update an existing cache entry...
- */
+ case DEVICE_DESCRIPTION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Update an existing cache entry...
+ */
- char make_model[256]; /* Make and model */
+ char make_model[256]; /* Make and model */
- if (!device)
- {
- debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
- addrname);
- return;
- }
+ if (strchr((char *)packet.object_value.string.bytes, ':') &&
+ strchr((char *)packet.object_value.string.bytes, ';'))
+ {
+ /*
+ * Description is the IEEE-1284 device ID...
+ */
- /*
- * Convert the description to a make and model string...
- */
+ char *ptr; /* Pointer into device ID */
- if (strchr(packet.object_value.string, ':') &&
- strchr(packet.object_value.string, ';'))
- {
- /*
- * Description is the IEEE-1284 device ID...
- */
+ for (ptr = (char *)packet.object_value.string.bytes; *ptr; ptr ++)
+ if (*ptr == '\n')
+ *ptr = ';'; /* A lot of bad printers put a newline */
+ if (!device->id)
+ device->id = strdup((char *)packet.object_value.string.bytes);
- backendGetMakeModel(packet.object_value.string, make_model,
- sizeof(make_model));
- }
- else
- {
- /*
- * Description is plain text...
- */
+ backendGetMakeModel((char *)packet.object_value.string.bytes,
+ make_model, sizeof(make_model));
- fix_make_model(make_model, packet.object_value.string,
- sizeof(make_model));
- }
+ if (device->info)
+ free(device->info);
- if (device->make_and_model)
- free(device->make_and_model);
+ device->info = strdup(make_model);
+ }
+ else
+ {
+ /*
+ * Description is plain text...
+ */
- device->make_and_model = strdup(make_model);
+ fix_make_model(make_model, (char *)packet.object_value.string.bytes,
+ sizeof(make_model));
+
+ if (device->info)
+ free(device->info);
+
+ device->info = strdup((char *)packet.object_value.string.bytes);
+ }
+
+ if (!device->make_and_model)
+ device->make_and_model = strdup(make_model);
+ }
+ break;
+
+ case DEVICE_ID :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ (!device->id ||
+ strlen(device->id) < packet.object_value.string.num_bytes))
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ char make_model[256]; /* Make and model */
+ char *ptr; /* Pointer into device ID */
+
+ for (ptr = (char *)packet.object_value.string.bytes; *ptr; ptr ++)
+ if (*ptr == '\n')
+ *ptr = ';'; /* A lot of bad printers put a newline */
+ if (device->id)
+ free(device->id);
+
+ device->id = strdup((char *)packet.object_value.string.bytes);
+
+ /*
+ * Convert the ID to a make and model string...
+ */
+
+ backendGetMakeModel((char *)packet.object_value.string.bytes,
+ make_model, sizeof(make_model));
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup(make_model);
+ }
+ break;
+
+ case DEVICE_LOCATION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->location)
+ device->location = strdup((char *)packet.object_value.string.bytes);
+ break;
+
+ case DEVICE_PRODUCT :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->id)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ if (!device->info)
+ device->info = strdup((char *)packet.object_value.string.bytes);
+
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup((char *)packet.object_value.string.bytes);
+ }
+ break;
+
+ case DEVICE_URI :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->uri && packet.object_value.string.num_bytes > 3)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ char scheme[32], /* URI scheme */
+ userpass[256], /* Username:password in URI */
+ hostname[256], /* Hostname in URI */
+ resource[1024]; /* Resource path in URI */
+ int port; /* Port number in URI */
+
+ if (!strncmp((char *)packet.object_value.string.bytes, "lpr:", 4))
+ {
+ /*
+ * We want "lpd://..." for the URI...
+ */
+
+ packet.object_value.string.bytes[2] = 'd';
+ }
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL,
+ (char *)packet.object_value.string.bytes,
+ scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource)) >= HTTP_URI_OK)
+ device->uri = strdup((char *)packet.object_value.string.bytes);
+ }
+ break;
}
}
*/
static void
-scan_devices(int fd) /* I - SNMP socket */
+scan_devices(int ipv4, /* I - SNMP IPv4 socket */
+ int ipv6) /* I - SNMP IPv6 socket */
{
+ int fd, /* File descriptor for this address */
+ busy; /* Are we busy processing something? */
char *address, /* Current address */
*community; /* Current community */
fd_set input; /* Input set for select() */
http_addrlist_t *addrs, /* List of addresses */
*addr; /* Current address */
snmp_cache_t *device; /* Current device */
+ char temp[1024]; /* Temporary address string */
- /*
- * Setup the request IDs...
- */
-
gettimeofday(&StartTime, NULL);
- DeviceTypeRequest = StartTime.tv_sec;
- DeviceDescRequest = StartTime.tv_sec + 1;
-
/*
* First send all of the broadcast queries...
*/
{
char ifname[255]; /* Interface name */
-
strlcpy(ifname, address + 4, sizeof(ifname));
if (ifname[0])
ifname[strlen(ifname) - 1] = '\0';
addrs = get_interface_addresses(ifname);
}
else
- addrs = httpAddrGetList(address, AF_INET, NULL);
+ addrs = httpAddrGetList(address, AF_UNSPEC, NULL);
if (!addrs)
{
community, address);
for (addr = addrs; addr; addr = addr->next)
- send_snmp_query(fd, &(addr->addr), SNMP_VERSION_1, community,
- DeviceTypeRequest, DeviceTypeOID);
+ {
+#ifdef AF_INET6
+ if (_httpAddrFamily(&(addr->addr)) == AF_INET6)
+ fd = ipv6;
+ else
+#endif /* AF_INET6 */
+ fd = ipv4;
+
+ debug_printf("DEBUG: Sending get request to %s...\n",
+ httpAddrString(&(addr->addr), temp, sizeof(temp)));
+
+ _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
+ CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
+ }
}
httpAddrFreeList(addrs);
* Then read any responses that come in over the next 3 seconds...
*/
- endtime = time(NULL) + 3;
+ endtime = time(NULL) + MaxRunTime;
FD_ZERO(&input);
while (time(NULL) < endtime)
{
- timeout.tv_sec = 1;
+ timeout.tv_sec = 2;
timeout.tv_usec = 0;
- FD_SET(fd, &input);
+ FD_SET(ipv4, &input);
+ if (ipv6 >= 0)
+ FD_SET(ipv6, &input);
+
+ fd = ipv4 > ipv6 ? ipv4 : ipv6;
if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
{
- fprintf(stderr, "ERROR: %.3f select() for %d failed: %s\n", run_time(),
- fd, strerror(errno));
+ fprintf(stderr, "ERROR: %.3f select() for %d/%d failed: %s\n", run_time(),
+ ipv4, ipv6, strerror(errno));
break;
}
- if (FD_ISSET(fd, &input))
- read_snmp_response(fd);
- else
- break;
- }
-
- /*
- * Finally, probe all of the printers we discovered to see how they are
- * connected...
- */
-
- for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
- device;
- device = (snmp_cache_t *)cupsArrayNext(Devices))
- if (MaxRunTime > 0 && run_time() >= MaxRunTime)
- break;
- else if (!device->uri)
- probe_device(device);
-
- debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
-}
-
-
-/*
- * 'send_snmp_query()' - Send an SNMP query packet.
- */
-
-static void
-send_snmp_query(
- int fd, /* I - SNMP socket */
- http_addr_t *addr, /* I - Address to send to */
- int version, /* I - SNMP version */
- const char *community, /* I - Community name */
- const unsigned request_id, /* I - Request ID */
- const int *oid) /* I - OID */
-{
- int i; /* Looping var */
- snmp_packet_t packet; /* SNMP message packet */
- unsigned char buffer[SNMP_MAX_PACKET];/* SNMP message buffer */
- int bytes; /* Size of message */
- char addrname[32]; /* Address name */
+ busy = 0;
+ if (FD_ISSET(ipv4, &input))
+ {
+ read_snmp_response(ipv4);
+ busy = 1;
+ }
- /*
- * Create the SNMP message...
- */
+ if (ipv6 >= 0 && FD_ISSET(ipv6, &input))
+ {
+ read_snmp_response(ipv6);
+ busy = 1;
+ }
- memset(&packet, 0, sizeof(packet));
+ if (!busy)
+ {
+ /*
+ * List devices with complete information...
+ */
- packet.version = version;
- packet.request_type = ASN1_GET_REQUEST;
- packet.request_id = request_id;
- packet.object_type = ASN1_NULL_VALUE;
-
- strlcpy(packet.community, community, sizeof(packet.community));
+ int sent_something = 0;
- for (i = 0; oid[i]; i ++)
- packet.object_name[i] = oid[i];
+ for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
+ device;
+ device = (snmp_cache_t *)cupsArrayNext(Devices))
+ if (!device->sent && device->info && device->make_and_model)
+ {
+ if (device->uri)
+ list_device(device);
+ else
+ probe_device(device);
- bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);
+ device->sent = sent_something = 1;
+ }
- if (bytes < 0)
- {
- fprintf(stderr, "ERROR: Unable to send SNMP query: %s\n", packet.error);
- return;
+ if (!sent_something)
+ break;
+ }
}
- /*
- * Send the message...
- */
-
- debug_printf("DEBUG: %.3f Sending %d bytes to %s...\n", run_time(),
- bytes, httpAddrString(addr, addrname, sizeof(addrname)));
- if (DebugLevel > 1)
- asn1_debug(buffer, bytes, 0);
- if (DebugLevel > 2)
- hex_debug(buffer, bytes);
-
- addr->ipv4.sin_port = htons(SNMP_PORT);
-
- if (sendto(fd, buffer, bytes, 0, (void *)addr, sizeof(addr->ipv4)) < bytes)
- fprintf(stderr, "ERROR: Unable to send %d bytes to %s: %s\n",
- bytes, addrname, strerror(errno));
+ debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
}
debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(),
port == 515 ? "lpd" : "socket", addrname, port);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ if ((fd = socket(_httpAddrFamily(addr), SOCK_STREAM, 0)) < 0)
{
- fprintf(stderr, "ERROR: Unable to create socket: %s\n", strerror(errno));
+ fprintf(stderr, "ERROR: Unable to create socket: %s\n",
+ strerror(errno));
return (-1);
}
- addr->ipv4.sin_port = htons(port);
+ _httpAddrSetPort(addr, port);
alarm(1);
/*
- * End of "$Id: snmp.c 5898 2006-08-28 18:54:10Z mike $".
+ * End of "$Id$".
*/