Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 78 additions & 32 deletions src/backend_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1477,8 +1477,8 @@ void print_socket(PrinterCUPS *p, int num_settings, GVariant *settings,

// Create the CUPS JOB
int job_id = 0;
if(cupsCreateDestJob(p->http, p->dest, p->dinfo, &job_id, title,
num_options, options) != IPP_STATUS_OK) {
if(cupsCreateDestJob(CUPS_HTTP_DEFAULT, p->dest, p->dinfo, &job_id, title,
num_options, options) != IPP_STATUS_OK) {
logwarn("job not created: %s\n" , cupsLastErrorString());
snprintf(error_msg, error_msg_len, "job not created: %s", cupsLastErrorString());
close(socket_fd);
Expand Down Expand Up @@ -1510,28 +1510,22 @@ void print_socket(PrinterCUPS *p, int num_settings, GVariant *settings,
return;
}

// start cups document
if(cupsStartDestDocument(p->http, p->dest, p->dinfo, job_id, title, CUPS_FORMAT_AUTO,
num_options, options, 1) != HTTP_STATUS_CONTINUE) {
logwarn("could not start document: %s\n", cupsLastErrorString());
close(socket_fd);
cupsFreeOptions(num_options, options);
return;
}

// Create a struct to pass data to the thread
// Create a struct to pass data to the thread
PrintDataThreadData *thread_data = g_malloc(sizeof(PrintDataThreadData));
thread_data->printer = p;
cupsCopyDest(p->dest, 0, &thread_data->dest);
thread_data->job_id = job_id;
thread_data->num_options = num_options;
thread_data->options = options;
thread_data->socket_fd = socket_fd;
thread_data->options = options;
thread_data->socket_fd = socket_fd;
snprintf(thread_data->title, sizeof(thread_data->title), "%s", title);

// Create a thread for handling data transfer to CUPS
pthread_t thread;
if (pthread_create(&thread, NULL, print_data_thread, thread_data) != 0) {
logwarn("Error creating thread");
close(socket_fd);
cupsFreeOptions(num_options, options);
cupsFreeDests(1, thread_data->dest);
g_free(thread_data);
} else {
// Detach the thread to allow it to run independently
Expand All @@ -1543,40 +1537,92 @@ void print_socket(PrinterCUPS *p, int num_settings, GVariant *settings,

static void *print_data_thread(void *data) {
PrintDataThreadData *thread_data = (PrintDataThreadData *)data;
char *buffer = g_malloc(65536);

/*
* Use CUPS_HTTP_DEFAULT so the CUPS library connects to cupsd via the
* Unix domain socket on this thread. The kernel then automatically
* vouches for our UID via peer credentials (SO_PEERCRED), satisfying
* the authenticated CUPS policy without needing a password or Kerberos
* ticket. Using p->http here would fail because that is a TCP connection
* where peer credential auth is impossible.
*/
cups_dinfo_t *dinfo = cupsCopyDestInfo(CUPS_HTTP_DEFAULT, thread_data->dest);
if (dinfo == NULL) {
logerror("print_data_thread: could not get dest info: %s\n",
cupsLastErrorString());
close(thread_data->socket_fd);
cupsFreeOptions(thread_data->num_options, thread_data->options);
cupsFreeDests(1, thread_data->dest);
g_free(buffer);
g_free(thread_data);
return NULL;
}

// Allocate dynamic memory for the buffer within the thread
char *buffer = g_malloc(1024);
/*
* cupsStartDestDocument begins a chunked HTTP POST on this thread's
* CUPS_HTTP_DEFAULT connection. cupsWriteRequestData and
* cupsFinishDestDocument must be called on the same thread to continue
* and finish that same HTTP POST — CUPS_HTTP_DEFAULT is per-thread
* (stored in _cups_globals_t), so mixing threads here would use a
* different connection and corrupt the stream.
*/
if (cupsStartDestDocument(CUPS_HTTP_DEFAULT,
thread_data->dest, dinfo,
thread_data->job_id,
thread_data->title,
CUPS_FORMAT_AUTO,
thread_data->num_options,
thread_data->options,
1) != HTTP_STATUS_CONTINUE) {
logerror("print_data_thread: could not start document: %s\n",
cupsLastErrorString());
cupsFreeDestInfo(dinfo);
close(thread_data->socket_fd);
cupsFreeOptions(thread_data->num_options, thread_data->options);
cupsFreeDests(1, thread_data->dest);
g_free(buffer);
g_free(thread_data);
return NULL;
}

//Accept incoming connections
/* Wait for the frontend to connect and start sending print data */
int client_fd = accept(thread_data->socket_fd, NULL, NULL);
if (client_fd == -1) {
logwarn("accept failed");
close(thread_data->socket_fd);
logwarn("print_data_thread: accept failed\n");
cupsFreeDestInfo(dinfo);
close(thread_data->socket_fd);
cupsFreeOptions(thread_data->num_options, thread_data->options);
cupsFreeDests(1, thread_data->dest);
g_free(buffer);
g_free(thread_data);
return NULL;
}

// Placeholder logic for reading data from the socket
ssize_t bytesRead;
while ((bytesRead = read(client_fd, buffer, 1024)) > 0) {
// Send data to CUPS using cupsWriteRequestData
http_status_t http_status = cupsWriteRequestData(thread_data->printer->http, buffer, bytesRead);
if (http_status != HTTP_STATUS_CONTINUE) {
logerror("Error writing print data to server.\n");
/* Read print data from the socket and forward it to CUPS */
ssize_t bytes_read;
while ((bytes_read = read(client_fd, buffer, 65536)) > 0) {
if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes_read)
!= HTTP_STATUS_CONTINUE) {
logerror("print_data_thread: error writing print data\n");
break;
}
}
close(client_fd);

// Cleanup and free resources
close(thread_data->socket_fd);
if (cupsFinishDestDocument(thread_data->printer->http, thread_data->printer->dest, thread_data->printer->dinfo) == IPP_STATUS_OK)
/* Finalise the document and report the result */
if (cupsFinishDestDocument(CUPS_HTTP_DEFAULT,
thread_data->dest, dinfo) == IPP_STATUS_OK)
logdebug("Document send succeeded.\n");
else
logerror("Document send failed: %s\n", cupsLastErrorString());

cupsFreeDestInfo(dinfo);
close(thread_data->socket_fd);
cupsFreeOptions(thread_data->num_options, thread_data->options);
g_free(thread_data);
cupsFreeDests(1, thread_data->dest);
g_free(buffer);

g_free(thread_data);
return NULL;
}

Expand Down
9 changes: 5 additions & 4 deletions src/backend_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,12 @@ typedef struct _Media
} Media;

typedef struct _PrintDataThreadData {
PrinterCUPS *printer;
int num_options;
cups_dest_t *dest;
int job_id;
int num_options;
cups_option_t *options;
int socket_fd;
struct sockaddr_un server_addr;
int socket_fd;
char title[256];
} PrintDataThreadData;

typedef struct _AddressList {
Expand Down
Loading