/*
- * "$Id: snmp.c 5736 2006-07-13 19:59:36Z mike $"
+ * "$Id: snmp.c 5898 2006-08-28 18:54:10Z mike $"
*
* SNMP discovery backend for the Common UNIX Printing System (CUPS).
*
* packed integer value.
* compare_cache() - Compare two cache entries.
* debug_printf() - Display some debugging information.
+ * do_request() - Do a non-blocking IPP request.
* fix_make_model() - Fix common problems in the make-and-model
* string.
* free_array() - Free an array of strings.
* get_interface_addresses() - Get the broadcast address(es) associated
* with an interface.
* hex_debug() - Output hex debugging data...
- * list_devices() - List all of the devices we found...
+ * list_device() - List a device we found...
* open_snmp_socket() - Open the SNMP broadcast socket.
* password_cb() - Handle authentication requests.
* probe_device() - Probe a device to discover whether it is a
} snmp_packet_t;
+/*
+ * Private CUPS API to set the last error...
+ */
+
+extern void _cupsSetError(ipp_status_t status, const char *message);
+
+
/*
* Local functions...
*/
static int asn1_size_packed(int integer);
static int compare_cache(snmp_cache_t *a, snmp_cache_t *b);
static void debug_printf(const char *format, ...);
+static ipp_t *do_request(http_t *http, ipp_t *request,
+ const char *resource);
static void fix_make_model(char *make_model,
const char *old_make_model,
int make_model_size);
static void free_cache(void);
static http_addrlist_t *get_interface_addresses(const char *ifname);
static void hex_debug(unsigned char *buffer, size_t len);
-static void list_devices(void);
+static void list_device(snmp_cache_t *cache);
static int open_snmp_socket(void);
static const char *password_cb(const char *prompt);
static void probe_device(snmp_cache_t *device);
static unsigned DeviceTypeRequest;
static unsigned DeviceDescRequest;
static int HostNameLookups = 0;
+static int MaxRunTime = 10;
static struct timeval StartTime;
char *argv[]) /* I - Command-line arguments */
{
int fd; /* SNMP socket */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
/*
cupsSetPasswordCB(password_cb);
+ /*
+ * Catch SIGALRM signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGALRM, alarm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGALRM);
+ action.sa_handler = alarm_handler;
+ sigaction(SIGALRM, &action, NULL);
+#else
+ signal(SIGALRM, alarm_handler);
+#endif /* HAVE_SIGSET */
+
/*
* Open the SNMP socket...
*/
scan_devices(fd);
- /*
- * Display the results...
- */
-
- list_devices();
-
/*
* Close, free, and return with no errors...
*/
debug_printf("DEBUG: add_cache(addr=%p, addrname=\"%s\", uri=\"%s\", "
"id=\"%s\", make_and_model=\"%s\")\n",
- addr, addrname, uri ? uri : "(null)", id ? id : "(null)",
+ addr, addrname, uri ? uri : "(null)", id ? id : "(null)",
make_and_model ? make_and_model : "(null)");
temp = calloc(1, sizeof(snmp_cache_t));
temp->make_and_model = strdup(make_and_model);
cupsArrayAdd(Devices, temp);
+
+ if (uri)
+ list_device(temp);
}
(void)sig;
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGALRM, alarm_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+
if (DebugLevel)
write(2, "DEBUG: ALARM!\n", 14);
}
}
+/*
+ * 'do_request()' - Do a non-blocking IPP request.
+ */
+
+static ipp_t * /* O - Response data or NULL */
+do_request(http_t *http, /* I - HTTP connection to server */
+ ipp_t *request, /* I - IPP request */
+ const char *resource) /* I - HTTP resource for POST */
+{
+ ipp_t *response; /* IPP response data */
+ http_status_t status; /* Status of HTTP request */
+ ipp_state_t state; /* State of IPP processing */
+
+
+ /*
+ * Setup the HTTP variables needed...
+ */
+
+ httpClearFields(http);
+ httpSetLength(http, ippLength(request));
+ httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
+
+ /*
+ * Do the POST request...
+ */
+
+ debug_printf("DEBUG: %.3f POST %s...\n", run_time(), resource);
+
+ if (httpPost(http, resource))
+ {
+ if (httpReconnect(http))
+ {
+ _cupsSetError(IPP_DEVICE_ERROR, "Unable to reconnect");
+ return (NULL);
+ }
+ else if (httpPost(http, resource))
+ {
+ _cupsSetError(IPP_GONE, "Unable to POST");
+ return (NULL);
+ }
+ }
+
+ /*
+ * Send the IPP data...
+ */
+
+ request->state = IPP_IDLE;
+ status = HTTP_CONTINUE;
+
+ while ((state = ippWrite(http, request)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+ else if (httpCheck(http))
+ {
+ if ((status = httpUpdate(http)) != HTTP_CONTINUE)
+ break;
+ }
+
+ /*
+ * Get the server's return status...
+ */
+
+ debug_printf("DEBUG: %.3f Getting response...\n", run_time());
+
+ while (status == HTTP_CONTINUE)
+ if (httpWait(http, 1000))
+ status = httpUpdate(http);
+ else
+ {
+ status = HTTP_ERROR;
+ http->error = ETIMEDOUT;
+ }
+
+ if (status != HTTP_OK)
+ {
+ /*
+ * Flush any error message...
+ */
+
+ httpFlush(http);
+ response = NULL;
+ }
+ else
+ {
+ /*
+ * Read the response...
+ */
+
+ response = ippNew();
+
+ while ((state = ippRead(http, response)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ {
+ /*
+ * Delete the response...
+ */
+
+ ippDelete(response);
+ response = NULL;
+
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
+ break;
+ }
+ }
+
+ /*
+ * Delete the original request and return the response...
+ */
+
+ ippDelete(request);
+
+ if (response)
+ {
+ ipp_attribute_t *attr; /* status-message attribute */
+
+
+ attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
+
+ _cupsSetError(response->request.status.status_code,
+ attr ? attr->values[0].string.text :
+ ippErrorString(response->request.status.status_code));
+ }
+ else if (status != HTTP_OK)
+ {
+ switch (status)
+ {
+ case HTTP_NOT_FOUND :
+ _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
+ break;
+
+ case HTTP_UNAUTHORIZED :
+ _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
+ break;
+
+ case HTTP_FORBIDDEN :
+ _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
+ break;
+
+ case HTTP_BAD_REQUEST :
+ _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
+ break;
+
+ case HTTP_REQUEST_TOO_LARGE :
+ _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
+ break;
+
+ case HTTP_NOT_IMPLEMENTED :
+ _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
+ break;
+
+ case HTTP_NOT_SUPPORTED :
+ _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
+ break;
+
+ default :
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
+ break;
+ }
+ }
+
+ return (response);
+}
+
+
/*
* 'fix_make_model()' - Fix common problems in the make-and-model string.
*/
_cups_strcpy(mmptr, mmptr + 7);
}
+ if ((mmptr = strstr(make_model, " Network")) != NULL)
+ {
+ /*
+ * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
+ * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
+ */
+
+ *mmptr = '\0';
+ }
+
if ((mmptr = strchr(make_model, ',')) != NULL)
{
/*
/*
- * 'list_devices()' - List all of the devices we found...
+ * 'list_device()' - List a device we found...
*/
static void
-list_devices(void)
+list_device(snmp_cache_t *cache) /* I - Cached device */
{
- snmp_cache_t *cache; /* Cached device */
-
-
- for (cache = (snmp_cache_t *)cupsArrayFirst(Devices);
- cache;
- cache = (snmp_cache_t *)cupsArrayNext(Devices))
- if (cache->uri)
- printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
- cache->uri,
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->addrname, cache->id ? cache->id : "");
+ if (cache->uri)
+ printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
+ cache->uri,
+ cache->make_and_model ? cache->make_and_model : "Unknown",
+ cache->make_and_model ? cache->make_and_model : "Unknown",
+ cache->addrname, cache->id ? cache->id : "");
}
debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);
- if ((http = httpConnect(device->addrname, 631)) != NULL)
+ if (device->make_and_model &&
+ (!strncasecmp(device->make_and_model, "Xerox", 5) ||
+ !strncasecmp(device->make_and_model, "Kyocera", 7)))
+ {
+ /*
+ * Xerox and Kyocera printers often lock up on IPP probes, so exclude
+ * them from the IPP connection test...
+ */
+
+ http = NULL;
+ }
+ else
+ {
+ /*
+ * Otherwise, try connecting for up to 1 second...
+ */
+
+ alarm(1);
+ http = httpConnect(device->addrname, 631);
+ alarm(0);
+ }
+
+ if (http);
{
/*
* IPP is supported...
};
- debug_printf("DEBUG: %s supports IPP!\n", device->addrname);
-
/*
* Use non-blocking IO...
*/
i < (int)(sizeof(resources) / sizeof(resources[0]));
i ++)
{
+ /*
+ * Stop early if we are out of time...
+ */
+
+ if (MaxRunTime > 0 && run_time() >= MaxRunTime)
+ break;
+
/*
* Don't look past /ipp if we have found a working URI...
*/
httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
device->addrname, 631, resources[i]);
- debug_printf("DEBUG: Trying %s (num_uris=%d)\n", uri, num_uris);
-
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
NULL, uri);
- response = cupsDoRequest(http, request, resources[i]);
+ response = do_request(http, request, resources[i]);
- debug_printf("DEBUG: %s %s (%s)\n", uri,
+ debug_printf("DEBUG: %.3f %s %s (%s)\n", run_time(), uri,
ippErrorString(cupsLastError()), cupsLastErrorString());
if (response && response->request.status.status_code == IPP_OK)
int linenum; /* Line number */
const char *cups_serverroot; /* CUPS_SERVERROOT env var */
const char *debug; /* CUPS_DEBUG_LEVEL env var */
+ const char *runtime; /* CUPS_MAX_RUN_TIME env var */
/*
if ((debug = getenv("CUPS_DEBUG_LEVEL")) != NULL)
DebugLevel = atoi(debug);
+ if ((runtime = getenv("CUPS_MAX_RUN_TIME")) != NULL)
+ MaxRunTime = atoi(runtime);
+
/*
* Find the snmp.conf file...
*/
!strcasecmp(value, "yes") ||
!strcasecmp(value, "true") ||
!strcasecmp(value, "double");
+ else if (!strcasecmp(line, "MaxRunTime"))
+ MaxRunTime = atoi(value);
else
fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n",
line, linenum, filename);
for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
device;
device = (snmp_cache_t *)cupsArrayNext(Devices))
- if (!device->uri)
+ if (MaxRunTime > 0 && run_time() >= MaxRunTime)
+ break;
+ else if (!device->uri)
probe_device(device);
debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
addr->ipv4.sin_port = htons(port);
- signal(SIGALRM, alarm_handler);
alarm(1);
status = connect(fd, (void *)addr, httpAddrLength(addr));
device->make_and_model = strdup(make_model);
}
+
+ list_device(device);
}
/*
- * End of "$Id: snmp.c 5736 2006-07-13 19:59:36Z mike $".
+ * End of "$Id: snmp.c 5898 2006-08-28 18:54:10Z mike $".
*/