]>
git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp.c
2 * "$Id: snmp.c 6495 2007-04-30 21:23:04Z mike $"
4 * SNMP discovery backend for the Common UNIX Printing System (CUPS).
6 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * main() - Discover printers via SNMP.
29 * add_array() - Add a string to an array.
30 * add_cache() - Add a cached device...
31 * add_device_uri() - Add a device URI to the cache.
32 * alarm_handler() - Handle alarm signals...
33 * asn1_decode_snmp() - Decode a SNMP packet.
34 * asn1_debug() - Decode an ASN1-encoded message.
35 * asn1_encode_snmp() - Encode a SNMP packet.
36 * asn1_get_integer() - Get an integer value.
37 * asn1_get_length() - Get a value length.
38 * asn1_get_oid() - Get an OID value.
39 * asn1_get_packed() - Get a packed integer value.
40 * asn1_get_string() - Get a string value.
41 * asn1_get_type() - Get a value type.
42 * asn1_set_integer() - Set an integer value.
43 * asn1_set_length() - Set a value length.
44 * asn1_set_oid() - Set an OID value.
45 * asn1_set_packed() - Set a packed integer value.
46 * asn1_size_integer() - Figure out the number of bytes needed for an
48 * asn1_size_length() - Figure out the number of bytes needed for a
50 * asn1_size_oid() - Figure out the numebr of bytes needed for an
52 * asn1_size_packed() - Figure out the number of bytes needed for a
53 * packed integer value.
54 * compare_cache() - Compare two cache entries.
55 * debug_printf() - Display some debugging information.
56 * fix_make_model() - Fix common problems in the make-and-model
58 * free_array() - Free an array of strings.
59 * free_cache() - Free the array of cached devices.
60 * get_interface_addresses() - Get the broadcast address(es) associated
62 * hex_debug() - Output hex debugging data...
63 * list_device() - List a device we found...
64 * open_snmp_socket() - Open the SNMP broadcast socket.
65 * password_cb() - Handle authentication requests.
66 * probe_device() - Probe a device to discover whether it is a
68 * read_snmp_conf() - Read the snmp.conf file.
69 * read_snmp_response() - Read and parse a SNMP response...
70 * run_time() - Return the total running time...
71 * scan_devices() - Scan for devices using SNMP.
72 * send_snmp_query() - Send an SNMP query packet.
73 * try_connect() - Try connecting on a port...
74 * update_cache() - Update a cached device...
78 * Include necessary headers.
81 #include <cups/http-private.h>
82 #include "backend-private.h"
83 #include <cups/array.h>
84 #include <cups/file.h>
89 * This backend implements SNMP printer discovery. It uses a broadcast-
90 * based approach to get SNMP response packets from potential printers,
91 * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on
92 * the device description string, and finally a probe of port 9100
93 * (AppSocket) and 515 (LPD).
95 * The current focus is on printers with internal network cards, although
96 * the code also works with many external print servers as well. Future
97 * versions will support scanning for vendor-specific SNMP OIDs and the
98 * new PWG Port Monitor MIB and not just the Host MIB OIDs.
100 * The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
101 * which can contain comments, blank lines, or any number of the following
109 * DeviceURI "regex pattern" uri
111 * HostNameLookups off
114 * The default is to use:
119 * HostNameLookups off
122 * This backend is known to work with the following network printers and
125 * Axis OfficeBasic, 5400, 5600
134 * It does not currently work with:
141 * (for all of these, they do not support the Host MIB)
148 #define SNMP_PORT 161 /* SNMP well-known port */
149 #define SNMP_MAX_OID 64 /* Maximum number of OID numbers */
150 #define SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */
151 #define SNMP_MAX_STRING 512 /* Maximum size of string */
152 #define SNMP_VERSION_1 0 /* SNMPv1 */
154 #define ASN1_END_OF_CONTENTS 0x00 /* End-of-contents */
155 #define ASN1_BOOLEAN 0x01 /* BOOLEAN */
156 #define ASN1_INTEGER 0x02 /* INTEGER or ENUMERATION */
157 #define ASN1_BIT_STRING 0x03 /* BIT STRING */
158 #define ASN1_OCTET_STRING 0x04 /* OCTET STRING */
159 #define ASN1_NULL_VALUE 0x05 /* NULL VALUE */
160 #define ASN1_OID 0x06 /* OBJECT IDENTIFIER */
161 #define ASN1_SEQUENCE 0x30 /* SEQUENCE */
162 #define ASN1_GET_REQUEST 0xa0 /* Get-Request-PDU */
163 #define ASN1_GET_RESPONSE 0xa2 /* Get-Response-PDU */
170 typedef struct device_uri_s
/**** DeviceURI values ****/
172 regex_t re
; /* Regular expression to match */
173 cups_array_t
*uris
; /* URIs */
176 typedef struct snmp_cache_s
/**** SNMP scan cache ****/
178 http_addr_t address
; /* Address of device */
179 char *addrname
, /* Name of device */
180 *uri
, /* device-uri */
182 *make_and_model
; /* device-make-and-model */
185 typedef struct snmp_packet_s
/**** SNMP packet ****/
187 const char *error
; /* Encode/decode error */
188 int version
; /* Version number */
189 char community
[SNMP_MAX_STRING
];
191 int request_type
; /* Request type */
192 int request_id
; /* request-id value */
193 int error_status
; /* error-status value */
194 int error_index
; /* error-index value */
195 int object_name
[SNMP_MAX_OID
];
196 /* object-name value */
197 int object_type
; /* object-value type */
200 int boolean
; /* Boolean value */
201 int integer
; /* Integer value */
202 int oid
[SNMP_MAX_OID
]; /* OID value */
203 char string
[SNMP_MAX_STRING
];/* String value */
204 } object_value
; /* object-value value */
209 * Private CUPS API to set the last error...
212 extern void _cupsSetError(ipp_status_t status
, const char *message
);
219 static char *add_array(cups_array_t
*a
, const char *s
);
220 static void add_cache(http_addr_t
*addr
, const char *addrname
,
221 const char *uri
, const char *id
,
222 const char *make_and_model
);
223 static device_uri_t
*add_device_uri(char *value
);
224 static void alarm_handler(int sig
);
225 static int asn1_decode_snmp(unsigned char *buffer
, size_t len
,
226 snmp_packet_t
*packet
);
227 static void asn1_debug(unsigned char *buffer
, size_t len
,
229 static int asn1_encode_snmp(unsigned char *buffer
, size_t len
,
230 snmp_packet_t
*packet
);
231 static int asn1_get_integer(unsigned char **buffer
,
232 unsigned char *bufend
,
234 static int asn1_get_oid(unsigned char **buffer
,
235 unsigned char *bufend
,
236 int length
, int *oid
, int oidsize
);
237 static int asn1_get_packed(unsigned char **buffer
,
238 unsigned char *bufend
);
239 static char *asn1_get_string(unsigned char **buffer
,
240 unsigned char *bufend
,
241 int length
, char *string
,
243 static int asn1_get_length(unsigned char **buffer
,
244 unsigned char *bufend
);
245 static int asn1_get_type(unsigned char **buffer
,
246 unsigned char *bufend
);
247 static void asn1_set_integer(unsigned char **buffer
,
249 static void asn1_set_length(unsigned char **buffer
,
251 static void asn1_set_oid(unsigned char **buffer
,
253 static void asn1_set_packed(unsigned char **buffer
,
255 static int asn1_size_integer(int integer
);
256 static int asn1_size_length(int length
);
257 static int asn1_size_oid(const int *oid
);
258 static int asn1_size_packed(int integer
);
259 static int compare_cache(snmp_cache_t
*a
, snmp_cache_t
*b
);
260 static void debug_printf(const char *format
, ...);
261 static void fix_make_model(char *make_model
,
262 const char *old_make_model
,
263 int make_model_size
);
264 static void free_array(cups_array_t
*a
);
265 static void free_cache(void);
266 static http_addrlist_t
*get_interface_addresses(const char *ifname
);
267 static void hex_debug(unsigned char *buffer
, size_t len
);
268 static void list_device(snmp_cache_t
*cache
);
269 static int open_snmp_socket(void);
270 static const char *password_cb(const char *prompt
);
271 static void probe_device(snmp_cache_t
*device
);
272 static void read_snmp_conf(const char *address
);
273 static void read_snmp_response(int fd
);
274 static double run_time(void);
275 static void scan_devices(int fd
);
276 static void send_snmp_query(int fd
, http_addr_t
*addr
, int version
,
277 const char *community
,
278 const unsigned request_id
,
280 static int try_connect(http_addr_t
*addr
, const char *addrname
,
282 static void update_cache(snmp_cache_t
*device
, const char *uri
,
283 const char *id
, const char *make_model
);
290 static cups_array_t
*Addresses
= NULL
;
291 static cups_array_t
*Communities
= NULL
;
292 static cups_array_t
*Devices
= NULL
;
293 static int DebugLevel
= 0;
294 static int DeviceDescOID
[] = { 1, 3, 6, 1, 2, 1, 25, 3,
296 static unsigned DeviceDescRequest
;
297 static int DeviceTypeOID
[] = { 1, 3, 6, 1, 2, 1, 25, 3,
299 static unsigned DeviceTypeRequest
;
300 static cups_array_t
*DeviceURIs
= NULL
;
301 static int HostNameLookups
= 0;
302 static int MaxRunTime
= 10;
303 static struct timeval StartTime
;
307 * 'main()' - Discover printers via SNMP.
310 int /* O - Exit status */
311 main(int argc
, /* I - Number of command-line arguments (6 or 7) */
312 char *argv
[]) /* I - Command-line arguments */
314 int fd
; /* SNMP socket */
315 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
316 struct sigaction action
; /* Actions for POSIX signals */
317 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
321 * Check command-line options...
326 fputs(_("Usage: snmp [host-or-ip-address]\n"), stderr
);
331 * Set the password callback for IPP operations...
334 cupsSetPasswordCB(password_cb
);
337 * Catch SIGALRM signals...
341 sigset(SIGALRM
, alarm_handler
);
342 #elif defined(HAVE_SIGACTION)
343 memset(&action
, 0, sizeof(action
));
345 sigemptyset(&action
.sa_mask
);
346 sigaddset(&action
.sa_mask
, SIGALRM
);
347 action
.sa_handler
= alarm_handler
;
348 sigaction(SIGALRM
, &action
, NULL
);
350 signal(SIGALRM
, alarm_handler
);
351 #endif /* HAVE_SIGSET */
354 * Open the SNMP socket...
357 if ((fd
= open_snmp_socket()) < 0)
361 * Read the configuration file and any cache data...
364 read_snmp_conf(argv
[1]);
366 Devices
= cupsArrayNew((cups_array_func_t
)compare_cache
, NULL
);
369 * Scan for devices...
375 * Close, free, and return with no errors...
380 free_array(Addresses
);
381 free_array(Communities
);
389 * 'add_array()' - Add a string to an array.
392 static char * /* O - New string */
393 add_array(cups_array_t
*a
, /* I - Array */
394 const char *s
) /* I - String to add */
396 char *dups
; /* New string */
401 cupsArrayAdd(a
, dups
);
408 * 'add_cache()' - Add a cached device...
412 add_cache(http_addr_t
*addr
, /* I - Device IP address */
413 const char *addrname
, /* I - IP address or name string */
414 const char *uri
, /* I - Device URI */
415 const char *id
, /* I - 1284 device ID */
416 const char *make_and_model
) /* I - Make and model */
418 snmp_cache_t
*temp
; /* New device entry */
421 debug_printf("DEBUG: add_cache(addr=%p, addrname=\"%s\", uri=\"%s\", "
422 "id=\"%s\", make_and_model=\"%s\")\n",
423 addr
, addrname
, uri
? uri
: "(null)", id
? id
: "(null)",
424 make_and_model
? make_and_model
: "(null)");
426 temp
= calloc(1, sizeof(snmp_cache_t
));
427 memcpy(&(temp
->address
), addr
, sizeof(temp
->address
));
429 temp
->addrname
= strdup(addrname
);
432 temp
->uri
= strdup(uri
);
435 temp
->id
= strdup(id
);
438 temp
->make_and_model
= strdup(make_and_model
);
440 cupsArrayAdd(Devices
, temp
);
448 * 'add_device_uri()' - Add a device URI to the cache.
450 * The value string is modified (chopped up) as needed.
453 static device_uri_t
* /* O - Device URI */
454 add_device_uri(char *value
) /* I - Value from snmp.conf */
456 device_uri_t
*device_uri
; /* Device URI */
457 char *start
; /* Start of value */
461 * Allocate memory as needed...
465 DeviceURIs
= cupsArrayNew(NULL
, NULL
);
470 if ((device_uri
= calloc(1, sizeof(device_uri_t
))) == NULL
)
473 if ((device_uri
->uris
= cupsArrayNew(NULL
, NULL
)) == NULL
)
480 * Scan the value string for the regular expression and URI(s)...
483 value
++; /* Skip leading " */
485 for (start
= value
; *value
&& *value
!= '\"'; value
++)
486 if (*value
== '\\' && value
[1])
487 _cups_strcpy(value
, value
+ 1);
491 fputs("ERROR: Missing end quote for DeviceURI!\n", stderr
);
493 cupsArrayDelete(device_uri
->uris
);
501 if (regcomp(&(device_uri
->re
), start
, REG_EXTENDED
| REG_ICASE
))
503 fputs("ERROR: Bad regular expression for DeviceURI!\n", stderr
);
505 cupsArrayDelete(device_uri
->uris
);
513 while (isspace(*value
& 255))
519 for (start
= value
; *value
&& !isspace(*value
& 255); value
++);
524 cupsArrayAdd(device_uri
->uris
, strdup(start
));
528 * Add the device URI to the list and return it...
531 cupsArrayAdd(DeviceURIs
, device_uri
);
538 * 'alarm_handler()' - Handle alarm signals...
542 alarm_handler(int sig
) /* I - Signal number */
550 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
551 signal(SIGALRM
, alarm_handler
);
552 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
555 write(2, "DEBUG: ALARM!\n", 14);
560 * 'asn1_decode_snmp()' - Decode a SNMP packet.
563 static int /* O - 0 on success, -1 on error */
564 asn1_decode_snmp(unsigned char *buffer
, /* I - Buffer */
565 size_t len
, /* I - Size of buffer */
566 snmp_packet_t
*packet
) /* I - SNMP packet */
568 unsigned char *bufptr
, /* Pointer into the data */
569 *bufend
; /* End of data */
570 int length
; /* Length of value */
574 * Initialize the decoding...
577 memset(packet
, 0, sizeof(snmp_packet_t
));
580 bufend
= buffer
+ len
;
582 if (asn1_get_type(&bufptr
, bufend
) != ASN1_SEQUENCE
)
583 packet
->error
= "Packet does not start with SEQUENCE";
584 else if (asn1_get_length(&bufptr
, bufend
) == 0)
585 packet
->error
= "SEQUENCE uses indefinite length";
586 else if (asn1_get_type(&bufptr
, bufend
) != ASN1_INTEGER
)
587 packet
->error
= "No version number";
588 else if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0)
589 packet
->error
= "Version uses indefinite length";
590 else if ((packet
->version
= asn1_get_integer(&bufptr
, bufend
, length
))
592 packet
->error
= "Bad SNMP version number";
593 else if (asn1_get_type(&bufptr
, bufend
) != ASN1_OCTET_STRING
)
594 packet
->error
= "No community name";
595 else if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0)
596 packet
->error
= "Community name uses indefinite length";
599 asn1_get_string(&bufptr
, bufend
, length
, packet
->community
,
600 sizeof(packet
->community
));
602 if ((packet
->request_type
= asn1_get_type(&bufptr
, bufend
))
603 != ASN1_GET_RESPONSE
)
604 packet
->error
= "Packet does not contain a Get-Response-PDU";
605 else if (asn1_get_length(&bufptr
, bufend
) == 0)
606 packet
->error
= "Get-Response-PDU uses indefinite length";
607 else if (asn1_get_type(&bufptr
, bufend
) != ASN1_INTEGER
)
608 packet
->error
= "No request-id";
609 else if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0)
610 packet
->error
= "request-id uses indefinite length";
613 packet
->request_id
= asn1_get_integer(&bufptr
, bufend
, length
);
615 if (asn1_get_type(&bufptr
, bufend
) != ASN1_INTEGER
)
616 packet
->error
= "No error-status";
617 else if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0)
618 packet
->error
= "error-status uses indefinite length";
621 packet
->error_status
= asn1_get_integer(&bufptr
, bufend
, length
);
623 if (asn1_get_type(&bufptr
, bufend
) != ASN1_INTEGER
)
624 packet
->error
= "No error-index";
625 else if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0)
626 packet
->error
= "error-index uses indefinite length";
629 packet
->error_index
= asn1_get_integer(&bufptr
, bufend
, length
);
631 if (asn1_get_type(&bufptr
, bufend
) != ASN1_SEQUENCE
)
632 packet
->error
= "No variable-bindings SEQUENCE";
633 else if (asn1_get_length(&bufptr
, bufend
) == 0)
634 packet
->error
= "variable-bindings uses indefinite length";
635 else if (asn1_get_type(&bufptr
, bufend
) != ASN1_SEQUENCE
)
636 packet
->error
= "No VarBind SEQUENCE";
637 else if (asn1_get_length(&bufptr
, bufend
) == 0)
638 packet
->error
= "VarBind uses indefinite length";
639 else if (asn1_get_type(&bufptr
, bufend
) != ASN1_OID
)
640 packet
->error
= "No name OID";
641 else if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0)
642 packet
->error
= "Name OID uses indefinite length";
645 asn1_get_oid(&bufptr
, bufend
, length
, packet
->object_name
,
648 packet
->object_type
= asn1_get_type(&bufptr
, bufend
);
650 if ((length
= asn1_get_length(&bufptr
, bufend
)) == 0 &&
651 packet
->object_type
!= ASN1_NULL_VALUE
&&
652 packet
->object_type
!= ASN1_OCTET_STRING
)
653 packet
->error
= "Value uses indefinite length";
656 switch (packet
->object_type
)
659 packet
->object_value
.boolean
=
660 asn1_get_integer(&bufptr
, bufend
, length
);
664 packet
->object_value
.integer
=
665 asn1_get_integer(&bufptr
, bufend
, length
);
668 case ASN1_NULL_VALUE
:
671 case ASN1_OCTET_STRING
:
672 asn1_get_string(&bufptr
, bufend
, length
,
673 packet
->object_value
.string
,
678 asn1_get_oid(&bufptr
, bufend
, length
,
679 packet
->object_value
.oid
, SNMP_MAX_OID
);
683 packet
->error
= "Unsupported value type";
693 return (packet
->error
? -1 : 0);
698 * 'asn1_debug()' - Decode an ASN1-encoded message.
702 asn1_debug(unsigned char *buffer
, /* I - Buffer */
703 size_t len
, /* I - Length of buffer */
704 int indent
) /* I - Indentation */
706 int i
; /* Looping var */
707 unsigned char *bufend
; /* End of buffer */
708 int integer
; /* Number value */
709 int oid
[SNMP_MAX_OID
]; /* OID value */
710 char string
[SNMP_MAX_STRING
];/* String value */
711 unsigned char value_type
; /* Type of value */
712 int value_length
; /* Length of value */
715 bufend
= buffer
+ len
;
717 while (buffer
< bufend
)
723 value_type
= asn1_get_type(&buffer
, bufend
);
724 value_length
= asn1_get_length(&buffer
, bufend
);
729 integer
= asn1_get_integer(&buffer
, bufend
, value_length
);
731 fprintf(stderr
, "DEBUG: %*sBOOLEAN %d bytes %d\n", indent
, "",
732 value_length
, integer
);
736 integer
= asn1_get_integer(&buffer
, bufend
, value_length
);
738 fprintf(stderr
, "DEBUG: %*sINTEGER %d bytes %d\n", indent
, "",
739 value_length
, integer
);
742 case ASN1_OCTET_STRING
:
743 fprintf(stderr
, "DEBUG: %*sOCTET STRING %d bytes \"%s\"\n", indent
, "",
744 value_length
, asn1_get_string(&buffer
, bufend
,
745 value_length
, string
,
749 case ASN1_NULL_VALUE
:
750 fprintf(stderr
, "DEBUG: %*sNULL VALUE %d bytes\n", indent
, "",
753 buffer
+= value_length
;
757 asn1_get_oid(&buffer
, bufend
, value_length
, oid
, SNMP_MAX_OID
);
759 fprintf(stderr
, "DEBUG: %*sOID %d bytes ", indent
, "",
761 for (i
= 0; oid
[i
]; i
++)
762 fprintf(stderr
, ".%d", oid
[i
]);
767 fprintf(stderr
, "DEBUG: %*sSEQUENCE %d bytes\n", indent
, "",
769 asn1_debug(buffer
, value_length
, indent
+ 4);
771 buffer
+= value_length
;
774 case ASN1_GET_REQUEST
:
775 fprintf(stderr
, "DEBUG: %*sGet-Request-PDU %d bytes\n", indent
, "",
777 asn1_debug(buffer
, value_length
, indent
+ 4);
779 buffer
+= value_length
;
782 case ASN1_GET_RESPONSE
:
783 fprintf(stderr
, "DEBUG: %*sGet-Response-PDU %d bytes\n", indent
, "",
785 asn1_debug(buffer
, value_length
, indent
+ 4);
787 buffer
+= value_length
;
791 fprintf(stderr
, "DEBUG: %*sUNKNOWN(%x) %d bytes\n", indent
, "",
792 value_type
, value_length
);
794 buffer
+= value_length
;
802 * 'asn1_encode_snmp()' - Encode a SNMP packet.
805 static int /* O - Length on success, -1 on error */
806 asn1_encode_snmp(unsigned char *buffer
, /* I - Buffer */
807 size_t bufsize
, /* I - Size of buffer */
808 snmp_packet_t
*packet
) /* I - SNMP packet */
810 unsigned char *bufptr
; /* Pointer into buffer */
811 int total
, /* Total length */
812 msglen
, /* Length of entire message */
813 commlen
, /* Length of community string */
814 reqlen
, /* Length of request */
815 listlen
, /* Length of variable list */
816 varlen
, /* Length of variable */
817 namelen
, /* Length of object name OID */
818 valuelen
; /* Length of object value */
822 * Get the lengths of the community string, OID, and message...
825 namelen
= asn1_size_oid(packet
->object_name
);
827 switch (packet
->object_type
)
829 case ASN1_NULL_VALUE
:
834 valuelen
= asn1_size_integer(packet
->object_value
.boolean
);
838 valuelen
= asn1_size_integer(packet
->object_value
.integer
);
841 case ASN1_OCTET_STRING
:
842 valuelen
= strlen(packet
->object_value
.string
);
846 valuelen
= asn1_size_oid(packet
->object_value
.oid
);
850 packet
->error
= "Unknown object type";
854 varlen
= 1 + asn1_size_length(namelen
) + namelen
+
855 1 + asn1_size_length(valuelen
) + valuelen
;
856 listlen
= 1 + asn1_size_length(varlen
) + varlen
;
857 reqlen
= 2 + asn1_size_integer(packet
->request_id
) +
858 2 + asn1_size_integer(packet
->error_status
) +
859 2 + asn1_size_integer(packet
->error_index
) +
860 1 + asn1_size_length(listlen
) + listlen
;
861 commlen
= strlen(packet
->community
);
862 msglen
= 2 + asn1_size_integer(packet
->version
) +
863 1 + asn1_size_length(commlen
) + commlen
+
864 1 + asn1_size_length(reqlen
) + reqlen
;
865 total
= 1 + asn1_size_length(msglen
) + msglen
;
869 packet
->error
= "Message too large for buffer";
874 * Then format the message...
879 *bufptr
++ = ASN1_SEQUENCE
; /* SNMPv1 message header */
880 asn1_set_length(&bufptr
, msglen
);
882 asn1_set_integer(&bufptr
, packet
->version
);
885 *bufptr
++ = ASN1_OCTET_STRING
; /* community */
886 asn1_set_length(&bufptr
, commlen
);
887 memcpy(bufptr
, packet
->community
, commlen
);
890 *bufptr
++ = packet
->request_type
; /* Get-Request-PDU */
891 asn1_set_length(&bufptr
, reqlen
);
893 asn1_set_integer(&bufptr
, packet
->request_id
);
895 asn1_set_integer(&bufptr
, packet
->error_status
);
897 asn1_set_integer(&bufptr
, packet
->error_index
);
899 *bufptr
++ = ASN1_SEQUENCE
; /* variable-bindings */
900 asn1_set_length(&bufptr
, listlen
);
902 *bufptr
++ = ASN1_SEQUENCE
; /* variable */
903 asn1_set_length(&bufptr
, varlen
);
905 asn1_set_oid(&bufptr
, packet
->object_name
);
908 switch (packet
->object_type
)
910 case ASN1_NULL_VALUE
:
911 *bufptr
++ = ASN1_NULL_VALUE
; /* ObjectValue */
912 *bufptr
++ = 0; /* Length */
916 asn1_set_integer(&bufptr
, packet
->object_value
.boolean
);
920 asn1_set_integer(&bufptr
, packet
->object_value
.integer
);
923 case ASN1_OCTET_STRING
:
924 *bufptr
++ = ASN1_OCTET_STRING
;
925 asn1_set_length(&bufptr
, valuelen
);
926 memcpy(bufptr
, packet
->object_value
.string
, valuelen
);
931 asn1_set_oid(&bufptr
, packet
->object_value
.oid
);
935 return (bufptr
- buffer
);
940 * 'asn1_get_integer()' - Get an integer value.
943 static int /* O - Integer value */
945 unsigned char **buffer
, /* IO - Pointer in buffer */
946 unsigned char *bufend
, /* I - End of buffer */
947 int length
) /* I - Length of value */
949 int value
; /* Integer value */
953 length
> 0 && *buffer
< bufend
;
954 length
--, (*buffer
) ++)
955 value
= (value
<< 8) | **buffer
;
962 * 'asn1_get_length()' - Get a value length.
965 static int /* O - Length */
966 asn1_get_length(unsigned char **buffer
, /* IO - Pointer in buffer */
967 unsigned char *bufend
) /* I - End of buffer */
969 int length
; /* Length */
976 length
= asn1_get_integer(buffer
, bufend
, length
& 127);
983 * 'asn1_get_oid()' - Get an OID value.
986 static int /* O - Last OID number */
988 unsigned char **buffer
, /* IO - Pointer in buffer */
989 unsigned char *bufend
, /* I - End of buffer */
990 int length
, /* I - Length of value */
991 int *oid
, /* I - OID buffer */
992 int oidsize
) /* I - Size of OID buffer */
994 unsigned char *valend
; /* End of value */
995 int *oidend
; /* End of OID buffer */
996 int number
; /* OID number */
999 valend
= *buffer
+ length
;
1000 oidend
= oid
+ oidsize
- 1;
1002 if (valend
> bufend
)
1005 number
= asn1_get_packed(buffer
, bufend
);
1009 *oid
++ = number
/ 40;
1010 number
= number
% 40;
1020 while (*buffer
< valend
)
1022 number
= asn1_get_packed(buffer
, bufend
);
1035 * 'asn1_get_packed()' - Get a packed integer value.
1038 static int /* O - Value */
1040 unsigned char **buffer
, /* IO - Pointer in buffer */
1041 unsigned char *bufend
) /* I - End of buffer */
1043 int value
; /* Value */
1048 while ((**buffer
& 128) && *buffer
< bufend
)
1050 value
= (value
<< 7) | (**buffer
& 127);
1054 if (*buffer
< bufend
)
1056 value
= (value
<< 7) | **buffer
;
1065 * 'asn1_get_string()' - Get a string value.
1068 static char * /* O - String */
1070 unsigned char **buffer
, /* IO - Pointer in buffer */
1071 unsigned char *bufend
, /* I - End of buffer */
1072 int length
, /* I - Value length */
1073 char *string
, /* I - String buffer */
1074 int strsize
) /* I - String buffer size */
1076 if (length
< strsize
)
1078 memcpy(string
, *buffer
, length
);
1079 string
[length
] = '\0';
1083 memcpy(string
, buffer
, strsize
- 1);
1084 string
[strsize
- 1] = '\0';
1087 (*buffer
) += length
;
1094 * 'asn1_get_type()' - Get a value type.
1097 static int /* O - Type */
1098 asn1_get_type(unsigned char **buffer
, /* IO - Pointer in buffer */
1099 unsigned char *bufend
) /* I - End of buffer */
1101 int type
; /* Type */
1107 if ((type
& 31) == 31)
1108 type
= asn1_get_packed(buffer
, bufend
);
1115 * 'asn1_set_integer()' - Set an integer value.
1119 asn1_set_integer(unsigned char **buffer
,/* IO - Pointer in buffer */
1120 int integer
) /* I - Integer value */
1122 **buffer
= ASN1_INTEGER
;
1125 if (integer
> 0x7fffff || integer
< -0x800000)
1129 **buffer
= integer
>> 24;
1131 **buffer
= integer
>> 16;
1133 **buffer
= integer
>> 8;
1138 else if (integer
> 0x7fff || integer
< -0x8000)
1142 **buffer
= integer
>> 16;
1144 **buffer
= integer
>> 8;
1149 else if (integer
> 0x7f || integer
< -0x80)
1153 **buffer
= integer
>> 8;
1169 * 'asn1_set_length()' - Set a value length.
1173 asn1_set_length(unsigned char **buffer
, /* IO - Pointer in buffer */
1174 int length
) /* I - Length value */
1178 **buffer
= 0x82; /* 2-byte length */
1180 **buffer
= length
>> 8;
1185 else if (length
> 127)
1187 **buffer
= 0x81; /* 1-byte length */
1194 **buffer
= length
; /* Length */
1201 * 'asn1_set_oid()' - Set an OID value.
1205 asn1_set_oid(unsigned char **buffer
, /* IO - Pointer in buffer */
1206 const int *oid
) /* I - OID value */
1208 **buffer
= ASN1_OID
;
1211 asn1_set_length(buffer
, asn1_size_oid(oid
));
1213 asn1_set_packed(buffer
, oid
[0] * 40 + oid
[1]);
1215 for (oid
+= 2; *oid
; oid
++)
1216 asn1_set_packed(buffer
, *oid
);
1221 * 'asn1_set_packed()' - Set a packed integer value.
1225 asn1_set_packed(unsigned char **buffer
, /* IO - Pointer in buffer */
1226 int integer
) /* I - Integer value */
1228 if (integer
> 0xfffffff)
1230 **buffer
= (integer
>> 28) & 0x7f;
1234 if (integer
> 0x1fffff)
1236 **buffer
= (integer
>> 21) & 0x7f;
1240 if (integer
> 0x3fff)
1242 **buffer
= (integer
>> 14) & 0x7f;
1248 **buffer
= (integer
>> 7) & 0x7f;
1252 **buffer
= integer
& 0x7f;
1257 * 'asn1_size_integer()' - Figure out the number of bytes needed for an
1261 static int /* O - Size in bytes */
1262 asn1_size_integer(int integer
) /* I - Integer value */
1264 if (integer
> 0x7fffff || integer
< -0x800000)
1266 else if (integer
> 0x7fff || integer
< -0x8000)
1268 else if (integer
> 0x7f || integer
< -0x80)
1276 * 'asn1_size_length()' - Figure out the number of bytes needed for a
1280 static int /* O - Size in bytes */
1281 asn1_size_length(int length
) /* I - Length value */
1285 else if (length
> 0x7f)
1293 * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an
1297 static int /* O - Size in bytes */
1298 asn1_size_oid(const int *oid
) /* I - OID value */
1300 int length
; /* Length of value */
1303 for (length
= asn1_size_packed(oid
[0] * 40 + oid
[1]), oid
+= 2; *oid
; oid
++)
1304 length
+= asn1_size_packed(*oid
);
1311 * 'asn1_size_packed()' - Figure out the number of bytes needed for a
1312 * packed integer value.
1315 static int /* O - Size in bytes */
1316 asn1_size_packed(int integer
) /* I - Integer value */
1318 if (integer
> 0xfffffff)
1320 else if (integer
> 0x1fffff)
1322 else if (integer
> 0x3fff)
1324 else if (integer
> 0x7f)
1332 * 'compare_cache()' - Compare two cache entries.
1335 static int /* O - Result of comparison */
1336 compare_cache(snmp_cache_t
*a
, /* I - First cache entry */
1337 snmp_cache_t
*b
) /* I - Second cache entry */
1339 return (strcasecmp(a
->addrname
, b
->addrname
));
1344 * 'debug_printf()' - Display some debugging information.
1348 debug_printf(const char *format
, /* I - Printf-style format string */
1349 ...) /* I - Additional arguments as needed */
1351 va_list ap
; /* Pointer to arguments */
1357 va_start(ap
, format
);
1358 vfprintf(stderr
, format
, ap
);
1364 * 'fix_make_model()' - Fix common problems in the make-and-model string.
1369 char *make_model
, /* I - New make-and-model string */
1370 const char *old_make_model
, /* I - Old make-and-model string */
1371 int make_model_size
) /* I - Size of new string buffer */
1373 char *mmptr
; /* Pointer into make-and-model string */
1377 * Fix some common problems with the make-and-model string so
1378 * that printer driver detection works better...
1381 if (!strncasecmp(old_make_model
, "Hewlett-Packard", 15))
1384 * Strip leading Hewlett-Packard and hp prefixes and replace
1385 * with a single HP manufacturer prefix...
1388 mmptr
= (char *)old_make_model
+ 15;
1390 while (isspace(*mmptr
& 255))
1393 if (!strncasecmp(mmptr
, "hp", 2))
1397 while (isspace(*mmptr
& 255))
1401 make_model
[0] = 'H';
1402 make_model
[1] = 'P';
1403 make_model
[2] = ' ';
1404 strlcpy(make_model
+ 3, mmptr
, make_model_size
- 3);
1406 else if (!strncasecmp(old_make_model
, "deskjet", 7))
1407 snprintf(make_model
, make_model_size
, "HP DeskJet%s", old_make_model
+ 7);
1408 else if (!strncasecmp(old_make_model
, "officejet", 9))
1409 snprintf(make_model
, make_model_size
, "HP OfficeJet%s", old_make_model
+ 9);
1410 else if (!strncasecmp(old_make_model
, "stylus_pro_", 11))
1411 snprintf(make_model
, make_model_size
, "EPSON Stylus Pro %s",
1412 old_make_model
+ 11);
1414 strlcpy(make_model
, old_make_model
, make_model_size
);
1416 if ((mmptr
= strstr(make_model
, ", Inc.,")) != NULL
)
1419 * Strip inc. from name, e.g. "Tektronix, Inc., Phaser 560"
1420 * becomes "Tektronix Phaser 560"...
1423 _cups_strcpy(mmptr
, mmptr
+ 7);
1426 if ((mmptr
= strstr(make_model
, " Network")) != NULL
)
1429 * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
1430 * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
1436 if ((mmptr
= strchr(make_model
, ',')) != NULL
)
1439 * Drop anything after a trailing comma...
1448 * 'free_array()' - Free an array of strings.
1452 free_array(cups_array_t
*a
) /* I - Array */
1454 char *s
; /* Current string */
1457 for (s
= (char *)cupsArrayFirst(a
); s
; s
= (char *)cupsArrayNext(a
))
1465 * 'free_cache()' - Free the array of cached devices.
1471 snmp_cache_t
*cache
; /* Cached device */
1474 for (cache
= (snmp_cache_t
*)cupsArrayFirst(Devices
);
1476 cache
= (snmp_cache_t
*)cupsArrayNext(Devices
))
1478 free(cache
->addrname
);
1486 if (cache
->make_and_model
)
1487 free(cache
->make_and_model
);
1492 cupsArrayDelete(Devices
);
1498 * 'get_interface_addresses()' - Get the broadcast address(es) associated
1499 * with an interface.
1502 static http_addrlist_t
* /* O - List of addresses */
1503 get_interface_addresses(
1504 const char *ifname
) /* I - Interface name */
1506 struct ifaddrs
*addrs
, /* Interface address list */
1507 *addr
; /* Current interface address */
1508 http_addrlist_t
*first
, /* First address in list */
1509 *last
, /* Last address in list */
1510 *current
; /* Current address */
1513 if (getifaddrs(&addrs
) < 0)
1516 for (addr
= addrs
, first
= NULL
, last
= NULL
; addr
; addr
= addr
->ifa_next
)
1517 if ((addr
->ifa_flags
& IFF_BROADCAST
) && addr
->ifa_broadaddr
&&
1518 addr
->ifa_broadaddr
->sa_family
== AF_INET
&&
1519 (!ifname
|| !strcmp(ifname
, addr
->ifa_name
)))
1521 current
= calloc(1, sizeof(http_addrlist_t
));
1523 memcpy(&(current
->addr
), addr
->ifa_broadaddr
,
1524 sizeof(struct sockaddr_in
));
1529 last
->next
= current
;
1541 * 'hex_debug()' - Output hex debugging data...
1545 hex_debug(unsigned char *buffer
, /* I - Buffer */
1546 size_t len
) /* I - Number of bytes */
1548 int col
; /* Current column */
1551 fputs("DEBUG: Hex dump of packet:\n", stderr
);
1553 for (col
= 0; len
> 0; col
++, buffer
++, len
--)
1555 if ((col
& 15) == 0)
1556 fprintf(stderr
, "DEBUG: %04X ", col
);
1558 fprintf(stderr
, " %02X", *buffer
);
1560 if ((col
& 15) == 15)
1570 * 'list_device()' - List a device we found...
1574 list_device(snmp_cache_t
*cache
) /* I - Cached device */
1577 printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
1579 cache
->make_and_model
? cache
->make_and_model
: "Unknown",
1580 cache
->make_and_model
? cache
->make_and_model
: "Unknown",
1581 cache
->addrname
, cache
->id
? cache
->id
: "");
1586 * 'open_snmp_socket()' - Open the SNMP broadcast socket.
1589 static int /* O - SNMP socket file descriptor */
1590 open_snmp_socket(void)
1592 int fd
; /* SNMP socket file descriptor */
1593 int val
; /* Socket option value */
1597 * Create the SNMP socket...
1600 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
1602 fprintf(stderr
, "ERROR: Unable to create SNMP socket - %s\n",
1609 * Set the "broadcast" flag...
1614 if (setsockopt(fd
, SOL_SOCKET
, SO_BROADCAST
, &val
, sizeof(val
)))
1616 fprintf(stderr
, "ERROR: Unable to set broadcast mode - %s\n",
1629 * 'password_cb()' - Handle authentication requests.
1631 * All we do right now is return NULL, indicating that no authentication
1635 static const char * /* O - Password (NULL) */
1636 password_cb(const char *prompt
) /* I - Prompt message */
1638 (void)prompt
; /* Anti-compiler-warning-code */
1645 * 'probe_device()' - Probe a device to discover whether it is a printer.
1647 * TODO: Try using the Port Monitor MIB to discover the correct protocol
1648 * to use - first need a commercially-available printer that supports
1653 probe_device(snmp_cache_t
*device
) /* I - Device */
1655 char uri
[1024], /* Full device URI */
1656 *uriptr
, /* Pointer into URI */
1657 *format
; /* Format string for device */
1658 device_uri_t
*device_uri
; /* Current DeviceURI match */
1661 debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device
->addrname
);
1665 * TODO: Try an mDNS query first, and then fallback on direct probes...
1668 if (!try_connect(&(device
->address
), device
->addrname
, 5353))
1670 debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device
->addrname
);
1673 #endif /* __APPLE__ */
1676 * Lookup the device in the match table...
1679 for (device_uri
= (device_uri_t
*)cupsArrayFirst(DeviceURIs
);
1681 device_uri
= (device_uri_t
*)cupsArrayNext(DeviceURIs
))
1682 if (!regexec(&(device_uri
->re
), device
->make_and_model
, 0, NULL
, 0))
1685 * Found a match, add the URIs...
1688 for (format
= (char *)cupsArrayFirst(device_uri
->uris
);
1690 format
= (char *)cupsArrayNext(device_uri
->uris
))
1692 for (uriptr
= uri
; *format
&& uriptr
< (uri
+ sizeof(uri
) - 1);)
1693 if (*format
== '%' && format
[1] == 's')
1696 * Insert hostname/address...
1699 strlcpy(uriptr
, device
->addrname
, sizeof(uri
) - (uriptr
- uri
));
1700 uriptr
+= strlen(uriptr
);
1704 *uriptr
++ = *format
++;
1708 update_cache(device
, uri
, NULL
, NULL
);
1715 * Then try the standard ports...
1718 if (!try_connect(&(device
->address
), device
->addrname
, 9100))
1720 debug_printf("DEBUG: %s supports AppSocket!\n", device
->addrname
);
1722 snprintf(uri
, sizeof(uri
), "socket://%s", device
->addrname
);
1723 update_cache(device
, uri
, NULL
, NULL
);
1725 else if (!try_connect(&(device
->address
), device
->addrname
, 515))
1727 debug_printf("DEBUG: %s supports LPD!\n", device
->addrname
);
1729 snprintf(uri
, sizeof(uri
), "lpd://%s/", device
->addrname
);
1730 update_cache(device
, uri
, NULL
, NULL
);
1736 * 'read_snmp_conf()' - Read the snmp.conf file.
1740 read_snmp_conf(const char *address
) /* I - Single address to probe */
1742 cups_file_t
*fp
; /* File pointer */
1743 char filename
[1024], /* Filename */
1744 line
[1024], /* Line from file */
1745 *value
; /* Value on line */
1746 int linenum
; /* Line number */
1747 const char *cups_serverroot
; /* CUPS_SERVERROOT env var */
1748 const char *debug
; /* CUPS_DEBUG_LEVEL env var */
1749 const char *runtime
; /* CUPS_MAX_RUN_TIME env var */
1753 * Initialize the global address and community lists...
1756 Addresses
= cupsArrayNew(NULL
, NULL
);
1757 Communities
= cupsArrayNew(NULL
, NULL
);
1760 add_array(Addresses
, address
);
1762 if ((debug
= getenv("CUPS_DEBUG_LEVEL")) != NULL
)
1763 DebugLevel
= atoi(debug
);
1765 if ((runtime
= getenv("CUPS_MAX_RUN_TIME")) != NULL
)
1766 MaxRunTime
= atoi(runtime
);
1769 * Find the snmp.conf file...
1772 if ((cups_serverroot
= getenv("CUPS_SERVERROOT")) == NULL
)
1773 cups_serverroot
= CUPS_SERVERROOT
;
1775 snprintf(filename
, sizeof(filename
), "%s/snmp.conf", cups_serverroot
);
1777 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
1780 * Read the snmp.conf file...
1785 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
1788 fprintf(stderr
, "ERROR: Missing value on line %d of %s!\n", linenum
,
1790 else if (!strcasecmp(line
, "Address"))
1793 add_array(Addresses
, value
);
1795 else if (!strcasecmp(line
, "Community"))
1796 add_array(Communities
, value
);
1797 else if (!strcasecmp(line
, "DebugLevel"))
1798 DebugLevel
= atoi(value
);
1799 else if (!strcasecmp(line
, "DeviceURI"))
1803 "ERROR: Missing double quote for regular expression on "
1804 "line %d of %s!\n", linenum
, filename
);
1806 add_device_uri(value
);
1808 else if (!strcasecmp(line
, "HostNameLookups"))
1809 HostNameLookups
= !strcasecmp(value
, "on") ||
1810 !strcasecmp(value
, "yes") ||
1811 !strcasecmp(value
, "true") ||
1812 !strcasecmp(value
, "double");
1813 else if (!strcasecmp(line
, "MaxRunTime"))
1814 MaxRunTime
= atoi(value
);
1816 fprintf(stderr
, "ERROR: Unknown directive %s on line %d of %s!\n",
1817 line
, linenum
, filename
);
1824 * Use defaults if parameters are undefined...
1827 if (cupsArrayCount(Addresses
) == 0)
1829 fputs("INFO: Using default SNMP Address @LOCAL\n", stderr
);
1830 add_array(Addresses
, "@LOCAL");
1833 if (cupsArrayCount(Communities
) == 0)
1835 fputs("INFO: Using default SNMP Community public\n", stderr
);
1836 add_array(Communities
, "public");
1842 * 'read_snmp_response()' - Read and parse a SNMP response...
1846 read_snmp_response(int fd
) /* I - SNMP socket file descriptor */
1848 unsigned char buffer
[SNMP_MAX_PACKET
];/* Data packet */
1849 int bytes
; /* Number of bytes received */
1850 http_addr_t addr
; /* Source address */
1851 socklen_t addrlen
; /* Source address length */
1852 char addrname
[256]; /* Source address name */
1853 snmp_packet_t packet
; /* Decoded packet */
1854 snmp_cache_t key
, /* Search key */
1855 *device
; /* Matching device */
1859 * Read the response data...
1862 addrlen
= sizeof(addr
);
1864 if ((bytes
= recvfrom(fd
, buffer
, sizeof(buffer
), 0, (void *)&addr
,
1867 fprintf(stderr
, "ERROR: Unable to read data from socket: %s\n",
1872 if (HostNameLookups
)
1873 httpAddrLookup(&addr
, addrname
, sizeof(addrname
));
1875 httpAddrString(&addr
, addrname
, sizeof(addrname
));
1877 debug_printf("DEBUG: %.3f Received %d bytes from %s...\n", run_time(),
1881 * Look for the response status code in the SNMP message header...
1884 if (asn1_decode_snmp(buffer
, bytes
, &packet
))
1886 fprintf(stderr
, "ERROR: Bad SNMP packet from %s: %s\n",
1887 addrname
, packet
.error
);
1889 asn1_debug(buffer
, bytes
, 0);
1890 hex_debug(buffer
, bytes
);
1895 debug_printf("DEBUG: community=\"%s\"\n", packet
.community
);
1896 debug_printf("DEBUG: request-id=%d\n", packet
.request_id
);
1897 debug_printf("DEBUG: error-status=%d\n", packet
.error_status
);
1900 asn1_debug(buffer
, bytes
, 0);
1903 hex_debug(buffer
, bytes
);
1905 if (packet
.error_status
)
1909 * Find a matching device in the cache...
1912 key
.addrname
= addrname
;
1913 device
= (snmp_cache_t
*)cupsArrayFind(Devices
, &key
);
1916 * Process the message...
1919 if (packet
.request_id
== DeviceTypeRequest
)
1922 * Got the device type response...
1927 debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
1933 * Add the device and request the device description...
1936 add_cache(&addr
, addrname
, NULL
, NULL
, NULL
);
1938 send_snmp_query(fd
, &addr
, SNMP_VERSION_1
, packet
.community
,
1939 DeviceDescRequest
, DeviceDescOID
);
1941 else if (packet
.request_id
== DeviceDescRequest
&&
1942 packet
.object_type
== ASN1_OCTET_STRING
)
1945 * Update an existing cache entry...
1948 char make_model
[256]; /* Make and model */
1953 debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
1959 * Convert the description to a make and model string...
1962 if (strchr(packet
.object_value
.string
, ':') &&
1963 strchr(packet
.object_value
.string
, ';'))
1966 * Description is the IEEE-1284 device ID...
1969 backendGetMakeModel(packet
.object_value
.string
, make_model
,
1970 sizeof(make_model
));
1975 * Description is plain text...
1978 fix_make_model(make_model
, packet
.object_value
.string
,
1979 sizeof(make_model
));
1982 if (device
->make_and_model
)
1983 free(device
->make_and_model
);
1985 device
->make_and_model
= strdup(make_model
);
1991 * 'run_time()' - Return the total running time...
1994 static double /* O - Number of seconds */
1997 struct timeval curtime
; /* Current time */
2000 gettimeofday(&curtime
, NULL
);
2002 return (curtime
.tv_sec
- StartTime
.tv_sec
+
2003 0.000001 * (curtime
.tv_usec
- StartTime
.tv_usec
));
2008 * 'scan_devices()' - Scan for devices using SNMP.
2012 scan_devices(int fd
) /* I - SNMP socket */
2014 char *address
, /* Current address */
2015 *community
; /* Current community */
2016 fd_set input
; /* Input set for select() */
2017 struct timeval timeout
; /* Timeout for select() */
2018 time_t endtime
; /* End time for scan */
2019 http_addrlist_t
*addrs
, /* List of addresses */
2020 *addr
; /* Current address */
2021 snmp_cache_t
*device
; /* Current device */
2025 * Setup the request IDs...
2028 gettimeofday(&StartTime
, NULL
);
2030 DeviceTypeRequest
= StartTime
.tv_sec
;
2031 DeviceDescRequest
= StartTime
.tv_sec
+ 1;
2034 * First send all of the broadcast queries...
2037 for (address
= (char *)cupsArrayFirst(Addresses
);
2039 address
= (char *)cupsArrayNext(Addresses
))
2041 if (!strcmp(address
, "@LOCAL"))
2042 addrs
= get_interface_addresses(NULL
);
2043 else if (!strncmp(address
, "@IF(", 4))
2045 char ifname
[255]; /* Interface name */
2048 strlcpy(ifname
, address
+ 4, sizeof(ifname
));
2050 ifname
[strlen(ifname
) - 1] = '\0';
2052 addrs
= get_interface_addresses(ifname
);
2055 addrs
= httpAddrGetList(address
, AF_INET
, NULL
);
2059 fprintf(stderr
, "ERROR: Unable to scan \"%s\"!\n", address
);
2063 for (community
= (char *)cupsArrayFirst(Communities
);
2065 community
= (char *)cupsArrayNext(Communities
))
2067 debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n",
2068 community
, address
);
2070 for (addr
= addrs
; addr
; addr
= addr
->next
)
2071 send_snmp_query(fd
, &(addr
->addr
), SNMP_VERSION_1
, community
,
2072 DeviceTypeRequest
, DeviceTypeOID
);
2075 httpAddrFreeList(addrs
);
2079 * Then read any responses that come in over the next 3 seconds...
2082 endtime
= time(NULL
) + 3;
2086 while (time(NULL
) < endtime
)
2089 timeout
.tv_usec
= 0;
2092 if (select(fd
+ 1, &input
, NULL
, NULL
, &timeout
) < 0)
2094 fprintf(stderr
, "ERROR: %.3f select() for %d failed: %s\n", run_time(),
2095 fd
, strerror(errno
));
2099 if (FD_ISSET(fd
, &input
))
2100 read_snmp_response(fd
);
2106 * Finally, probe all of the printers we discovered to see how they are
2110 for (device
= (snmp_cache_t
*)cupsArrayFirst(Devices
);
2112 device
= (snmp_cache_t
*)cupsArrayNext(Devices
))
2113 if (MaxRunTime
> 0 && run_time() >= MaxRunTime
)
2115 else if (!device
->uri
)
2116 probe_device(device
);
2118 debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
2123 * 'send_snmp_query()' - Send an SNMP query packet.
2128 int fd
, /* I - SNMP socket */
2129 http_addr_t
*addr
, /* I - Address to send to */
2130 int version
, /* I - SNMP version */
2131 const char *community
, /* I - Community name */
2132 const unsigned request_id
, /* I - Request ID */
2133 const int *oid
) /* I - OID */
2135 int i
; /* Looping var */
2136 snmp_packet_t packet
; /* SNMP message packet */
2137 unsigned char buffer
[SNMP_MAX_PACKET
];/* SNMP message buffer */
2138 int bytes
; /* Size of message */
2139 char addrname
[32]; /* Address name */
2143 * Create the SNMP message...
2146 memset(&packet
, 0, sizeof(packet
));
2148 packet
.version
= version
;
2149 packet
.request_type
= ASN1_GET_REQUEST
;
2150 packet
.request_id
= request_id
;
2151 packet
.object_type
= ASN1_NULL_VALUE
;
2153 strlcpy(packet
.community
, community
, sizeof(packet
.community
));
2155 for (i
= 0; oid
[i
]; i
++)
2156 packet
.object_name
[i
] = oid
[i
];
2158 bytes
= asn1_encode_snmp(buffer
, sizeof(buffer
), &packet
);
2162 fprintf(stderr
, "ERROR: Unable to send SNMP query: %s\n",
2168 * Send the message...
2171 debug_printf("DEBUG: %.3f Sending %d bytes to %s...\n", run_time(),
2172 bytes
, httpAddrString(addr
, addrname
, sizeof(addrname
)));
2174 asn1_debug(buffer
, bytes
, 0);
2176 hex_debug(buffer
, bytes
);
2178 addr
->ipv4
.sin_port
= htons(SNMP_PORT
);
2180 if (sendto(fd
, buffer
, bytes
, 0, (void *)addr
, sizeof(addr
->ipv4
)) < bytes
)
2181 fprintf(stderr
, "ERROR: Unable to send %d bytes to %s: %s\n",
2182 bytes
, addrname
, strerror(errno
));
2187 * 'try_connect()' - Try connecting on a port...
2190 static int /* O - 0 on success or -1 on error */
2191 try_connect(http_addr_t
*addr
, /* I - Socket address */
2192 const char *addrname
, /* I - Hostname or IP address */
2193 int port
) /* I - Port number */
2195 int fd
; /* Socket */
2196 int status
; /* Connection status */
2199 debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(),
2200 port
== 515 ? "lpd" : "socket", addrname
, port
);
2202 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
2204 fprintf(stderr
, "ERROR: Unable to create socket: %s\n",
2209 addr
->ipv4
.sin_port
= htons(port
);
2213 status
= connect(fd
, (void *)addr
, httpAddrLength(addr
));
2223 * 'update_cache()' - Update a cached device...
2227 update_cache(snmp_cache_t
*device
, /* I - Device */
2228 const char *uri
, /* I - Device URI */
2229 const char *id
, /* I - Device ID */
2230 const char *make_model
) /* I - Device make and model */
2235 device
->uri
= strdup(uri
);
2242 device
->id
= strdup(id
);
2247 if (device
->make_and_model
)
2248 free(device
->make_and_model
);
2250 device
->make_and_model
= strdup(make_model
);
2253 list_device(device
);
2258 * End of "$Id: snmp.c 6495 2007-04-30 21:23:04Z mike $".