cups_array_t *ra,
cups_array_t *exclude);
static void create_job(cupsd_client_t *con, ipp_attribute_t *uri);
-static void *create_local_bg_thread(cupsd_printer_t *printer);
+static void *create_local_bg_thread(cupsd_client_t *con);
static void create_local_printer(cupsd_client_t *con);
static cups_array_t *create_requested_array(ipp_t *request);
static void create_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
static void send_http_error(cupsd_client_t *con, http_status_t status,
cupsd_printer_t *printer);
static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4);
+static int send_response(cupsd_client_t *con);
static void set_default(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
}
}
- if (con->response)
+ if (!con->bg_pending && con->response)
{
/*
* Sending data from the scheduler...
*/
- cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname);
-
- httpClearFields(con->http);
-
-#ifdef CUPSD_USE_CHUNKING
- /*
- * Because older versions of CUPS (1.1.17 and older) and some IPP
- * clients do not implement chunking properly, we cannot use
- * chunking by default. This may become the default in future
- * CUPS releases, or we might add a configuration directive for
- * it.
- */
-
- if (con->http->version == HTTP_1_1)
- {
- cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked");
- cupsdSetLength(con->http, 0);
- }
- else
-#endif /* CUPSD_USE_CHUNKING */
- {
- size_t length; /* Length of response */
-
-
- length = ippLength(con->response);
-
- if (con->file >= 0 && !con->pipe_pid)
- {
- struct stat fileinfo; /* File information */
-
- if (!fstat(con->file, &fileinfo))
- length += (size_t)fileinfo.st_size;
- }
-
- cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length);
- httpSetLength(con->http, length);
- }
-
- if (cupsdSendHeader(con, HTTP_STATUS_OK, "application/ipp", CUPSD_AUTH_NONE))
- {
- /*
- * Tell the caller the response header was sent successfully...
- */
-
- cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con);
-
- return (1);
- }
- else
- {
- /*
- * Tell the caller the response header could not be sent...
- */
-
- return (0);
- }
+ return (send_response(con));
}
else
{
return;
}
- // Run a background thread to create the PPD...
- cupsThreadCreate((cups_thread_func_t)create_local_bg_thread, printer);
+ if (!printer->printer_id)
+ printer->printer_id = NextPrinterId ++;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ cupsdSetPrinterAttrs(printer);
+
+ /* Run a background thread to create the PPD... */
+ cupsdLogClient(con, CUPSD_LOG_DEBUG, "Creating PPD in background thread.");
+
+ con->bg_pending = 1;
+ con->bg_printer = printer;
+
+ cupsThreadCreate((cups_thread_func_t)create_local_bg_thread, con);
+ return;
}
else if (!strcmp(ppd_name, "raw"))
{
static void * /* O - Exit status */
create_local_bg_thread(
- cupsd_printer_t *printer) /* I - Printer */
+ cupsd_client_t *con) /* I - Client */
{
+ cupsd_printer_t *printer = con->bg_printer;
+ /* Printer */
cups_file_t *from, /* Source file */
*to; /* Destination file */
- char fromppd[1024], /* Source PPD */
+ char device_uri[1024], /* Device URI */
+ fromppd[1024], /* Source PPD */
toppd[1024], /* Destination PPD */
scheme[32], /* URI scheme */
userpass[256], /* User:pass */
http_encryption_t encryption; /* Type of encryption to use */
http_t *http; /* Connection to printer */
ipp_t *request, /* Request to printer */
- *response; /* Response from printer */
+ *response = NULL; /* Response from printer */
ipp_attribute_t *attr; /* Attribute in response */
ipp_status_t status; /* Status code */
static const char * const pattrs[] = /* Printer attributes we need */
* Try connecting to the printer...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri);
+ cupsRWLockRead(&printer->lock);
+ cupsCopyString(device_uri, printer->device_uri, sizeof(device_uri));
+ cupsRWUnlock(&printer->lock);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, device_uri);
- if (strstr(printer->device_uri, "._tcp"))
+ if (strstr(device_uri, "._tcp"))
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s: Resolving mDNS URI \"%s\".", printer->name, printer->device_uri);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s: Resolving mDNS URI \"%s\".", printer->name, device_uri);
- if (!httpResolveURI(printer->device_uri, uri, sizeof(uri), HTTP_RESOLVE_DEFAULT, NULL, NULL))
+ if (!httpResolveURI(device_uri, uri, sizeof(uri), HTTP_RESOLVE_DEFAULT, NULL, NULL))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Couldn't resolve mDNS URI \"%s\".", printer->name, printer->device_uri);
- return (NULL);
+
+ /* Force printer to timeout and be deleted */
+ cupsRWLockWrite(&printer->lock);
+ printer->state_time = 0;
+ cupsRWUnlock(&printer->lock);
+
+ send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Couldn't resolve mDNS URI \"%s\"."), printer->device_uri);
+ goto finish_response;
}
+ cupsRWLockWrite(&printer->lock);
cupsdSetString(&printer->device_uri, uri);
+ cupsRWUnlock(&printer->lock);
+
+ cupsCopyString(device_uri, uri, sizeof(device_uri));
}
- if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri);
- return (NULL);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, device_uri);
+
+ /* Force printer to timeout and be deleted */
+ cupsRWLockWrite(&printer->lock);
+ printer->state_time = 0;
+ cupsRWUnlock(&printer->lock);
+
+ send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Bad device URI \"%s\"."), device_uri);
+ goto finish_response;
}
if (!strcmp(scheme, "ipps") || port == 443)
if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsGetErrorString());
- return (NULL);
+
+ /* Force printer to timeout and be deleted */
+ cupsRWLockWrite(&printer->lock);
+ printer->state_time = 0;
+ cupsRWUnlock(&printer->lock);
+
+ send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to connect to %s:%d: %s"), host, port, cupsGetErrorString());
+ goto finish_response;
}
/*
* If we did not succeed to obtain the "media-col-database" attribute
* try to get it separately
*/
+
if (ippFindAttribute(response, "media-col-database", IPP_TAG_ZERO) ==
NULL)
{
if ((from = cupsFileOpen(fromppd, "r")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno));
- ippDelete(response);
- return (NULL);
+
+ /* Force printer to timeout and be deleted */
+ cupsRWLockWrite(&printer->lock);
+ printer->state_time = 0;
+ cupsRWUnlock(&printer->lock);
+
+ send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to read generated PPD: %s"), strerror(errno));
+ goto finish_response;
}
snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name);
if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno));
- ippDelete(response);
cupsFileClose(from);
- return (NULL);
+
+ /* Force printer to timeout and be deleted */
+ cupsRWLockWrite(&printer->lock);
+ printer->state_time = 0;
+ cupsRWUnlock(&printer->lock);
+
+ send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to create PPD for printer: %s"), strerror(errno));
+ goto finish_response;
}
while (cupsFileGets(from, line, sizeof(line)))
cupsFileClose(from);
if (!cupsdCloseCreatedConfFile(to, toppd))
{
+ cupsRWLockWrite(&printer->lock);
+
printer->config_time = time(NULL);
printer->state = IPP_PSTATE_IDLE;
printer->accepting = 1;
+ cupsRWUnlock(&printer->lock);
+
cupsdSetPrinterAttrs(printer);
cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name);
}
}
else
+ {
cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed: %s", printer->name, cupsGetErrorString());
+ /* Force printer to timeout and be deleted */
+ cupsRWLockWrite(&printer->lock);
+ printer->state_time = 0;
+ cupsRWUnlock(&printer->lock);
+
+ send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to create PPD: %s"), cupsGetErrorString());
+ goto finish_response;
+ }
+
+ /*
+ * Respond to the client...
+ */
+
+ send_ipp_status(con, IPP_STATUS_OK, _("Local printer created."));
+
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", (int)printer->state);
+ add_printer_state_reasons(con, printer);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
+
+ finish_response:
+
ippDelete(response);
+ con->bg_pending = 0;
+
+ send_response(con);
+
return (NULL);
}
* Run a background thread to create the PPD...
*/
- cupsThreadCreate((cups_thread_func_t)create_local_bg_thread, printer);
+ con->bg_pending = 1;
+ con->bg_printer = printer;
+
+ cupsThreadCreate((cups_thread_func_t)create_local_bg_thread, con);
+
+ return;
/*
* Return printer attributes...
*/
- send_ipp_status(con, IPP_STATUS_OK, _("Local printer created."));
-
add_printer_attributes:
ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
}
+/*
+ * 'send_response()' - Send the IPP response.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+send_response(cupsd_client_t *con) /* I - Client */
+{
+ ipp_attribute_t *uri; /* Target URI */
+ int ret = 0; /* Return value */
+ static cups_mutex_t mutex = CUPS_MUTEX_INITIALIZER;
+ /* Mutex for logging/access */
+
+
+ cupsMutexLock(&mutex);
+
+ if ((uri = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) == NULL)
+ {
+ if ((uri = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) == NULL)
+ uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME);
+ }
+
+ cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname);
+
+ httpClearFields(con->http);
+
+#ifdef CUPSD_USE_CHUNKING
+ /*
+ * Because older versions of CUPS (1.1.17 and older) and some IPP
+ * clients do not implement chunking properly, we cannot use
+ * chunking by default. This may become the default in future
+ * CUPS releases, or we might add a configuration directive for
+ * it.
+ */
+
+ if (con->http->version == HTTP_1_1)
+ {
+ cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked");
+ cupsdSetLength(con->http, 0);
+ }
+ else
+#endif /* CUPSD_USE_CHUNKING */
+ {
+ size_t length; /* Length of response */
+
+
+ length = ippLength(con->response);
+
+ if (con->file >= 0 && !con->pipe_pid)
+ {
+ struct stat fileinfo; /* File information */
+
+ if (!fstat(con->file, &fileinfo))
+ length += (size_t)fileinfo.st_size;
+ }
+
+ cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length);
+ httpSetLength(con->http, length);
+ }
+
+ if (cupsdSendHeader(con, HTTP_STATUS_OK, "application/ipp", CUPSD_AUTH_NONE))
+ {
+ /*
+ * Tell the caller the response header was sent successfully...
+ */
+
+ cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con);
+
+ ret = 1;
+ }
+
+ cupsMutexUnlock(&mutex);
+
+ return (ret);
+}
+
+
/*
* 'set_default()' - Set the default destination...
*/