X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=backend%2Fsnmp.c;h=a94e89c578a4ee482f088c037e9e520bbf8c9182;hb=61515785f7de12d8b2a29090020e684988f89977;hp=916430bd8d218a19c0707cd05ec1674e5010b954;hpb=bc44d92092094935265183305a38196ce2822756;p=thirdparty%2Fcups.git diff --git a/backend/snmp.c b/backend/snmp.c index 916430bd8..a94e89c57 100644 --- a/backend/snmp.c +++ b/backend/snmp.c @@ -1,9 +1,9 @@ /* - * "$Id: snmp.c 6649 2007-07-11 21:46:42Z mike $" + * "$Id: snmp.c 10996 2013-05-29 11:51:34Z msweet $" * - * SNMP discovery backend for the Common UNIX Printing System (CUPS). + * SNMP discovery backend for CUPS. * - * Copyright 2007 by Apple Inc. + * 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 @@ -21,38 +21,15 @@ * 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. * 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. @@ -60,7 +37,6 @@ * 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... */ @@ -69,24 +45,22 @@ * Include necessary headers. */ -#include #include "backend-private.h" #include #include +#include #include /* * This backend implements SNMP printer discovery. It uses a broadcast- * based approach to get SNMP response packets from potential printers, - * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on - * the device description string, and finally a probe of port 9100 - * (AppSocket) and 515 (LPD). + * 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 @@ -108,12 +82,13 @@ * Community public * DebugLevel 0 * HostNameLookups off - * MaxRunTime 10 + * 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 @@ -132,32 +107,20 @@ * (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 */ @@ -170,38 +133,12 @@ typedef struct snmp_cache_s /**** SNMP scan cache ****/ 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... @@ -213,40 +150,6 @@ static void add_cache(http_addr_t *addr, const char *addrname, 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 void fix_make_model(char *make_model, @@ -255,19 +158,13 @@ static void fix_make_model(char *make_model, 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, @@ -282,15 +179,18 @@ static cups_array_t *Addresses = NULL; static cups_array_t *Communities = NULL; static cups_array_t *Devices = NULL; static int DebugLevel = 0; -static int DeviceDescOID[] = { 1, 3, 6, 1, 2, 1, 25, 3, - 2, 1, 3, 1, 0 }; -static unsigned DeviceDescRequest; -static int DeviceTypeOID[] = { 1, 3, 6, 1, 2, 1, 25, 3, - 2, 1, 2, 1, 0 }; -static unsigned DeviceTypeRequest; +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; @@ -302,7 +202,8 @@ int /* O - Exit status */ 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 */ @@ -314,7 +215,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (argc > 2) { - fputs(_("Usage: snmp [host-or-ip-address]\n"), stderr); + _cupsLangPuts(stderr, _("Usage: snmp [host-or-ip-address]")); return (1); } @@ -345,28 +246,39 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * 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); @@ -547,778 +459,6 @@ alarm_handler(int sig) /* I - Signal number */ } -/* - * 'asn1_decode_snmp()' - Decode a SNMP packet. - */ - -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 */ -{ - unsigned char *bufptr, /* Pointer into the data */ - *bufend; /* End of data */ - int length; /* Length of value */ - - - /* - * Initialize the decoding... - */ - - 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; - } - } - } - } - } - } - } - - return (packet->error ? -1 : 0); -} - - -/* - * 'asn1_debug()' - Decode an ASN1-encoded message. - */ - -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 */ - - - bufend = buffer + len; - - while (buffer < bufend) - { - /* - * Get value type... - */ - - value_type = asn1_get_type(&buffer, bufend); - value_length = asn1_get_length(&buffer, bufend); - - 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; - } - } -} - - -/* - * '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 */ - - - /* - * Get the lengths of the community string, OID, and message... - */ - - namelen = asn1_size_oid(packet->object_name); - - switch (packet->object_type) - { - 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; - - case ASN1_OCTET_STRING : - valuelen = strlen(packet->object_value.string); - break; - - case ASN1_OID : - valuelen = asn1_size_oid(packet->object_value.oid); - break; - - default : - packet->error = "Unknown object type"; - return (-1); - } - - 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); - } - - /* - * Then format the message... - */ - - bufptr = buffer; - - *bufptr++ = ASN1_SEQUENCE; /* SNMPv1 message header */ - asn1_set_length(&bufptr, msglen); - - asn1_set_integer(&bufptr, packet->version); - /* version */ - - *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 */ - - 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; - - case ASN1_INTEGER : - asn1_set_integer(&bufptr, packet->object_value.integer); - break; - - case ASN1_OCTET_STRING : - *bufptr++ = ASN1_OCTET_STRING; - asn1_set_length(&bufptr, valuelen); - memcpy(bufptr, packet->object_value.string, valuelen); - bufptr += valuelen; - break; - - case ASN1_OID : - asn1_set_oid(&bufptr, packet->object_value.oid); - break; - } - - return (bufptr - buffer); -} - - -/* - * 'asn1_get_integer()' - Get an integer value. - */ - -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 */ -{ - int value; /* Integer value */ - - - for (value = 0; - length > 0 && *buffer < bufend; - length --, (*buffer) ++) - value = (value << 8) | **buffer; - - return (value); -} - - -/* - * 'asn1_get_length()' - Get a value length. - */ - -static int /* O - Length */ -asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */ - unsigned char *bufend) /* I - End of buffer */ -{ - int length; /* Length */ - - - length = **buffer; - (*buffer) ++; - - if (length & 128) - length = asn1_get_integer(buffer, bufend, length & 127); - - return (length); -} - - -/* - * 'asn1_get_oid()' - Get an OID value. - */ - -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 */ -{ - unsigned char *valend; /* End of value */ - int *oidend; /* End of OID buffer */ - int number; /* OID number */ - - - valend = *buffer + length; - oidend = oid + oidsize - 1; - - if (valend > bufend) - valend = bufend; - - number = asn1_get_packed(buffer, bufend); - - if (number < 80) - { - *oid++ = number / 40; - number = number % 40; - *oid++ = number; - } - else - { - *oid++ = 2; - number -= 80; - *oid++ = number; - } - - while (*buffer < valend) - { - number = asn1_get_packed(buffer, bufend); - - if (oid < oidend) - *oid++ = number; - } - - *oid = 0; - - return (number); -} - - -/* - * 'asn1_get_packed()' - Get a packed integer value. - */ - -static int /* O - Value */ -asn1_get_packed( - unsigned char **buffer, /* IO - Pointer in buffer */ - unsigned char *bufend) /* I - End of buffer */ -{ - int value; /* Value */ - - - value = 0; - - while ((**buffer & 128) && *buffer < bufend) - { - value = (value << 7) | (**buffer & 127); - (*buffer) ++; - } - - if (*buffer < bufend) - { - value = (value << 7) | **buffer; - (*buffer) ++; - } - - return (value); -} - - -/* - * 'asn1_get_string()' - Get a string value. - */ - -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 */ -{ - if (length < strsize) - { - memcpy(string, *buffer, length); - string[length] = '\0'; - } - else - { - memcpy(string, buffer, strsize - 1); - string[strsize - 1] = '\0'; - } - - (*buffer) += length; - - return (string); -} - - -/* - * 'asn1_get_type()' - Get a value type. - */ - -static int /* O - Type */ -asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */ - unsigned char *bufend) /* I - End of buffer */ -{ - int type; /* Type */ - - - type = **buffer; - (*buffer) ++; - - if ((type & 31) == 31) - type = asn1_get_packed(buffer, bufend); - - return (type); -} - - -/* - * '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 >> 28) & 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. */ @@ -1327,7 +467,7 @@ 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)); + return (_cups_strcasecmp(a->addrname, b->addrname)); } @@ -1369,7 +509,7 @@ fix_make_model( * that printer driver detection works better... */ - if (!strncasecmp(old_make_model, "Hewlett-Packard", 15)) + if (!_cups_strncasecmp(old_make_model, "Hewlett-Packard", 15)) { /* * Strip leading Hewlett-Packard and hp prefixes and replace @@ -1381,7 +521,7 @@ fix_make_model( while (isspace(*mmptr & 255)) mmptr ++; - if (!strncasecmp(mmptr, "hp", 2)) + if (!_cups_strncasecmp(mmptr, "hp", 2)) { mmptr += 2; @@ -1394,11 +534,11 @@ fix_make_model( make_model[2] = ' '; strlcpy(make_model + 3, mmptr, make_model_size - 3); } - else if (!strncasecmp(old_make_model, "deskjet", 7)) + else if (!_cups_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, "officejet", 9)) + else if (!_cups_strncasecmp(old_make_model, "officejet", 9)) snprintf(make_model, make_model_size, "HP OfficeJet%s", old_make_model + 9); - else if (!strncasecmp(old_make_model, "stylus_pro_", 11)) + 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 @@ -1528,35 +668,6 @@ get_interface_addresses( } -/* - * '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); - - for (col = 0; len > 0; col ++, buffer ++, len --) - { - if ((col & 15) == 0) - fprintf(stderr, "DEBUG: %04X ", col); - - fprintf(stderr, " %02X", *buffer); - - if ((col & 15) == 15) - putc('\n', stderr); - } - - if (col & 15) - putc('\n', stderr); -} - - /* * 'list_device()' - List a device we found... */ @@ -1565,54 +676,8 @@ static void 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); } @@ -1653,7 +718,7 @@ probe_device(snmp_cache_t *device) /* I - Device */ #ifdef __APPLE__ /* - * TODO: Try an mDNS query first, and then fallback on direct probes... + * If the printer supports Bonjour/mDNS, don't report it from the SNMP backend. */ if (!try_connect(&(device->address), device->addrname, 5353)) @@ -1670,7 +735,8 @@ probe_device(snmp_cache_t *device) /* I - Device */ for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs); device_uri; device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs)) - if (!regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0)) + if (device->make_and_model && + !regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0)) { /* * Found a match, add the URIs... @@ -1778,16 +844,16 @@ read_snmp_conf(const char *address) /* I - Single address to probe */ 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, "DeviceURI")) + else if (!_cups_strcasecmp(line, "DeviceURI")) { if (*value != '\"') fprintf(stderr, @@ -1796,12 +862,12 @@ read_snmp_conf(const char *address) /* I - Single address to probe */ else add_device_uri(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, "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", @@ -1842,12 +908,8 @@ read_snmp_conf(const char *address) /* I - Single address to probe */ 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 */ @@ -1856,10 +918,7 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ * 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)); @@ -1867,24 +926,20 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ } 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); + fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n", addrname, + packet.error); return; } @@ -1893,13 +948,7 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ 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; /* @@ -1913,73 +962,194 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ * 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(&(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; - add_cache(&addr, addrname, NULL, NULL, NULL); + case DEVICE_DESCRIPTION : + if (device && packet.object_type == CUPS_ASN1_OCTET_STRING) + { + /* + * Update an existing cache entry... + */ - 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... - */ + char make_model[256]; /* Make and model */ - char make_model[256]; /* Make and model */ + if (strchr((char *)packet.object_value.string.bytes, ':') && + strchr((char *)packet.object_value.string.bytes, ';')) + { + /* + * Description is the IEEE-1284 device ID... + */ - if (!device) - { - debug_printf("DEBUG: Discarding device description for \"%s\"...\n", - addrname); - return; - } + char *ptr; /* Pointer into device ID */ - /* - * Convert the description to a make and model string... - */ + 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); - if (strchr(packet.object_value.string, ':') && - strchr(packet.object_value.string, ';')) - { - /* - * Description is the IEEE-1284 device ID... - */ + backendGetMakeModel((char *)packet.object_value.string.bytes, + make_model, sizeof(make_model)); - backendGetMakeModel(packet.object_value.string, make_model, - sizeof(make_model)); - } - else - { - /* - * Description is plain text... - */ + if (device->info) + free(device->info); - fix_make_model(make_model, packet.object_value.string, - sizeof(make_model)); - } + device->info = strdup(make_model); + } + else + { + /* + * Description is plain text... + */ - if (device->make_and_model) - free(device->make_and_model); + fix_make_model(make_model, (char *)packet.object_value.string.bytes, + sizeof(make_model)); - device->make_and_model = strdup(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; } } @@ -2006,8 +1176,11 @@ run_time(void) */ 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() */ @@ -2016,17 +1189,11 @@ scan_devices(int fd) /* I - SNMP socket */ 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... */ @@ -2041,7 +1208,6 @@ scan_devices(int fd) /* I - SNMP socket */ { char ifname[255]; /* Interface name */ - strlcpy(ifname, address + 4, sizeof(ifname)); if (ifname[0]) ifname[strlen(ifname) - 1] = '\0'; @@ -2049,7 +1215,7 @@ scan_devices(int fd) /* I - SNMP socket */ addrs = get_interface_addresses(ifname); } else - addrs = httpAddrGetList(address, AF_INET, NULL); + addrs = httpAddrGetList(address, AF_UNSPEC, NULL); if (!addrs) { @@ -2065,8 +1231,20 @@ scan_devices(int fd) /* I - SNMP socket */ 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); @@ -2076,107 +1254,68 @@ scan_devices(int fd) /* I - SNMP socket */ * 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()); } @@ -2196,14 +1335,14 @@ try_connect(http_addr_t *addr, /* I - Socket address */ 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)); return (-1); } - addr->ipv4.sin_port = htons(port); + _httpAddrSetPort(addr, port); alarm(1); @@ -2252,5 +1391,5 @@ update_cache(snmp_cache_t *device, /* I - Device */ /* - * End of "$Id: snmp.c 6649 2007-07-11 21:46:42Z mike $". + * End of "$Id: snmp.c 10996 2013-05-29 11:51:34Z msweet $". */