Introduction

The CUPS filter and backend APIs define standard exit codes and provide access to the backchannel data stream. They are only used when writing backends, filters, and port monitors.

General Usage

The <cups/backend.h> and <cups/cups.h> header files must be included to use the CUPS_BACKEND_ constants and cupsBackChannel functions, respectively.

The <cups/sidechannel.h> header file must be included to use the CUPS_SC_ constants and cupsSideChannel functions.

Programs using these functions must be linked to the CUPS library: libcups.a, libcups.so.2, libcups.2.dylib, libcups_s.a, or libcups2.lib depending on the platform. The following command compiles myprogram.c using GCC and the CUPS library:

gcc -o myprogram myprogram.c -lcups

Compatibility

The cupsBackChannel functions require CUPS 1.2 or higher. The cupsSideChannel functions require CUPS 1.3 or higher.

Using the cupsBackChannel APIs

The cupsBackChannel APIs allow your filters, drivers, and port monitors to read data back from a printer and your backends to send data from a printer to the filters, drivers, and port monitors associated with the current job. Back-channel data is normally sent by the printer in response to a command sent from your program to the printer via stdout.

The cupsBackChannelRead() function reads data from the printer via the backend. You provide a timeout in seconds along with a buffer pointer and the size of that buffer. It returns the number of bytes or -1 if there was an error. The following code example shows how to poll for back-channel data in your program:

#include <cups/cups.h>

char buffer[8192];
ssize_t bytes;

/* Use a timeout of 0.0 seconds to poll for back-channel data */
bytes = cupsBackChannelRead(buffer, sizeof(buffer), 0.0);

If you are writing a backend, the cupsBackChannelWrite() function sends any back-channel data you have received from the printer to upstream filters in the print filter chain. We recommend using a timeout of 1.0 seconds:

#include <cups/cups.h>

char buffer[8192];
ssize_t bytes;

/* Use a timeout of 1.0 seconds to give filters a chance to read */
cupsBackChannelWrite(buffer, bytes, 1.0);

Using the cupsSideChannel APIs

The cupsSideChannel APIs allow your filters, drivers, port monitors, and backend to send and receive the following out-of-band commands:

Sending Commands from a Filter, Driver, or Port Monitor

The cupsSideChannelDoRequest() function is used by filters, drivers, and port monitors to send a command to the backend and read back a response:

cups_sc_status_t cupsSideChannelDoRequest(cups_sc_command_t command,
                                          char *data, int *datalen,
                                          double timeout);

The CUPS_SC_CMD_SOFT_RESET and CUPS_SC_CMD_DRAIN_OUTPUT commands do not return any data values, while the others return one or more bytes. The timeout parameter allows your program to poll or wait for the command to complete - use a timeout of 30 seconds for CUPS_SC_CMD_SOFT_RESET and CUPS_SC_CMD_DRAIN_OUTPUT and a timeout of 1 second for all other commands.

CUPS_SC_CMD_GET_BIDI returns a single char value that tells you whether the backend supports bidirectional communications:

#include <cups/sidechannel.h>

char data;
int datalen;
cups_sc_bidi_t bidi;
cups_sc_status_t status;

/* Tell cupsSideChannelDoRequest() how big our buffer is... */
datalen = 1;

/* Get the bidirectional capabilities, waiting for up to 1 second */
status  = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, &data, &datalen, 1.0);

/* Use the returned value if OK was returned and the length is still 1 */
if (status == CUPS_SC_STATUS_OK && datalen == 1)
  bidi = (cups_sc_bidi_t)data;
else
  bidi = CUPS_SC_BIDI_NOT_SUPPORTED;

CUPS_SC_CMD_GET_DEVICE_ID returns a string of characters containing the IEEE-1284 device ID for the connected printer:

#include <cups/sidechannel.h>

char data[2049];
int datalen;
cups_sc_status_t status;

/* Tell cupsSideChannelDoRequest() how big our buffer is, less 1 byte for nul-termination... */
datalen = sizeof(data) - 1;

/* Get the IEEE-1284 device ID, waiting for up to 1 second */
status  = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_DEVICE_ID, data, &datalen, 1.0);

/* Use the returned value if OK was returned and the length is non-zero */
if (status == CUPS_SC_STATUS_OK && datalen > 0)
  data[datalen] = '\0';
else
  data[0] = '\0';

CUPS_SC_CMD_GET_STATE returns a single char value that tells you the current device state:

#include <cups/sidechannel.h>

char data;
int datalen;
cups_sc_state_t state;
cups_sc_status_t status;

/* Tell cupsSideChannelDoRequest() how big our buffer is... */
datalen = 1;

/* Get the bidirectional capabilities, waiting for up to 1 second */
status  = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_STATE, &data, &datalen, 1.0);

/* Use the returned value if OK was returned and the length is still 1 */
if (status == CUPS_SC_STATUS_OK && datalen == 1)
  state = (cups_sc_state_t)data;
else
  state = CUPS_SC_STATE_OFFLINE;

Handling Commands in your Backend

The cupsSideChannelRead() function is used by backends to read a command from a filter, driver, or port monitor:

int cupsSideChannelRead(cups_sc_command_t &command,
                        cups_sc_status_t  &status,
                        char *data, int *datalen, double timeout);

Backends can either poll for commands using a timeout of 0.0, wait indefinitely for commands using a timeout of -1.0 (probably in a separate thread for that purpose), or use select() or poll() on the CUPS_SC_FD file descriptor (4) to handle input and output on several file descriptors at the same time. Backends can pass NULL for the data and datalen parameters, since none of the commands sent by upstream filters contain any data at this time.

Once a command is processed, the backend uses the cupsSideChannelWrite() function to send its response:

#include <cups/sidechannel.h>

cups_sc_command_t command;
cups_sc_status_t status;

/* Poll for a command... */
if (!cupsSideChannelRead(&command, &status, NULL, NULL, 0.0))
{
  char data[2048];
  int datalen;

  switch (command)
  {
    ... handle supported commands, file data/datalen/status with values as needed ...

    default :
        status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
	datalen = 0;
	break;
  }

  /* Send a response... */
  cupsSideChannelWrite(command, status, data, datalen, 1.0);
}

Contents

Functions

 CUPS 1.2 cupsBackChannelRead()

Description

Read data from the backchannel.

Reads up to "bytes" bytes from the backchannel. The "timeout" parameter controls how many seconds to wait for the data - use 0.0 to return immediately if there is no data, -1.0 to wait for data indefinitely.

Syntax

ssize_t
cupsBackChannelRead( char * buffer, size_t bytes, double timeout);

Arguments

NameDescription
bufferBuffer to read
bytesBytes to read
timeoutTimeout in seconds

Returns

Bytes read or -1 on error

 CUPS 1.2 cupsBackChannelWrite()

Description

Write data to the backchannel.

Writes "bytes" bytes to the backchannel. The "timeout" parameter controls how many seconds to wait for the data to be written - use 0.0 to return immediately if the data cannot be written, -1.0 to wait indefinitely.

Syntax

ssize_t
cupsBackChannelWrite( const char * buffer, size_t bytes, double timeout);

Arguments

NameDescription
bufferBuffer to write
bytesBytes to write
timeoutTimeout in seconds

Returns

Bytes written or -1 on error

 CUPS 1.3 cupsSideChannelDoRequest()

Description

Send a side-channel command to a backend and wait for a response.

This function is normally only called by filters, drivers, or port monitors in order to communicate with the backend used by the current printer. Programs must be prepared to handle timeout or "not implemented" status codes, which indicate that the backend or device do not support the specified side-channel command.

The "datalen" parameter must be initialized to the size of the buffer pointed to by the "data" parameter. cupsSideChannelDoRequest() will update the value to contain the number of data bytes in the buffer.

Syntax

cups_sc_status_t
cupsSideChannelDoRequest( cups_sc_command_t command, char * data, int * datalen, double timeout);

Arguments

NameDescription
commandCommand to send
dataResponse data buffer pointer
datalenSize of data buffer on entry, number of bytes in buffer on return
timeoutTimeout in seconds

Returns

Status of command

 CUPS 1.3 cupsSideChannelRead()

Description

Read a side-channel message.

This function is normally only called by backend programs to read commands from a filter, driver, or port monitor program. The caller must be prepared to handle incomplete or invalid messages and return the corresponding status codes.

The "datalen" parameter must be initialized to the size of the buffer pointed to by the "data" parameter. cupsSideChannelDoRequest() will update the value to contain the number of data bytes in the buffer.

Syntax

int
cupsSideChannelRead( cups_sc_command_t * command, cups_sc_status_t * status, char * data, int * datalen, double timeout);

Arguments

NameDescription
commandCommand code
statusStatus code
dataData buffer pointer
datalenSize of data buffer on entry, number of bytes in buffer on return
timeoutTimeout in seconds

Returns

0 on success, -1 on error

 CUPS 1.3 cupsSideChannelWrite()

Description

Write a side-channel message.

This function is normally only called by backend programs to send responses to a filter, driver, or port monitor program.

Syntax

int
cupsSideChannelWrite( cups_sc_command_t command, cups_sc_status_t status, const char * data, int datalen, double timeout);

Arguments

NameDescription
commandCommand code
statusStatus code
dataData buffer pointer
datalenNumber of bytes of data
timeoutTimeout in seconds

Returns

0 on success, -1 on error