]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / snmp.c
1 /*
2 * "$Id: snmp.c 6180 2007-01-03 18:19:32Z mike $"
3 *
4 * SNMP discovery backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2006 by Easy Software Products, all rights reserved.
7 *
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
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Discover printers via SNMP.
29 * add_array() - Add a string to an array.
30 * add_cache() - Add a cached device...
31 * alarm_handler() - Handle alarm signals...
32 * asn1_decode_snmp() - Decode a SNMP packet.
33 * asn1_debug() - Decode an ASN1-encoded message.
34 * asn1_encode_snmp() - Encode a SNMP packet.
35 * asn1_get_integer() - Get an integer value.
36 * asn1_get_length() - Get a value length.
37 * asn1_get_oid() - Get an OID value.
38 * asn1_get_packed() - Get a packed integer value.
39 * asn1_get_string() - Get a string value.
40 * asn1_get_type() - Get a value type.
41 * asn1_set_integer() - Set an integer value.
42 * asn1_set_length() - Set a value length.
43 * asn1_set_oid() - Set an OID value.
44 * asn1_set_packed() - Set a packed integer value.
45 * asn1_size_integer() - Figure out the number of bytes needed for an
46 * integer value.
47 * asn1_size_length() - Figure out the number of bytes needed for a
48 * length value.
49 * asn1_size_oid() - Figure out the numebr of bytes needed for an
50 * OID value.
51 * asn1_size_packed() - Figure out the number of bytes needed for a
52 * packed integer value.
53 * compare_cache() - Compare two cache entries.
54 * debug_printf() - Display some debugging information.
55 * do_request() - Do a non-blocking IPP request.
56 * fix_make_model() - Fix common problems in the make-and-model
57 * string.
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
61 * with an interface.
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
67 * printer.
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...
75 */
76
77 /*
78 * Include necessary headers.
79 */
80
81 #include <cups/http-private.h>
82 #include "backend-private.h"
83 #include <cups/array.h>
84 #include <cups/file.h>
85
86
87 /*
88 * This backend implements SNMP printer discovery. It uses a broadcast-
89 * based approach to get SNMP response packets from potential printers
90 * and then interrogates each responder by trying to connect on port
91 * 631, 9100, and 515.
92 *
93 * The current focus is on printers with internal network cards, although
94 * the code also works with many external print servers as well. Future
95 * versions will support scanning for vendor-specific SNMP OIDs and the
96 * new PWG Port Monitor MIB and not just the Host MIB OIDs.
97 *
98 * The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
99 * which can contain comments, blank lines, or any number of the following
100 * directives:
101 *
102 * Address ip-address
103 * Address @LOCAL
104 * Address @IF(name)
105 * Community name
106 * DebugLevel N
107 * HostNameLookups on
108 * HostNameLookups off
109 *
110 * The default is to use:
111 *
112 * Address @LOCAL
113 * Community public
114 * DebugLevel 0
115 * HostNameLookups off
116 *
117 * This backend is known to work with the following network printers and
118 * print servers:
119 *
120 * Axis OfficeBasic, 5400, 5600
121 * EPSON
122 * Genicom
123 * HP JetDirect
124 * Lexmark
125 * Sharp
126 * Tektronix
127 * Xerox
128 *
129 * It does not currently work with:
130 *
131 * DLink
132 * Linksys
133 * Netgear
134 * Okidata
135 *
136 * (for all of these, they do not support the Host MIB)
137 */
138
139 /*
140 * Constants...
141 */
142
143 #define SNMP_PORT 161 /* SNMP well-known port */
144 #define SNMP_MAX_OID 64 /* Maximum number of OID numbers */
145 #define SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */
146 #define SNMP_MAX_STRING 512 /* Maximum size of string */
147 #define SNMP_VERSION_1 0 /* SNMPv1 */
148
149 #define ASN1_END_OF_CONTENTS 0x00 /* End-of-contents */
150 #define ASN1_BOOLEAN 0x01 /* BOOLEAN */
151 #define ASN1_INTEGER 0x02 /* INTEGER or ENUMERATION */
152 #define ASN1_BIT_STRING 0x03 /* BIT STRING */
153 #define ASN1_OCTET_STRING 0x04 /* OCTET STRING */
154 #define ASN1_NULL_VALUE 0x05 /* NULL VALUE */
155 #define ASN1_OID 0x06 /* OBJECT IDENTIFIER */
156 #define ASN1_SEQUENCE 0x30 /* SEQUENCE */
157 #define ASN1_GET_REQUEST 0xa0 /* Get-Request-PDU */
158 #define ASN1_GET_RESPONSE 0xa2 /* Get-Response-PDU */
159
160
161 /*
162 * Types...
163 */
164
165 typedef struct snmp_cache_s /**** SNMP scan cache ****/
166 {
167 http_addr_t address; /* Address of device */
168 char *addrname, /* Name of device */
169 *uri, /* device-uri */
170 *id, /* device-id */
171 *make_and_model; /* device-make-and-model */
172 } snmp_cache_t;
173
174 typedef struct snmp_packet_s /**** SNMP packet ****/
175 {
176 const char *error; /* Encode/decode error */
177 int version; /* Version number */
178 char community[SNMP_MAX_STRING];
179 /* Community name */
180 int request_type; /* Request type */
181 int request_id; /* request-id value */
182 int error_status; /* error-status value */
183 int error_index; /* error-index value */
184 int object_name[SNMP_MAX_OID];
185 /* object-name value */
186 int object_type; /* object-value type */
187 union
188 {
189 int boolean; /* Boolean value */
190 int integer; /* Integer value */
191 int oid[SNMP_MAX_OID]; /* OID value */
192 char string[SNMP_MAX_STRING];/* String value */
193 } object_value; /* object-value value */
194 } snmp_packet_t;
195
196
197 /*
198 * Private CUPS API to set the last error...
199 */
200
201 extern void _cupsSetError(ipp_status_t status, const char *message);
202
203
204 /*
205 * Local functions...
206 */
207
208 static char *add_array(cups_array_t *a, const char *s);
209 static void add_cache(http_addr_t *addr, const char *addrname,
210 const char *uri, const char *id,
211 const char *make_and_model);
212 static void alarm_handler(int sig);
213 static int asn1_decode_snmp(unsigned char *buffer, size_t len,
214 snmp_packet_t *packet);
215 static void asn1_debug(unsigned char *buffer, size_t len,
216 int indent);
217 static int asn1_encode_snmp(unsigned char *buffer, size_t len,
218 snmp_packet_t *packet);
219 static int asn1_get_integer(unsigned char **buffer,
220 unsigned char *bufend,
221 int length);
222 static int asn1_get_oid(unsigned char **buffer,
223 unsigned char *bufend,
224 int length, int *oid, int oidsize);
225 static int asn1_get_packed(unsigned char **buffer,
226 unsigned char *bufend);
227 static char *asn1_get_string(unsigned char **buffer,
228 unsigned char *bufend,
229 int length, char *string,
230 int strsize);
231 static int asn1_get_length(unsigned char **buffer,
232 unsigned char *bufend);
233 static int asn1_get_type(unsigned char **buffer,
234 unsigned char *bufend);
235 static void asn1_set_integer(unsigned char **buffer,
236 int integer);
237 static void asn1_set_length(unsigned char **buffer,
238 int length);
239 static void asn1_set_oid(unsigned char **buffer,
240 const int *oid);
241 static void asn1_set_packed(unsigned char **buffer,
242 int integer);
243 static int asn1_size_integer(int integer);
244 static int asn1_size_length(int length);
245 static int asn1_size_oid(const int *oid);
246 static int asn1_size_packed(int integer);
247 static int compare_cache(snmp_cache_t *a, snmp_cache_t *b);
248 static void debug_printf(const char *format, ...);
249 static ipp_t *do_request(http_t *http, ipp_t *request,
250 const char *resource);
251 static void fix_make_model(char *make_model,
252 const char *old_make_model,
253 int make_model_size);
254 static void free_array(cups_array_t *a);
255 static void free_cache(void);
256 static http_addrlist_t *get_interface_addresses(const char *ifname);
257 static void hex_debug(unsigned char *buffer, size_t len);
258 static void list_device(snmp_cache_t *cache);
259 static int open_snmp_socket(void);
260 static const char *password_cb(const char *prompt);
261 static void probe_device(snmp_cache_t *device);
262 static void read_snmp_conf(const char *address);
263 static void read_snmp_response(int fd);
264 static double run_time(void);
265 static void scan_devices(int fd);
266 static void send_snmp_query(int fd, http_addr_t *addr, int version,
267 const char *community,
268 const unsigned request_id,
269 const int *oid);
270 static int try_connect(http_addr_t *addr, const char *addrname,
271 int port);
272 static void update_cache(snmp_cache_t *device, const char *uri,
273 const char *id, const char *make_model);
274
275
276 /*
277 * Local globals...
278 */
279
280 static cups_array_t *Addresses = NULL;
281 static cups_array_t *Communities = NULL;
282 static cups_array_t *Devices = NULL;
283 static int DebugLevel = 0;
284 static int DeviceTypeOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
285 2, 1, 2, 1, 0 };
286 static int DeviceDescOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
287 2, 1, 3, 1, 0 };
288 static unsigned DeviceTypeRequest;
289 static unsigned DeviceDescRequest;
290 static int HostNameLookups = 0;
291 static int MaxRunTime = 10;
292 static struct timeval StartTime;
293
294
295 /*
296 * 'main()' - Discover printers via SNMP.
297 */
298
299 int /* O - Exit status */
300 main(int argc, /* I - Number of command-line arguments (6 or 7) */
301 char *argv[]) /* I - Command-line arguments */
302 {
303 int fd; /* SNMP socket */
304 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
305 struct sigaction action; /* Actions for POSIX signals */
306 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
307
308
309 /*
310 * Check command-line options...
311 */
312
313 if (argc > 2)
314 {
315 fputs("Usage: snmp [host-or-ip-address]\n", stderr);
316 return (1);
317 }
318
319 /*
320 * Set the password callback for IPP operations...
321 */
322
323 cupsSetPasswordCB(password_cb);
324
325 /*
326 * Catch SIGALRM signals...
327 */
328
329 #ifdef HAVE_SIGSET
330 sigset(SIGALRM, alarm_handler);
331 #elif defined(HAVE_SIGACTION)
332 memset(&action, 0, sizeof(action));
333
334 sigemptyset(&action.sa_mask);
335 sigaddset(&action.sa_mask, SIGALRM);
336 action.sa_handler = alarm_handler;
337 sigaction(SIGALRM, &action, NULL);
338 #else
339 signal(SIGALRM, alarm_handler);
340 #endif /* HAVE_SIGSET */
341
342 /*
343 * Open the SNMP socket...
344 */
345
346 if ((fd = open_snmp_socket()) < 0)
347 return (1);
348
349 /*
350 * Read the configuration file and any cache data...
351 */
352
353 read_snmp_conf(argv[1]);
354
355 Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
356
357 /*
358 * Scan for devices...
359 */
360
361 scan_devices(fd);
362
363 /*
364 * Close, free, and return with no errors...
365 */
366
367 close(fd);
368
369 free_array(Addresses);
370 free_array(Communities);
371 free_cache();
372
373 return (0);
374 }
375
376
377 /*
378 * 'add_array()' - Add a string to an array.
379 */
380
381 static char * /* O - New string */
382 add_array(cups_array_t *a, /* I - Array */
383 const char *s) /* I - String to add */
384 {
385 char *dups; /* New string */
386
387
388 dups = strdup(s);
389
390 cupsArrayAdd(a, dups);
391
392 return (dups);
393 }
394
395
396 /*
397 * 'add_cache()' - Add a cached device...
398 */
399
400 static void
401 add_cache(http_addr_t *addr, /* I - Device IP address */
402 const char *addrname, /* I - IP address or name string */
403 const char *uri, /* I - Device URI */
404 const char *id, /* I - 1284 device ID */
405 const char *make_and_model) /* I - Make and model */
406 {
407 snmp_cache_t *temp; /* New device entry */
408
409
410 debug_printf("DEBUG: add_cache(addr=%p, addrname=\"%s\", uri=\"%s\", "
411 "id=\"%s\", make_and_model=\"%s\")\n",
412 addr, addrname, uri ? uri : "(null)", id ? id : "(null)",
413 make_and_model ? make_and_model : "(null)");
414
415 temp = calloc(1, sizeof(snmp_cache_t));
416 memcpy(&(temp->address), addr, sizeof(temp->address));
417
418 temp->addrname = strdup(addrname);
419
420 if (uri)
421 temp->uri = strdup(uri);
422
423 if (id)
424 temp->id = strdup(id);
425
426 if (make_and_model)
427 temp->make_and_model = strdup(make_and_model);
428
429 cupsArrayAdd(Devices, temp);
430
431 if (uri)
432 list_device(temp);
433 }
434
435
436 /*
437 * 'alarm_handler()' - Handle alarm signals...
438 */
439
440 static void
441 alarm_handler(int sig) /* I - Signal number */
442 {
443 /*
444 * Do nothing...
445 */
446
447 (void)sig;
448
449 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
450 signal(SIGALRM, alarm_handler);
451 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
452
453 if (DebugLevel)
454 write(2, "DEBUG: ALARM!\n", 14);
455 }
456
457
458 /*
459 * 'asn1_decode_snmp()' - Decode a SNMP packet.
460 */
461
462 static int /* O - 0 on success, -1 on error */
463 asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */
464 size_t len, /* I - Size of buffer */
465 snmp_packet_t *packet) /* I - SNMP packet */
466 {
467 unsigned char *bufptr, /* Pointer into the data */
468 *bufend; /* End of data */
469 int length; /* Length of value */
470
471
472 /*
473 * Initialize the decoding...
474 */
475
476 memset(packet, 0, sizeof(snmp_packet_t));
477
478 bufptr = buffer;
479 bufend = buffer + len;
480
481 if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
482 packet->error = "Packet does not start with SEQUENCE";
483 else if (asn1_get_length(&bufptr, bufend) == 0)
484 packet->error = "SEQUENCE uses indefinite length";
485 else if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
486 packet->error = "No version number";
487 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
488 packet->error = "Version uses indefinite length";
489 else if ((packet->version = asn1_get_integer(&bufptr, bufend, length))
490 != SNMP_VERSION_1)
491 packet->error = "Bad SNMP version number";
492 else if (asn1_get_type(&bufptr, bufend) != ASN1_OCTET_STRING)
493 packet->error = "No community name";
494 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
495 packet->error = "Community name uses indefinite length";
496 else
497 {
498 asn1_get_string(&bufptr, bufend, length, packet->community,
499 sizeof(packet->community));
500
501 if ((packet->request_type = asn1_get_type(&bufptr, bufend))
502 != ASN1_GET_RESPONSE)
503 packet->error = "Packet does not contain a Get-Response-PDU";
504 else if (asn1_get_length(&bufptr, bufend) == 0)
505 packet->error = "Get-Response-PDU uses indefinite length";
506 else if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
507 packet->error = "No request-id";
508 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
509 packet->error = "request-id uses indefinite length";
510 else
511 {
512 packet->request_id = asn1_get_integer(&bufptr, bufend, length);
513
514 if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
515 packet->error = "No error-status";
516 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
517 packet->error = "error-status uses indefinite length";
518 else
519 {
520 packet->error_status = asn1_get_integer(&bufptr, bufend, length);
521
522 if (asn1_get_type(&bufptr, bufend) != ASN1_INTEGER)
523 packet->error = "No error-index";
524 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
525 packet->error = "error-index uses indefinite length";
526 else
527 {
528 packet->error_index = asn1_get_integer(&bufptr, bufend, length);
529
530 if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
531 packet->error = "No variable-bindings SEQUENCE";
532 else if (asn1_get_length(&bufptr, bufend) == 0)
533 packet->error = "variable-bindings uses indefinite length";
534 else if (asn1_get_type(&bufptr, bufend) != ASN1_SEQUENCE)
535 packet->error = "No VarBind SEQUENCE";
536 else if (asn1_get_length(&bufptr, bufend) == 0)
537 packet->error = "VarBind uses indefinite length";
538 else if (asn1_get_type(&bufptr, bufend) != ASN1_OID)
539 packet->error = "No name OID";
540 else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
541 packet->error = "Name OID uses indefinite length";
542 else
543 {
544 asn1_get_oid(&bufptr, bufend, length, packet->object_name,
545 SNMP_MAX_OID);
546
547 packet->object_type = asn1_get_type(&bufptr, bufend);
548
549 if ((length = asn1_get_length(&bufptr, bufend)) == 0 &&
550 packet->object_type != ASN1_NULL_VALUE &&
551 packet->object_type != ASN1_OCTET_STRING)
552 packet->error = "Value uses indefinite length";
553 else
554 {
555 switch (packet->object_type)
556 {
557 case ASN1_BOOLEAN :
558 packet->object_value.boolean =
559 asn1_get_integer(&bufptr, bufend, length);
560 break;
561
562 case ASN1_INTEGER :
563 packet->object_value.integer =
564 asn1_get_integer(&bufptr, bufend, length);
565 break;
566
567 case ASN1_NULL_VALUE :
568 break;
569
570 case ASN1_OCTET_STRING :
571 asn1_get_string(&bufptr, bufend, length,
572 packet->object_value.string,
573 SNMP_MAX_STRING);
574 break;
575
576 case ASN1_OID :
577 asn1_get_oid(&bufptr, bufend, length,
578 packet->object_value.oid, SNMP_MAX_OID);
579 break;
580
581 default :
582 packet->error = "Unsupported value type";
583 break;
584 }
585 }
586 }
587 }
588 }
589 }
590 }
591
592 return (packet->error ? -1 : 0);
593 }
594
595
596 /*
597 * 'asn1_debug()' - Decode an ASN1-encoded message.
598 */
599
600 static void
601 asn1_debug(unsigned char *buffer, /* I - Buffer */
602 size_t len, /* I - Length of buffer */
603 int indent) /* I - Indentation */
604 {
605 int i; /* Looping var */
606 unsigned char *bufend; /* End of buffer */
607 int integer; /* Number value */
608 int oid[SNMP_MAX_OID]; /* OID value */
609 char string[SNMP_MAX_STRING];/* String value */
610 unsigned char value_type; /* Type of value */
611 int value_length; /* Length of value */
612
613
614 bufend = buffer + len;
615
616 while (buffer < bufend)
617 {
618 /*
619 * Get value type...
620 */
621
622 value_type = asn1_get_type(&buffer, bufend);
623 value_length = asn1_get_length(&buffer, bufend);
624
625 switch (value_type)
626 {
627 case ASN1_BOOLEAN :
628 integer = asn1_get_integer(&buffer, bufend, value_length);
629
630 fprintf(stderr, "DEBUG: %*sBOOLEAN %d bytes %d\n", indent, "",
631 value_length, integer);
632 break;
633
634 case ASN1_INTEGER :
635 integer = asn1_get_integer(&buffer, bufend, value_length);
636
637 fprintf(stderr, "DEBUG: %*sINTEGER %d bytes %d\n", indent, "",
638 value_length, integer);
639 break;
640
641 case ASN1_OCTET_STRING :
642 fprintf(stderr, "DEBUG: %*sOCTET STRING %d bytes \"%s\"\n", indent, "",
643 value_length, asn1_get_string(&buffer, bufend,
644 value_length, string,
645 sizeof(string)));
646 break;
647
648 case ASN1_NULL_VALUE :
649 fprintf(stderr, "DEBUG: %*sNULL VALUE %d bytes\n", indent, "",
650 value_length);
651
652 buffer += value_length;
653 break;
654
655 case ASN1_OID :
656 asn1_get_oid(&buffer, bufend, value_length, oid, SNMP_MAX_OID);
657
658 fprintf(stderr, "DEBUG: %*sOID %d bytes ", indent, "",
659 value_length);
660 for (i = 0; oid[i]; i ++)
661 fprintf(stderr, ".%d", oid[i]);
662 putc('\n', stderr);
663 break;
664
665 case ASN1_SEQUENCE :
666 fprintf(stderr, "DEBUG: %*sSEQUENCE %d bytes\n", indent, "",
667 value_length);
668 asn1_debug(buffer, value_length, indent + 4);
669
670 buffer += value_length;
671 break;
672
673 case ASN1_GET_REQUEST :
674 fprintf(stderr, "DEBUG: %*sGet-Request-PDU %d bytes\n", indent, "",
675 value_length);
676 asn1_debug(buffer, value_length, indent + 4);
677
678 buffer += value_length;
679 break;
680
681 case ASN1_GET_RESPONSE :
682 fprintf(stderr, "DEBUG: %*sGet-Response-PDU %d bytes\n", indent, "",
683 value_length);
684 asn1_debug(buffer, value_length, indent + 4);
685
686 buffer += value_length;
687 break;
688
689 default :
690 fprintf(stderr, "DEBUG: %*sUNKNOWN(%x) %d bytes\n", indent, "",
691 value_type, value_length);
692
693 buffer += value_length;
694 break;
695 }
696 }
697 }
698
699
700 /*
701 * 'asn1_encode_snmp()' - Encode a SNMP packet.
702 */
703
704 static int /* O - Length on success, -1 on error */
705 asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */
706 size_t bufsize, /* I - Size of buffer */
707 snmp_packet_t *packet) /* I - SNMP packet */
708 {
709 unsigned char *bufptr; /* Pointer into buffer */
710 int total, /* Total length */
711 msglen, /* Length of entire message */
712 commlen, /* Length of community string */
713 reqlen, /* Length of request */
714 listlen, /* Length of variable list */
715 varlen, /* Length of variable */
716 namelen, /* Length of object name OID */
717 valuelen; /* Length of object value */
718
719
720 /*
721 * Get the lengths of the community string, OID, and message...
722 */
723
724 namelen = asn1_size_oid(packet->object_name);
725
726 switch (packet->object_type)
727 {
728 case ASN1_NULL_VALUE :
729 valuelen = 0;
730 break;
731
732 case ASN1_BOOLEAN :
733 valuelen = asn1_size_integer(packet->object_value.boolean);
734 break;
735
736 case ASN1_INTEGER :
737 valuelen = asn1_size_integer(packet->object_value.integer);
738 break;
739
740 case ASN1_OCTET_STRING :
741 valuelen = strlen(packet->object_value.string);
742 break;
743
744 case ASN1_OID :
745 valuelen = asn1_size_oid(packet->object_value.oid);
746 break;
747
748 default :
749 packet->error = "Unknown object type";
750 return (-1);
751 }
752
753 varlen = 1 + asn1_size_length(namelen) + namelen +
754 1 + asn1_size_length(valuelen) + valuelen;
755 listlen = 1 + asn1_size_length(varlen) + varlen;
756 reqlen = 2 + asn1_size_integer(packet->request_id) +
757 2 + asn1_size_integer(packet->error_status) +
758 2 + asn1_size_integer(packet->error_index) +
759 1 + asn1_size_length(listlen) + listlen;
760 commlen = strlen(packet->community);
761 msglen = 2 + asn1_size_integer(packet->version) +
762 1 + asn1_size_length(commlen) + commlen +
763 1 + asn1_size_length(reqlen) + reqlen;
764 total = 1 + asn1_size_length(msglen) + msglen;
765
766 if (total > bufsize)
767 {
768 packet->error = "Message too large for buffer";
769 return (-1);
770 }
771
772 /*
773 * Then format the message...
774 */
775
776 bufptr = buffer;
777
778 *bufptr++ = ASN1_SEQUENCE; /* SNMPv1 message header */
779 asn1_set_length(&bufptr, msglen);
780
781 asn1_set_integer(&bufptr, packet->version);
782 /* version */
783
784 *bufptr++ = ASN1_OCTET_STRING; /* community */
785 asn1_set_length(&bufptr, commlen);
786 memcpy(bufptr, packet->community, commlen);
787 bufptr += commlen;
788
789 *bufptr++ = packet->request_type; /* Get-Request-PDU */
790 asn1_set_length(&bufptr, reqlen);
791
792 asn1_set_integer(&bufptr, packet->request_id);
793
794 asn1_set_integer(&bufptr, packet->error_status);
795
796 asn1_set_integer(&bufptr, packet->error_index);
797
798 *bufptr++ = ASN1_SEQUENCE; /* variable-bindings */
799 asn1_set_length(&bufptr, listlen);
800
801 *bufptr++ = ASN1_SEQUENCE; /* variable */
802 asn1_set_length(&bufptr, varlen);
803
804 asn1_set_oid(&bufptr, packet->object_name);
805 /* ObjectName */
806
807 switch (packet->object_type)
808 {
809 case ASN1_NULL_VALUE :
810 *bufptr++ = ASN1_NULL_VALUE; /* ObjectValue */
811 *bufptr++ = 0; /* Length */
812 break;
813
814 case ASN1_BOOLEAN :
815 asn1_set_integer(&bufptr, packet->object_value.boolean);
816 break;
817
818 case ASN1_INTEGER :
819 asn1_set_integer(&bufptr, packet->object_value.integer);
820 break;
821
822 case ASN1_OCTET_STRING :
823 *bufptr++ = ASN1_OCTET_STRING;
824 asn1_set_length(&bufptr, valuelen);
825 memcpy(bufptr, packet->object_value.string, valuelen);
826 bufptr += valuelen;
827 break;
828
829 case ASN1_OID :
830 asn1_set_oid(&bufptr, packet->object_value.oid);
831 break;
832 }
833
834 return (bufptr - buffer);
835 }
836
837
838 /*
839 * 'asn1_get_integer()' - Get an integer value.
840 */
841
842 static int /* O - Integer value */
843 asn1_get_integer(
844 unsigned char **buffer, /* IO - Pointer in buffer */
845 unsigned char *bufend, /* I - End of buffer */
846 int length) /* I - Length of value */
847 {
848 int value; /* Integer value */
849
850
851 for (value = 0;
852 length > 0 && *buffer < bufend;
853 length --, (*buffer) ++)
854 value = (value << 8) | **buffer;
855
856 return (value);
857 }
858
859
860 /*
861 * 'asn1_get_length()' - Get a value length.
862 */
863
864 static int /* O - Length */
865 asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */
866 unsigned char *bufend) /* I - End of buffer */
867 {
868 int length; /* Length */
869
870
871 length = **buffer;
872 (*buffer) ++;
873
874 if (length & 128)
875 length = asn1_get_integer(buffer, bufend, length & 127);
876
877 return (length);
878 }
879
880
881 /*
882 * 'asn1_get_oid()' - Get an OID value.
883 */
884
885 static int /* O - Last OID number */
886 asn1_get_oid(
887 unsigned char **buffer, /* IO - Pointer in buffer */
888 unsigned char *bufend, /* I - End of buffer */
889 int length, /* I - Length of value */
890 int *oid, /* I - OID buffer */
891 int oidsize) /* I - Size of OID buffer */
892 {
893 unsigned char *valend; /* End of value */
894 int *oidend; /* End of OID buffer */
895 int number; /* OID number */
896
897
898 valend = *buffer + length;
899 oidend = oid + oidsize - 1;
900
901 if (valend > bufend)
902 valend = bufend;
903
904 number = asn1_get_packed(buffer, bufend);
905
906 if (number < 80)
907 {
908 *oid++ = number / 40;
909 number = number % 40;
910 *oid++ = number;
911 }
912 else
913 {
914 *oid++ = 2;
915 number -= 80;
916 *oid++ = number;
917 }
918
919 while (*buffer < valend)
920 {
921 number = asn1_get_packed(buffer, bufend);
922
923 if (oid < oidend)
924 *oid++ = number;
925 }
926
927 *oid = 0;
928
929 return (number);
930 }
931
932
933 /*
934 * 'asn1_get_packed()' - Get a packed integer value.
935 */
936
937 static int /* O - Value */
938 asn1_get_packed(
939 unsigned char **buffer, /* IO - Pointer in buffer */
940 unsigned char *bufend) /* I - End of buffer */
941 {
942 int value; /* Value */
943
944
945 value = 0;
946
947 while ((**buffer & 128) && *buffer < bufend)
948 {
949 value = (value << 7) | (**buffer & 127);
950 (*buffer) ++;
951 }
952
953 if (*buffer < bufend)
954 {
955 value = (value << 7) | **buffer;
956 (*buffer) ++;
957 }
958
959 return (value);
960 }
961
962
963 /*
964 * 'asn1_get_string()' - Get a string value.
965 */
966
967 static char * /* O - String */
968 asn1_get_string(
969 unsigned char **buffer, /* IO - Pointer in buffer */
970 unsigned char *bufend, /* I - End of buffer */
971 int length, /* I - Value length */
972 char *string, /* I - String buffer */
973 int strsize) /* I - String buffer size */
974 {
975 if (length < strsize)
976 {
977 memcpy(string, *buffer, length);
978 string[length] = '\0';
979 }
980 else
981 {
982 memcpy(string, buffer, strsize - 1);
983 string[strsize - 1] = '\0';
984 }
985
986 (*buffer) += length;
987
988 return (string);
989 }
990
991
992 /*
993 * 'asn1_get_type()' - Get a value type.
994 */
995
996 static int /* O - Type */
997 asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */
998 unsigned char *bufend) /* I - End of buffer */
999 {
1000 int type; /* Type */
1001
1002
1003 type = **buffer;
1004 (*buffer) ++;
1005
1006 if ((type & 31) == 31)
1007 type = asn1_get_packed(buffer, bufend);
1008
1009 return (type);
1010 }
1011
1012
1013 /*
1014 * 'asn1_set_integer()' - Set an integer value.
1015 */
1016
1017 static void
1018 asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */
1019 int integer) /* I - Integer value */
1020 {
1021 **buffer = ASN1_INTEGER;
1022 (*buffer) ++;
1023
1024 if (integer > 0x7fffff || integer < -0x800000)
1025 {
1026 **buffer = 4;
1027 (*buffer) ++;
1028 **buffer = integer >> 24;
1029 (*buffer) ++;
1030 **buffer = integer >> 16;
1031 (*buffer) ++;
1032 **buffer = integer >> 8;
1033 (*buffer) ++;
1034 **buffer = integer;
1035 (*buffer) ++;
1036 }
1037 else if (integer > 0x7fff || integer < -0x8000)
1038 {
1039 **buffer = 3;
1040 (*buffer) ++;
1041 **buffer = integer >> 16;
1042 (*buffer) ++;
1043 **buffer = integer >> 8;
1044 (*buffer) ++;
1045 **buffer = integer;
1046 (*buffer) ++;
1047 }
1048 else if (integer > 0x7f || integer < -0x80)
1049 {
1050 **buffer = 2;
1051 (*buffer) ++;
1052 **buffer = integer >> 8;
1053 (*buffer) ++;
1054 **buffer = integer;
1055 (*buffer) ++;
1056 }
1057 else
1058 {
1059 **buffer = 1;
1060 (*buffer) ++;
1061 **buffer = integer;
1062 (*buffer) ++;
1063 }
1064 }
1065
1066
1067 /*
1068 * 'asn1_set_length()' - Set a value length.
1069 */
1070
1071 static void
1072 asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */
1073 int length) /* I - Length value */
1074 {
1075 if (length > 255)
1076 {
1077 **buffer = 0x82; /* 2-byte length */
1078 (*buffer) ++;
1079 **buffer = length >> 8;
1080 (*buffer) ++;
1081 **buffer = length;
1082 (*buffer) ++;
1083 }
1084 else if (length > 127)
1085 {
1086 **buffer = 0x81; /* 1-byte length */
1087 (*buffer) ++;
1088 **buffer = length;
1089 (*buffer) ++;
1090 }
1091 else
1092 {
1093 **buffer = length; /* Length */
1094 (*buffer) ++;
1095 }
1096 }
1097
1098
1099 /*
1100 * 'asn1_set_oid()' - Set an OID value.
1101 */
1102
1103 static void
1104 asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */
1105 const int *oid) /* I - OID value */
1106 {
1107 **buffer = ASN1_OID;
1108 (*buffer) ++;
1109
1110 asn1_set_length(buffer, asn1_size_oid(oid));
1111
1112 asn1_set_packed(buffer, oid[0] * 40 + oid[1]);
1113
1114 for (oid += 2; *oid; oid ++)
1115 asn1_set_packed(buffer, *oid);
1116 }
1117
1118
1119 /*
1120 * 'asn1_set_packed()' - Set a packed integer value.
1121 */
1122
1123 static void
1124 asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */
1125 int integer) /* I - Integer value */
1126 {
1127 if (integer > 0xfffffff)
1128 {
1129 **buffer = (integer >> 28) & 0x7f;
1130 (*buffer) ++;
1131 }
1132
1133 if (integer > 0x1fffff)
1134 {
1135 **buffer = (integer >> 21) & 0x7f;
1136 (*buffer) ++;
1137 }
1138
1139 if (integer > 0x3fff)
1140 {
1141 **buffer = (integer >> 14) & 0x7f;
1142 (*buffer) ++;
1143 }
1144
1145 if (integer > 0x7f)
1146 {
1147 **buffer = (integer >> 7) & 0x7f;
1148 (*buffer) ++;
1149 }
1150
1151 **buffer = integer & 0x7f;
1152 (*buffer) ++;
1153 }
1154
1155 /*
1156 * 'asn1_size_integer()' - Figure out the number of bytes needed for an
1157 * integer value.
1158 */
1159
1160 static int /* O - Size in bytes */
1161 asn1_size_integer(int integer) /* I - Integer value */
1162 {
1163 if (integer > 0x7fffff || integer < -0x800000)
1164 return (4);
1165 else if (integer > 0x7fff || integer < -0x8000)
1166 return (3);
1167 else if (integer > 0x7f || integer < -0x80)
1168 return (2);
1169 else
1170 return (1);
1171 }
1172
1173
1174 /*
1175 * 'asn1_size_length()' - Figure out the number of bytes needed for a
1176 * length value.
1177 */
1178
1179 static int /* O - Size in bytes */
1180 asn1_size_length(int length) /* I - Length value */
1181 {
1182 if (length > 0xff)
1183 return (3);
1184 else if (length > 0x7f)
1185 return (2);
1186 else
1187 return (1);
1188 }
1189
1190
1191 /*
1192 * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an
1193 * OID value.
1194 */
1195
1196 static int /* O - Size in bytes */
1197 asn1_size_oid(const int *oid) /* I - OID value */
1198 {
1199 int length; /* Length of value */
1200
1201
1202 for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2; *oid; oid ++)
1203 length += asn1_size_packed(*oid);
1204
1205 return (length);
1206 }
1207
1208
1209 /*
1210 * 'asn1_size_packed()' - Figure out the number of bytes needed for a
1211 * packed integer value.
1212 */
1213
1214 static int /* O - Size in bytes */
1215 asn1_size_packed(int integer) /* I - Integer value */
1216 {
1217 if (integer > 0xfffffff)
1218 return (5);
1219 else if (integer > 0x1fffff)
1220 return (4);
1221 else if (integer > 0x3fff)
1222 return (3);
1223 else if (integer > 0x7f)
1224 return (2);
1225 else
1226 return (1);
1227 }
1228
1229
1230 /*
1231 * 'compare_cache()' - Compare two cache entries.
1232 */
1233
1234 static int /* O - Result of comparison */
1235 compare_cache(snmp_cache_t *a, /* I - First cache entry */
1236 snmp_cache_t *b) /* I - Second cache entry */
1237 {
1238 return (strcasecmp(a->addrname, b->addrname));
1239 }
1240
1241
1242 /*
1243 * 'debug_printf()' - Display some debugging information.
1244 */
1245
1246 static void
1247 debug_printf(const char *format, /* I - Printf-style format string */
1248 ...) /* I - Additional arguments as needed */
1249 {
1250 va_list ap; /* Pointer to arguments */
1251
1252
1253 if (!DebugLevel)
1254 return;
1255
1256 va_start(ap, format);
1257 vfprintf(stderr, format, ap);
1258 va_end(ap);
1259 }
1260
1261
1262 /*
1263 * 'do_request()' - Do a non-blocking IPP request.
1264 */
1265
1266 static ipp_t * /* O - Response data or NULL */
1267 do_request(http_t *http, /* I - HTTP connection to server */
1268 ipp_t *request, /* I - IPP request */
1269 const char *resource) /* I - HTTP resource for POST */
1270 {
1271 ipp_t *response; /* IPP response data */
1272 http_status_t status; /* Status of HTTP request */
1273 ipp_state_t state; /* State of IPP processing */
1274
1275
1276 /*
1277 * Setup the HTTP variables needed...
1278 */
1279
1280 httpClearFields(http);
1281 httpSetLength(http, ippLength(request));
1282 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
1283
1284 /*
1285 * Do the POST request...
1286 */
1287
1288 debug_printf("DEBUG: %.3f POST %s...\n", run_time(), resource);
1289
1290 if (httpPost(http, resource))
1291 {
1292 if (httpReconnect(http))
1293 {
1294 _cupsSetError(IPP_DEVICE_ERROR, "Unable to reconnect");
1295 return (NULL);
1296 }
1297 else if (httpPost(http, resource))
1298 {
1299 _cupsSetError(IPP_GONE, "Unable to POST");
1300 return (NULL);
1301 }
1302 }
1303
1304 /*
1305 * Send the IPP data...
1306 */
1307
1308 request->state = IPP_IDLE;
1309 status = HTTP_CONTINUE;
1310
1311 while ((state = ippWrite(http, request)) != IPP_DATA)
1312 if (state == IPP_ERROR)
1313 {
1314 status = HTTP_ERROR;
1315 break;
1316 }
1317 else if (httpCheck(http))
1318 {
1319 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
1320 break;
1321 }
1322
1323 /*
1324 * Get the server's return status...
1325 */
1326
1327 debug_printf("DEBUG: %.3f Getting response...\n", run_time());
1328
1329 while (status == HTTP_CONTINUE)
1330 if (httpWait(http, 1000))
1331 status = httpUpdate(http);
1332 else
1333 {
1334 status = HTTP_ERROR;
1335 http->error = ETIMEDOUT;
1336 }
1337
1338 if (status != HTTP_OK)
1339 {
1340 /*
1341 * Flush any error message...
1342 */
1343
1344 httpFlush(http);
1345 response = NULL;
1346 }
1347 else
1348 {
1349 /*
1350 * Read the response...
1351 */
1352
1353 response = ippNew();
1354
1355 while ((state = ippRead(http, response)) != IPP_DATA)
1356 if (state == IPP_ERROR)
1357 {
1358 /*
1359 * Delete the response...
1360 */
1361
1362 ippDelete(response);
1363 response = NULL;
1364
1365 _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
1366 break;
1367 }
1368 }
1369
1370 /*
1371 * Delete the original request and return the response...
1372 */
1373
1374 ippDelete(request);
1375
1376 if (response)
1377 {
1378 ipp_attribute_t *attr; /* status-message attribute */
1379
1380
1381 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
1382
1383 _cupsSetError(response->request.status.status_code,
1384 attr ? attr->values[0].string.text :
1385 ippErrorString(response->request.status.status_code));
1386 }
1387 else if (status != HTTP_OK)
1388 {
1389 switch (status)
1390 {
1391 case HTTP_NOT_FOUND :
1392 _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
1393 break;
1394
1395 case HTTP_UNAUTHORIZED :
1396 _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
1397 break;
1398
1399 case HTTP_FORBIDDEN :
1400 _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
1401 break;
1402
1403 case HTTP_BAD_REQUEST :
1404 _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
1405 break;
1406
1407 case HTTP_REQUEST_TOO_LARGE :
1408 _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
1409 break;
1410
1411 case HTTP_NOT_IMPLEMENTED :
1412 _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
1413 break;
1414
1415 case HTTP_NOT_SUPPORTED :
1416 _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
1417 break;
1418
1419 default :
1420 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
1421 break;
1422 }
1423 }
1424
1425 return (response);
1426 }
1427
1428
1429 /*
1430 * 'fix_make_model()' - Fix common problems in the make-and-model string.
1431 */
1432
1433 static void
1434 fix_make_model(
1435 char *make_model, /* I - New make-and-model string */
1436 const char *old_make_model, /* I - Old make-and-model string */
1437 int make_model_size) /* I - Size of new string buffer */
1438 {
1439 char *mmptr; /* Pointer into make-and-model string */
1440
1441
1442 /*
1443 * Fix some common problems with the make-and-model string so
1444 * that printer driver detection works better...
1445 */
1446
1447 if (!strncasecmp(old_make_model, "Hewlett-Packard", 15))
1448 {
1449 /*
1450 * Strip leading Hewlett-Packard and hp prefixes and replace
1451 * with a single HP manufacturer prefix...
1452 */
1453
1454 mmptr = (char *)old_make_model + 15;
1455
1456 while (isspace(*mmptr & 255))
1457 mmptr ++;
1458
1459 if (!strncasecmp(mmptr, "hp", 2))
1460 {
1461 mmptr += 2;
1462
1463 while (isspace(*mmptr & 255))
1464 mmptr ++;
1465 }
1466
1467 make_model[0] = 'H';
1468 make_model[1] = 'P';
1469 make_model[2] = ' ';
1470 strlcpy(make_model + 3, mmptr, make_model_size - 3);
1471 }
1472 else if (!strncasecmp(old_make_model, "deskjet", 7))
1473 snprintf(make_model, make_model_size, "HP DeskJet%s", old_make_model + 7);
1474 else if (!strncasecmp(old_make_model, "officejet", 9))
1475 snprintf(make_model, make_model_size, "HP OfficeJet%s", old_make_model + 9);
1476 else if (!strncasecmp(old_make_model, "stylus_pro_", 11))
1477 snprintf(make_model, make_model_size, "EPSON Stylus Pro %s",
1478 old_make_model + 11);
1479 else
1480 strlcpy(make_model, old_make_model, make_model_size);
1481
1482 if ((mmptr = strstr(make_model, ", Inc.,")) != NULL)
1483 {
1484 /*
1485 * Strip inc. from name, e.g. "Tektronix, Inc., Phaser 560"
1486 * becomes "Tektronix Phaser 560"...
1487 */
1488
1489 _cups_strcpy(mmptr, mmptr + 7);
1490 }
1491
1492 if ((mmptr = strstr(make_model, " Network")) != NULL)
1493 {
1494 /*
1495 * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
1496 * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
1497 */
1498
1499 *mmptr = '\0';
1500 }
1501
1502 if ((mmptr = strchr(make_model, ',')) != NULL)
1503 {
1504 /*
1505 * Drop anything after a trailing comma...
1506 */
1507
1508 *mmptr = '\0';
1509 }
1510 }
1511
1512
1513 /*
1514 * 'free_array()' - Free an array of strings.
1515 */
1516
1517 static void
1518 free_array(cups_array_t *a) /* I - Array */
1519 {
1520 char *s; /* Current string */
1521
1522
1523 for (s = (char *)cupsArrayFirst(a); s; s = (char *)cupsArrayNext(a))
1524 free(s);
1525
1526 cupsArrayDelete(a);
1527 }
1528
1529
1530 /*
1531 * 'free_cache()' - Free the array of cached devices.
1532 */
1533
1534 static void
1535 free_cache(void)
1536 {
1537 snmp_cache_t *cache; /* Cached device */
1538
1539
1540 for (cache = (snmp_cache_t *)cupsArrayFirst(Devices);
1541 cache;
1542 cache = (snmp_cache_t *)cupsArrayNext(Devices))
1543 {
1544 free(cache->addrname);
1545
1546 if (cache->uri)
1547 free(cache->uri);
1548
1549 if (cache->id)
1550 free(cache->id);
1551
1552 if (cache->make_and_model)
1553 free(cache->make_and_model);
1554
1555 free(cache);
1556 }
1557
1558 cupsArrayDelete(Devices);
1559 Devices = NULL;
1560 }
1561
1562
1563 /*
1564 * 'get_interface_addresses()' - Get the broadcast address(es) associated
1565 * with an interface.
1566 */
1567
1568 static http_addrlist_t * /* O - List of addresses */
1569 get_interface_addresses(
1570 const char *ifname) /* I - Interface name */
1571 {
1572 struct ifaddrs *addrs, /* Interface address list */
1573 *addr; /* Current interface address */
1574 http_addrlist_t *first, /* First address in list */
1575 *last, /* Last address in list */
1576 *current; /* Current address */
1577
1578
1579 if (getifaddrs(&addrs) < 0)
1580 return (NULL);
1581
1582 for (addr = addrs, first = NULL, last = NULL; addr; addr = addr->ifa_next)
1583 if ((addr->ifa_flags & IFF_BROADCAST) && addr->ifa_broadaddr &&
1584 addr->ifa_broadaddr->sa_family == AF_INET &&
1585 (!ifname || !strcmp(ifname, addr->ifa_name)))
1586 {
1587 current = calloc(1, sizeof(http_addrlist_t));
1588
1589 memcpy(&(current->addr), addr->ifa_broadaddr,
1590 sizeof(struct sockaddr_in));
1591
1592 if (!last)
1593 first = current;
1594 else
1595 last->next = current;
1596
1597 last = current;
1598 }
1599
1600 freeifaddrs(addrs);
1601
1602 return (first);
1603 }
1604
1605
1606 /*
1607 * 'hex_debug()' - Output hex debugging data...
1608 */
1609
1610 static void
1611 hex_debug(unsigned char *buffer, /* I - Buffer */
1612 size_t len) /* I - Number of bytes */
1613 {
1614 int col; /* Current column */
1615
1616
1617 fputs("DEBUG: Hex dump of packet:\n", stderr);
1618
1619 for (col = 0; len > 0; col ++, buffer ++, len --)
1620 {
1621 if ((col & 15) == 0)
1622 fprintf(stderr, "DEBUG: %04X ", col);
1623
1624 fprintf(stderr, " %02X", *buffer);
1625
1626 if ((col & 15) == 15)
1627 putc('\n', stderr);
1628 }
1629
1630 if (col & 15)
1631 putc('\n', stderr);
1632 }
1633
1634
1635 /*
1636 * 'list_device()' - List a device we found...
1637 */
1638
1639 static void
1640 list_device(snmp_cache_t *cache) /* I - Cached device */
1641 {
1642 if (cache->uri)
1643 printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
1644 cache->uri,
1645 cache->make_and_model ? cache->make_and_model : "Unknown",
1646 cache->make_and_model ? cache->make_and_model : "Unknown",
1647 cache->addrname, cache->id ? cache->id : "");
1648 }
1649
1650
1651 /*
1652 * 'open_snmp_socket()' - Open the SNMP broadcast socket.
1653 */
1654
1655 static int /* O - SNMP socket file descriptor */
1656 open_snmp_socket(void)
1657 {
1658 int fd; /* SNMP socket file descriptor */
1659 int val; /* Socket option value */
1660
1661
1662 /*
1663 * Create the SNMP socket...
1664 */
1665
1666 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1667 {
1668 fprintf(stderr, "ERROR: Unable to create SNMP socket - %s\n",
1669 strerror(errno));
1670
1671 return (-1);
1672 }
1673
1674 /*
1675 * Set the "broadcast" flag...
1676 */
1677
1678 val = 1;
1679
1680 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1681 {
1682 fprintf(stderr, "ERROR: Unable to set broadcast mode - %s\n",
1683 strerror(errno));
1684
1685 close(fd);
1686
1687 return (-1);
1688 }
1689
1690 return (fd);
1691 }
1692
1693
1694 /*
1695 * 'password_cb()' - Handle authentication requests.
1696 *
1697 * All we do right now is return NULL, indicating that no authentication
1698 * is possible.
1699 */
1700
1701 static const char * /* O - Password (NULL) */
1702 password_cb(const char *prompt) /* I - Prompt message */
1703 {
1704 (void)prompt; /* Anti-compiler-warning-code */
1705
1706 return (NULL);
1707 }
1708
1709
1710 /*
1711 * 'probe_device()' - Probe a device to discover whether it is a printer.
1712 *
1713 * TODO: Try using the Port Monitor MIB to discover the correct protocol
1714 * to use - first need a commercially-available printer that supports
1715 * it, though...
1716 */
1717
1718 static void
1719 probe_device(snmp_cache_t *device) /* I - Device */
1720 {
1721 int i, j; /* Looping vars */
1722 http_t *http; /* HTTP connection for IPP */
1723 char uri[1024]; /* Full device URI */
1724
1725
1726 /*
1727 * Try connecting via IPP first...
1728 */
1729
1730 debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);
1731
1732 if (device->make_and_model &&
1733 (!strncasecmp(device->make_and_model, "Epson", 5) ||
1734 !strncasecmp(device->make_and_model, "HP ", 3) ||
1735 !strncasecmp(device->make_and_model, "Hewlett", 7) ||
1736 !strncasecmp(device->make_and_model, "Kyocera", 7) ||
1737 !strncasecmp(device->make_and_model, "Lexmark", 7) ||
1738 !strncasecmp(device->make_and_model, "Tektronix", 9) ||
1739 !strncasecmp(device->make_and_model, "Xerox", 5)))
1740 {
1741 /*
1742 * Epson, HP, Kyocera, Lexmark, Tektronix, and Xerox printers often lock
1743 * up on IPP probes, so exclude them from the IPP connection test...
1744 */
1745
1746 http = NULL;
1747 }
1748 else
1749 {
1750 /*
1751 * Otherwise, try connecting for up to 1 second...
1752 */
1753
1754 alarm(1);
1755 http = httpConnect(device->addrname, 631);
1756 alarm(0);
1757 }
1758
1759 if (http)
1760 {
1761 /*
1762 * IPP is supported...
1763 */
1764
1765 ipp_t *request, /* IPP request */
1766 *response; /* IPP response */
1767 ipp_attribute_t *model, /* printer-make-and-model attribute */
1768 *info, /* printer-info attribute */
1769 *supported; /* printer-uri-supported attribute */
1770 char make_model[256],/* Make and model string to use */
1771 temp[256]; /* Temporary make/model string */
1772 int num_uris; /* Number of good URIs */
1773 static const char * const resources[] =
1774 { /* Common resource paths for IPP */
1775 "/ipp",
1776 /*"/ipp/port2",*/
1777 /*"/ipp/port3",*/
1778 /*"/EPSON_IPP_Printer",*/
1779 "/LPT1",
1780 "/LPT2",
1781 "/COM1",
1782 "/"
1783 };
1784
1785
1786 /*
1787 * Use non-blocking IO...
1788 */
1789
1790 httpBlocking(http, 0);
1791
1792 /*
1793 * Loop through a list of common resources that covers 99% of the
1794 * IPP-capable printers on the market today...
1795 */
1796
1797 for (i = 0, num_uris = 0;
1798 i < (int)(sizeof(resources) / sizeof(resources[0]));
1799 i ++)
1800 {
1801 /*
1802 * Stop early if we are out of time...
1803 */
1804
1805 if (MaxRunTime > 0 && run_time() >= MaxRunTime)
1806 break;
1807
1808 /*
1809 * Don't look past /ipp if we have found a working URI...
1810 */
1811
1812 if (num_uris > 0 && strncmp(resources[i], "/ipp", 4))
1813 break;
1814
1815 httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1816 device->addrname, 631, resources[i]);
1817
1818 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1819
1820 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1821 NULL, uri);
1822
1823 response = do_request(http, request, resources[i]);
1824
1825 debug_printf("DEBUG: %.3f %s %s (%s)\n", run_time(), uri,
1826 ippErrorString(cupsLastError()), cupsLastErrorString());
1827
1828 if (response && response->request.status.status_code == IPP_OK)
1829 {
1830 model = ippFindAttribute(response, "printer-make-and-model",
1831 IPP_TAG_TEXT);
1832 info = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT);
1833 supported = ippFindAttribute(response, "printer-uri-supported",
1834 IPP_TAG_URI);
1835
1836 if (!supported)
1837 {
1838 fprintf(stderr, "ERROR: Missing printer-uri-supported from %s!\n",
1839 device->addrname);
1840
1841 httpClose(http);
1842 return;
1843 }
1844
1845 debug_printf("DEBUG: printer-info=\"%s\"\n",
1846 info ? info->values[0].string.text : "(null)");
1847 debug_printf("DEBUG: printer-make-and-model=\"%s\"\n",
1848 model ? model->values[0].string.text : "(null)");
1849
1850 /*
1851 * Don't advertise this port if the printer actually only supports
1852 * a more generic version...
1853 */
1854
1855 if (!strncmp(resources[i], "/ipp/", 5))
1856 {
1857 for (j = 0; j < supported->num_values; j ++)
1858 if (strstr(supported->values[j].string.text, "/ipp/"))
1859 break;
1860
1861 if (j >= supported->num_values)
1862 {
1863 ippDelete(response);
1864 break;
1865 }
1866 }
1867
1868 /*
1869 * Don't use the printer-info attribute if it does not contain the
1870 * IEEE-1284 device ID data...
1871 */
1872
1873 if (info &&
1874 (!strchr(info->values[0].string.text, ':') ||
1875 !strchr(info->values[0].string.text, ';')))
1876 info = NULL;
1877
1878 /*
1879 * Don't use the printer-make-and-model if it contains a generic
1880 * string like "Ricoh IPP Printer"...
1881 */
1882
1883 if (model && strstr(model->values[0].string.text, "IPP Printer"))
1884 model = NULL;
1885
1886 /*
1887 * If we don't have a printer-make-and-model string from the printer
1888 * but do have the 1284 device ID string, generate a make-and-model
1889 * string from the device ID info...
1890 */
1891
1892 if (model)
1893 strlcpy(temp, model->values[0].string.text, sizeof(temp));
1894 else if (info)
1895 backendGetMakeModel(info->values[0].string.text, temp, sizeof(temp));
1896 else
1897 temp[0] = '\0';
1898
1899 fix_make_model(make_model, temp, sizeof(make_model));
1900
1901 /*
1902 * Update the current device or add a new printer to the cache...
1903 */
1904
1905 if (num_uris == 0)
1906 update_cache(device, uri,
1907 info ? info->values[0].string.text : NULL,
1908 make_model[0] ? make_model : NULL);
1909 else
1910 add_cache(&(device->address), device->addrname, uri,
1911 info ? info->values[0].string.text : NULL,
1912 make_model[0] ? make_model : NULL);
1913
1914 num_uris ++;
1915 }
1916
1917 ippDelete(response);
1918
1919 if (num_uris > 0 && cupsLastError() != IPP_OK)
1920 break;
1921 }
1922
1923 httpClose(http);
1924
1925 if (num_uris > 0)
1926 return;
1927 }
1928
1929 /*
1930 * OK, now try the standard ports...
1931 */
1932
1933 if (!try_connect(&(device->address), device->addrname, 9100))
1934 {
1935 debug_printf("DEBUG: %s supports AppSocket!\n", device->addrname);
1936
1937 snprintf(uri, sizeof(uri), "socket://%s", device->addrname);
1938 update_cache(device, uri, NULL, NULL);
1939 }
1940 else if (!try_connect(&(device->address), device->addrname, 515))
1941 {
1942 debug_printf("DEBUG: %s supports LPD!\n", device->addrname);
1943
1944 snprintf(uri, sizeof(uri), "lpd://%s/", device->addrname);
1945 update_cache(device, uri, NULL, NULL);
1946 }
1947 }
1948
1949
1950 /*
1951 * 'read_snmp_conf()' - Read the snmp.conf file.
1952 */
1953
1954 static void
1955 read_snmp_conf(const char *address) /* I - Single address to probe */
1956 {
1957 cups_file_t *fp; /* File pointer */
1958 char filename[1024], /* Filename */
1959 line[1024], /* Line from file */
1960 *value; /* Value on line */
1961 int linenum; /* Line number */
1962 const char *cups_serverroot; /* CUPS_SERVERROOT env var */
1963 const char *debug; /* CUPS_DEBUG_LEVEL env var */
1964 const char *runtime; /* CUPS_MAX_RUN_TIME env var */
1965
1966
1967 /*
1968 * Initialize the global address and community lists...
1969 */
1970
1971 Addresses = cupsArrayNew(NULL, NULL);
1972 Communities = cupsArrayNew(NULL, NULL);
1973
1974 if (address)
1975 add_array(Addresses, address);
1976
1977 if ((debug = getenv("CUPS_DEBUG_LEVEL")) != NULL)
1978 DebugLevel = atoi(debug);
1979
1980 if ((runtime = getenv("CUPS_MAX_RUN_TIME")) != NULL)
1981 MaxRunTime = atoi(runtime);
1982
1983 /*
1984 * Find the snmp.conf file...
1985 */
1986
1987 if ((cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
1988 cups_serverroot = CUPS_SERVERROOT;
1989
1990 snprintf(filename, sizeof(filename), "%s/snmp.conf", cups_serverroot);
1991
1992 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1993 {
1994 /*
1995 * Read the snmp.conf file...
1996 */
1997
1998 linenum = 0;
1999
2000 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
2001 {
2002 if (!value)
2003 fprintf(stderr, "ERROR: Missing value on line %d of %s!\n", linenum,
2004 filename);
2005 else if (!strcasecmp(line, "Address"))
2006 {
2007 if (!address)
2008 add_array(Addresses, value);
2009 }
2010 else if (!strcasecmp(line, "Community"))
2011 add_array(Communities, value);
2012 else if (!strcasecmp(line, "DebugLevel"))
2013 DebugLevel = atoi(value);
2014 else if (!strcasecmp(line, "HostNameLookups"))
2015 HostNameLookups = !strcasecmp(value, "on") ||
2016 !strcasecmp(value, "yes") ||
2017 !strcasecmp(value, "true") ||
2018 !strcasecmp(value, "double");
2019 else if (!strcasecmp(line, "MaxRunTime"))
2020 MaxRunTime = atoi(value);
2021 else
2022 fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n",
2023 line, linenum, filename);
2024 }
2025
2026 cupsFileClose(fp);
2027 }
2028
2029 /*
2030 * Use defaults if parameters are undefined...
2031 */
2032
2033 if (cupsArrayCount(Addresses) == 0)
2034 {
2035 fputs("INFO: Using default SNMP Address @LOCAL\n", stderr);
2036 add_array(Addresses, "@LOCAL");
2037 }
2038
2039 if (cupsArrayCount(Communities) == 0)
2040 {
2041 fputs("INFO: Using default SNMP Community public\n", stderr);
2042 add_array(Communities, "public");
2043 }
2044 }
2045
2046
2047 /*
2048 * 'read_snmp_response()' - Read and parse a SNMP response...
2049 */
2050
2051 static void
2052 read_snmp_response(int fd) /* I - SNMP socket file descriptor */
2053 {
2054 unsigned char buffer[SNMP_MAX_PACKET];/* Data packet */
2055 int bytes; /* Number of bytes received */
2056 http_addr_t addr; /* Source address */
2057 socklen_t addrlen; /* Source address length */
2058 char addrname[256]; /* Source address name */
2059 snmp_packet_t packet; /* Decoded packet */
2060 snmp_cache_t key, /* Search key */
2061 *device; /* Matching device */
2062
2063
2064 /*
2065 * Read the response data...
2066 */
2067
2068 addrlen = sizeof(addr);
2069
2070 if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (void *)&addr,
2071 &addrlen)) < 0)
2072 {
2073 fprintf(stderr, "ERROR: Unable to read data from socket: %s\n",
2074 strerror(errno));
2075 return;
2076 }
2077
2078 if (HostNameLookups)
2079 httpAddrLookup(&addr, addrname, sizeof(addrname));
2080 else
2081 httpAddrString(&addr, addrname, sizeof(addrname));
2082
2083 debug_printf("DEBUG: %.3f Received %d bytes from %s...\n", run_time(),
2084 bytes, addrname);
2085
2086 /*
2087 * Look for the response status code in the SNMP message header...
2088 */
2089
2090 if (asn1_decode_snmp(buffer, bytes, &packet))
2091 {
2092 fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n", addrname,
2093 packet.error);
2094
2095 asn1_debug(buffer, bytes, 0);
2096 hex_debug(buffer, bytes);
2097
2098 return;
2099 }
2100
2101 debug_printf("DEBUG: community=\"%s\"\n", packet.community);
2102 debug_printf("DEBUG: request-id=%d\n", packet.request_id);
2103 debug_printf("DEBUG: error-status=%d\n", packet.error_status);
2104
2105 if (DebugLevel > 1)
2106 asn1_debug(buffer, bytes, 0);
2107
2108 if (DebugLevel > 2)
2109 hex_debug(buffer, bytes);
2110
2111 if (packet.error_status)
2112 return;
2113
2114 /*
2115 * Find a matching device in the cache...
2116 */
2117
2118 key.addrname = addrname;
2119 device = (snmp_cache_t *)cupsArrayFind(Devices, &key);
2120
2121 /*
2122 * Process the message...
2123 */
2124
2125 if (packet.request_id == DeviceTypeRequest)
2126 {
2127 /*
2128 * Got the device type response...
2129 */
2130
2131 if (device)
2132 {
2133 debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
2134 addrname);
2135 return;
2136 }
2137
2138 /*
2139 * Add the device and request the device description...
2140 */
2141
2142 add_cache(&addr, addrname, NULL, NULL, NULL);
2143
2144 send_snmp_query(fd, &addr, SNMP_VERSION_1, packet.community,
2145 DeviceDescRequest, DeviceDescOID);
2146 }
2147 else if (packet.request_id == DeviceDescRequest &&
2148 packet.object_type == ASN1_OCTET_STRING)
2149 {
2150 /*
2151 * Update an existing cache entry...
2152 */
2153
2154 char make_model[256]; /* Make and model */
2155
2156
2157 if (!device)
2158 {
2159 debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
2160 addrname);
2161 return;
2162 }
2163
2164 /*
2165 * Convert the description to a make and model string...
2166 */
2167
2168 if (strchr(packet.object_value.string, ':') &&
2169 strchr(packet.object_value.string, ';'))
2170 {
2171 /*
2172 * Description is the IEEE-1284 device ID...
2173 */
2174
2175 backendGetMakeModel(packet.object_value.string, make_model,
2176 sizeof(make_model));
2177 }
2178 else
2179 {
2180 /*
2181 * Description is plain text...
2182 */
2183
2184 fix_make_model(make_model, packet.object_value.string,
2185 sizeof(make_model));
2186 }
2187
2188 if (device->make_and_model)
2189 free(device->make_and_model);
2190
2191 device->make_and_model = strdup(make_model);
2192 }
2193 }
2194
2195
2196 /*
2197 * 'run_time()' - Return the total running time...
2198 */
2199
2200 static double /* O - Number of seconds */
2201 run_time(void)
2202 {
2203 struct timeval curtime; /* Current time */
2204
2205
2206 gettimeofday(&curtime, NULL);
2207
2208 return (curtime.tv_sec - StartTime.tv_sec +
2209 0.000001 * (curtime.tv_usec - StartTime.tv_usec));
2210 }
2211
2212
2213 /*
2214 * 'scan_devices()' - Scan for devices using SNMP.
2215 */
2216
2217 static void
2218 scan_devices(int fd) /* I - SNMP socket */
2219 {
2220 char *address, /* Current address */
2221 *community; /* Current community */
2222 fd_set input; /* Input set for select() */
2223 struct timeval timeout; /* Timeout for select() */
2224 time_t endtime; /* End time for scan */
2225 http_addrlist_t *addrs, /* List of addresses */
2226 *addr; /* Current address */
2227 snmp_cache_t *device; /* Current device */
2228
2229
2230 /*
2231 * Setup the request IDs...
2232 */
2233
2234 gettimeofday(&StartTime, NULL);
2235
2236 DeviceTypeRequest = StartTime.tv_sec;
2237 DeviceDescRequest = StartTime.tv_sec + 1;
2238
2239 /*
2240 * First send all of the broadcast queries...
2241 */
2242
2243 for (address = (char *)cupsArrayFirst(Addresses);
2244 address;
2245 address = (char *)cupsArrayNext(Addresses))
2246 {
2247 if (!strcmp(address, "@LOCAL"))
2248 addrs = get_interface_addresses(NULL);
2249 else if (!strncmp(address, "@IF(", 4))
2250 {
2251 char ifname[255]; /* Interface name */
2252
2253
2254 strlcpy(ifname, address + 4, sizeof(ifname));
2255 if (ifname[0])
2256 ifname[strlen(ifname) - 1] = '\0';
2257
2258 addrs = get_interface_addresses(ifname);
2259 }
2260 else
2261 addrs = httpAddrGetList(address, AF_INET, NULL);
2262
2263 if (!addrs)
2264 {
2265 fprintf(stderr, "ERROR: Unable to scan \"%s\"!\n", address);
2266 continue;
2267 }
2268
2269 for (community = (char *)cupsArrayFirst(Communities);
2270 community;
2271 community = (char *)cupsArrayNext(Communities))
2272 {
2273 debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n",
2274 community, address);
2275
2276 for (addr = addrs; addr; addr = addr->next)
2277 send_snmp_query(fd, &(addr->addr), SNMP_VERSION_1, community,
2278 DeviceTypeRequest, DeviceTypeOID);
2279 }
2280
2281 httpAddrFreeList(addrs);
2282 }
2283
2284 /*
2285 * Then read any responses that come in over the next 3 seconds...
2286 */
2287
2288 endtime = time(NULL) + 3;
2289
2290 FD_ZERO(&input);
2291
2292 while (time(NULL) < endtime)
2293 {
2294 timeout.tv_sec = 1;
2295 timeout.tv_usec = 0;
2296
2297 FD_SET(fd, &input);
2298 if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
2299 {
2300 fprintf(stderr, "ERROR: %.3f select() for %d failed: %s\n", run_time(),
2301 fd, strerror(errno));
2302 break;
2303 }
2304
2305 if (FD_ISSET(fd, &input))
2306 read_snmp_response(fd);
2307 else
2308 break;
2309 }
2310
2311 /*
2312 * Finally, probe all of the printers we discovered to see how they are
2313 * connected...
2314 */
2315
2316 for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
2317 device;
2318 device = (snmp_cache_t *)cupsArrayNext(Devices))
2319 if (MaxRunTime > 0 && run_time() >= MaxRunTime)
2320 break;
2321 else if (!device->uri)
2322 probe_device(device);
2323
2324 debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
2325 }
2326
2327
2328 /*
2329 * 'send_snmp_query()' - Send an SNMP query packet.
2330 */
2331
2332 static void
2333 send_snmp_query(
2334 int fd, /* I - SNMP socket */
2335 http_addr_t *addr, /* I - Address to send to */
2336 int version, /* I - SNMP version */
2337 const char *community, /* I - Community name */
2338 const unsigned request_id, /* I - Request ID */
2339 const int *oid) /* I - OID */
2340 {
2341 int i; /* Looping var */
2342 snmp_packet_t packet; /* SNMP message packet */
2343 unsigned char buffer[SNMP_MAX_PACKET];/* SNMP message buffer */
2344 int bytes; /* Size of message */
2345 char addrname[32]; /* Address name */
2346
2347
2348 /*
2349 * Create the SNMP message...
2350 */
2351
2352 memset(&packet, 0, sizeof(packet));
2353
2354 packet.version = version;
2355 packet.request_type = ASN1_GET_REQUEST;
2356 packet.request_id = request_id;
2357 packet.object_type = ASN1_NULL_VALUE;
2358
2359 strlcpy(packet.community, community, sizeof(packet.community));
2360
2361 for (i = 0; oid[i]; i ++)
2362 packet.object_name[i] = oid[i];
2363
2364 bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);
2365
2366 if (bytes < 0)
2367 {
2368 fprintf(stderr, "ERROR: Unable to send SNMP query: %s\n", packet.error);
2369 return;
2370 }
2371
2372 /*
2373 * Send the message...
2374 */
2375
2376 debug_printf("DEBUG: %.3f Sending %d bytes to %s...\n", run_time(),
2377 bytes, httpAddrString(addr, addrname, sizeof(addrname)));
2378 if (DebugLevel > 1)
2379 asn1_debug(buffer, bytes, 0);
2380 if (DebugLevel > 2)
2381 hex_debug(buffer, bytes);
2382
2383 addr->ipv4.sin_port = htons(SNMP_PORT);
2384
2385 if (sendto(fd, buffer, bytes, 0, (void *)addr, sizeof(addr->ipv4)) < bytes)
2386 fprintf(stderr, "ERROR: Unable to send %d bytes to %s: %s\n",
2387 bytes, addrname, strerror(errno));
2388 }
2389
2390
2391 /*
2392 * 'try_connect()' - Try connecting on a port...
2393 */
2394
2395 static int /* O - 0 on success or -1 on error */
2396 try_connect(http_addr_t *addr, /* I - Socket address */
2397 const char *addrname, /* I - Hostname or IP address */
2398 int port) /* I - Port number */
2399 {
2400 int fd; /* Socket */
2401 int status; /* Connection status */
2402
2403
2404 debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(),
2405 port == 515 ? "lpd" : "socket", addrname, port);
2406
2407 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
2408 {
2409 fprintf(stderr, "ERROR: Unable to create socket: %s\n", strerror(errno));
2410 return (-1);
2411 }
2412
2413 addr->ipv4.sin_port = htons(port);
2414
2415 alarm(1);
2416
2417 status = connect(fd, (void *)addr, httpAddrLength(addr));
2418
2419 close(fd);
2420 alarm(0);
2421
2422 return (status);
2423 }
2424
2425
2426 /*
2427 * 'update_cache()' - Update a cached device...
2428 */
2429
2430 static void
2431 update_cache(snmp_cache_t *device, /* I - Device */
2432 const char *uri, /* I - Device URI */
2433 const char *id, /* I - Device ID */
2434 const char *make_model) /* I - Device make and model */
2435 {
2436 if (device->uri)
2437 free(device->uri);
2438
2439 device->uri = strdup(uri);
2440
2441 if (id)
2442 {
2443 if (device->id)
2444 free(device->id);
2445
2446 device->id = strdup(id);
2447 }
2448
2449 if (make_model)
2450 {
2451 if (device->make_and_model)
2452 free(device->make_and_model);
2453
2454 device->make_and_model = strdup(make_model);
2455 }
2456
2457 list_device(device);
2458 }
2459
2460
2461 /*
2462 * End of "$Id: snmp.c 6180 2007-01-03 18:19:32Z mike $".
2463 */