4 * Common network APIs for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * "LICENSE" which should have been included with this file. If this
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
22 * Include necessary headers.
25 #include "backend-private.h"
28 # include <sys/time.h>
30 # include <sys/select.h>
34 #endif /* HAVE_DNSSD */
42 static void resolve_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
,
43 uint32_t interfaceIndex
,
44 DNSServiceErrorType errorCode
,
45 const char *fullName
, const char *hostTarget
,
46 uint16_t port
, uint16_t txtLen
,
47 const unsigned char *txtRecord
, void *context
);
48 #endif /* HAVE_DNSSD */
52 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
57 backendCheckSideChannel(
58 int snmp_fd
, /* I - SNMP socket */
59 http_addr_t
*addr
) /* I - Address of device */
61 fd_set input
; /* Select input set */
62 struct timeval timeout
; /* Select timeout */
66 FD_SET(CUPS_SC_FD
, &input
);
68 timeout
.tv_sec
= timeout
.tv_usec
= 0;
70 if (select(CUPS_SC_FD
+ 1, &input
, NULL
, NULL
, &timeout
) > 0)
71 backendNetworkSideCB(-1, -1, snmp_fd
, addr
, 0);
76 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
81 int print_fd
, /* I - Print file or -1 */
82 int device_fd
, /* I - Device file or -1 */
83 int snmp_fd
, /* I - SNMP socket */
84 http_addr_t
*addr
, /* I - Address of device */
85 int use_bc
) /* I - Use back-channel data? */
87 cups_sc_command_t command
; /* Request command */
88 cups_sc_status_t status
; /* Request/response status */
89 char data
[2048]; /* Request/response data */
90 int datalen
; /* Request/response data size */
91 const char *device_id
; /* 1284DEVICEID env var */
94 datalen
= sizeof(data
);
96 if (cupsSideChannelRead(&command
, &status
, data
, &datalen
, 1.0))
98 _cupsLangPuts(stderr
, _("WARNING: Failed to read side-channel request!\n"));
104 case CUPS_SC_CMD_DRAIN_OUTPUT
:
106 * Our sockets disable the Nagle algorithm and data is sent immediately.
110 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
111 else if (backendDrainOutput(print_fd
, device_fd
))
112 status
= CUPS_SC_STATUS_IO_ERROR
;
114 status
= CUPS_SC_STATUS_OK
;
119 case CUPS_SC_CMD_GET_BIDI
:
124 case CUPS_SC_CMD_GET_DEVICE_ID
:
127 cups_snmp_t packet
; /* Packet from printer */
128 static const int ppmPrinterIEEE1284DeviceId
[] =
129 { CUPS_OID_ppmPrinterIEEE1284DeviceId
,1,-1 };
131 if (_cupsSNMPWrite(snmp_fd
, addr
, 1, _cupsSNMPDefaultCommunity(),
132 CUPS_ASN1_GET_REQUEST
, 1,
133 ppmPrinterIEEE1284DeviceId
))
135 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0) &&
136 packet
.object_type
== CUPS_ASN1_OCTET_STRING
)
138 strlcpy(data
, packet
.object_value
.string
, sizeof(data
));
139 datalen
= (int)strlen(data
);
145 if ((device_id
= getenv("1284DEVICEID")) != NULL
)
147 strlcpy(data
, device_id
, sizeof(data
));
148 datalen
= (int)strlen(data
);
153 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
158 cupsSideChannelWrite(command
, status
, data
, datalen
, 1.0);
163 * 'backendResolveURI()' - Get the device URI, resolving as needed.
166 const char * /* O - Device URI */
167 backendResolveURI(char **argv
) /* I - Command-line arguments */
169 const char *uri
; /* Device URI */
170 char scheme
[32], /* URI components... */
175 http_uri_status_t status
; /* URI decode status */
178 * Get the device URI...
181 uri
= cupsBackendDeviceURI(argv
);
183 if ((status
= httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
,
184 sizeof(scheme
), userpass
, sizeof(userpass
),
185 hostname
, sizeof(hostname
), &port
,
186 resource
, sizeof(resource
))) < HTTP_URI_OK
)
188 fprintf(stderr
, "ERROR: Bad device URI \"%s\" (%d)!\n", uri
, status
);
189 exit (CUPS_BACKEND_STOP
);
193 * Resolve it as needed...
196 if (strstr(hostname
, "._tcp"))
199 DNSServiceRef ref
; /* DNS-SD service reference */
200 char *regtype
, /* Pointer to type in hostname */
201 *domain
; /* Pointer to domain in hostname */
202 static char resolved_uri
[HTTP_MAX_URI
];
203 /* Resolved device URI */
206 * Separate the hostname into service name, registration type, and domain...
209 regtype
= strchr(hostname
, '.');
212 domain
= regtype
+ strlen(regtype
) - 1;
213 if (domain
> regtype
&& *domain
== '.')
216 for (domain
= strchr(regtype
, '.');
218 domain
= strchr(domain
+ 1, '.'))
219 if (domain
[1] != '_')
226 "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
227 hostname
, regtype
, domain
? domain
: "(null)");
229 if (DNSServiceResolve(&ref
, 0, 0, hostname
, regtype
, domain
,
231 resolved_uri
) == kDNSServiceErr_NoError
)
233 if (DNSServiceProcessResult(ref
) != kDNSServiceErr_NoError
)
238 DNSServiceRefDeallocate(ref
);
241 #endif /* HAVE_DNSSD */
247 fprintf(stderr
, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri
);
248 exit(CUPS_BACKEND_STOP
);
258 * 'resolve_callback()' - Build a device URI for the given service name.
263 DNSServiceRef sdRef
, /* I - Service reference */
264 DNSServiceFlags flags
, /* I - Results flags */
265 uint32_t interfaceIndex
, /* I - Interface number */
266 DNSServiceErrorType errorCode
, /* I - Error, if any */
267 const char *fullName
, /* I - Full service name */
268 const char *hostTarget
, /* I - Hostname */
269 uint16_t port
, /* I - Port number */
270 uint16_t txtLen
, /* I - Length of TXT record */
271 const unsigned char *txtRecord
, /* I - TXT record data */
272 void *context
) /* I - Pointer to URI buffer */
274 const char *scheme
; /* URI scheme */
275 char rp
[257]; /* Remote printer */
276 const void *value
; /* Value from TXT record */
277 uint8_t valueLen
; /* Length of value */
281 "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
282 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
283 "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef
, flags
,
284 interfaceIndex
, errorCode
, fullName
, hostTarget
, port
, txtLen
,
288 * Figure out the scheme from the full name...
291 if (strstr(fullName
, "._ipp"))
293 else if (strstr(fullName
, "._printer."))
295 else if (strstr(fullName
, "._pdl-datastream."))
298 scheme
= "riousbprint";
301 * Extract the "remote printer" key from the TXT record...
304 if ((value
= TXTRecordGetValuePtr(txtLen
, txtRecord
, "rp",
308 * Convert to resource by concatenating with a leading "/"...
312 memcpy(rp
, value
, valueLen
);
313 rp
[valueLen
+ 1] = '\0';
319 * Assemble the final device URI...
322 httpAssembleURI(HTTP_URI_CODING_ALL
, (char *)context
, HTTP_MAX_URI
, scheme
,
323 NULL
, hostTarget
, ntohs(port
), rp
);
325 fprintf(stderr
, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context
);
327 #endif /* HAVE_DNSSD */
336 * Common network APIs for the Common UNIX Printing System (CUPS).
338 * Copyright 2007-2008 by Apple Inc.
339 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
341 * These coded instructions, statements, and computer programs are the
342 * property of Apple Inc. and are protected by Federal copyright
343 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
344 * "LICENSE" which should have been included with this file. If this
345 * file is missing or damaged, see the license at "http://www.cups.org/".
347 * This file is subject to the Apple OS-Developed Software exception.
354 * Include necessary headers.
357 #include "backend-private.h"
360 # include <sys/time.h>
362 # include <sys/select.h>
366 #endif /* HAVE_DNSSD */
374 static void resolve_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
,
375 uint32_t interfaceIndex
,
376 DNSServiceErrorType errorCode
,
377 const char *fullName
, const char *hostTarget
,
378 uint16_t port
, uint16_t txtLen
,
379 const unsigned char *txtRecord
, void *context
);
380 #endif /* HAVE_DNSSD */
384 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
389 backendCheckSideChannel(
390 int snmp_fd
, /* I - SNMP socket */
391 http_addr_t
*addr
) /* I - Address of device */
393 fd_set input
; /* Select input set */
394 struct timeval timeout
; /* Select timeout */
398 FD_SET(CUPS_SC_FD
, &input
);
400 timeout
.tv_sec
= timeout
.tv_usec
= 0;
402 if (select(CUPS_SC_FD
+ 1, &input
, NULL
, NULL
, &timeout
) > 0)
403 backendNetworkSideCB(-1, -1, snmp_fd
, addr
, 0);
408 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
412 backendNetworkSideCB(
413 int print_fd
, /* I - Print file or -1 */
414 int device_fd
, /* I - Device file or -1 */
415 int snmp_fd
, /* I - SNMP socket */
416 http_addr_t
*addr
, /* I - Address of device */
417 int use_bc
) /* I - Use back-channel data? */
419 cups_sc_command_t command
; /* Request command */
420 cups_sc_status_t status
; /* Request/response status */
421 char data
[2048]; /* Request/response data */
422 int datalen
; /* Request/response data size */
423 const char *device_id
; /* 1284DEVICEID env var */
426 datalen
= sizeof(data
);
428 if (cupsSideChannelRead(&command
, &status
, data
, &datalen
, 1.0))
430 _cupsLangPuts(stderr
, _("WARNING: Failed to read side-channel request!\n"));
436 case CUPS_SC_CMD_DRAIN_OUTPUT
:
438 * Our sockets disable the Nagle algorithm and data is sent immediately.
442 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
443 else if (backendDrainOutput(print_fd
, device_fd
))
444 status
= CUPS_SC_STATUS_IO_ERROR
;
446 status
= CUPS_SC_STATUS_OK
;
451 case CUPS_SC_CMD_GET_BIDI
:
456 case CUPS_SC_CMD_GET_DEVICE_ID
:
459 cups_snmp_t packet
; /* Packet from printer */
460 static const int ppmPrinterIEEE1284DeviceId
[] =
461 { CUPS_OID_ppmPrinterIEEE1284DeviceId
,1,-1 };
463 if (_cupsSNMPWrite(snmp_fd
, addr
, 1, _cupsSNMPDefaultCommunity(),
464 CUPS_ASN1_GET_REQUEST
, 1,
465 ppmPrinterIEEE1284DeviceId
))
467 if (_cupsSNMPRead(snmp_fd
, &packet
, 1.0) &&
468 packet
.object_type
== CUPS_ASN1_OCTET_STRING
)
470 strlcpy(data
, packet
.object_value
.string
, sizeof(data
));
471 datalen
= (int)strlen(data
);
477 if ((device_id
= getenv("1284DEVICEID")) != NULL
)
479 strlcpy(data
, device_id
, sizeof(data
));
480 datalen
= (int)strlen(data
);
485 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
490 cupsSideChannelWrite(command
, status
, data
, datalen
, 1.0);
495 * 'backendResolveURI()' - Get the device URI, resolving as needed.
498 const char * /* O - Device URI */
499 backendResolveURI(char **argv
) /* I - Command-line arguments */
501 const char *uri
; /* Device URI */
502 char scheme
[32], /* URI components... */
507 http_uri_status_t status
; /* URI decode status */
510 * Get the device URI...
513 uri
= cupsBackendDeviceURI(argv
);
515 if ((status
= httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
,
516 sizeof(scheme
), userpass
, sizeof(userpass
),
517 hostname
, sizeof(hostname
), &port
,
518 resource
, sizeof(resource
))) < HTTP_URI_OK
)
520 fprintf(stderr
, "ERROR: Bad device URI \"%s\" (%d)!\n", uri
, status
);
521 exit (CUPS_BACKEND_STOP
);
525 * Resolve it as needed...
528 if (strstr(hostname
, "._tcp"))
531 DNSServiceRef ref
; /* DNS-SD service reference */
532 char *regtype
, /* Pointer to type in hostname */
533 *domain
; /* Pointer to domain in hostname */
534 static char resolved_uri
[HTTP_MAX_URI
];
535 /* Resolved device URI */
538 * Separate the hostname into service name, registration type, and domain...
541 regtype
= strchr(hostname
, '.');
544 domain
= regtype
+ strlen(regtype
) - 1;
545 if (domain
> regtype
&& *domain
== '.')
548 for (domain
= strchr(regtype
, '.');
550 domain
= strchr(domain
+ 1, '.'))
551 if (domain
[1] != '_')
558 "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
559 hostname
, regtype
, domain
? domain
: "(null)");
561 if (DNSServiceResolve(&ref
, 0, 0, hostname
, regtype
, domain
,
563 resolved_uri
) == kDNSServiceErr_NoError
)
565 if (DNSServiceProcessResult(ref
) != kDNSServiceErr_NoError
)
570 DNSServiceRefDeallocate(ref
);
573 #endif /* HAVE_DNSSD */
579 fprintf(stderr
, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri
);
580 exit(CUPS_BACKEND_STOP
);
590 * 'resolve_callback()' - Build a device URI for the given service name.
595 DNSServiceRef sdRef
, /* I - Service reference */
596 DNSServiceFlags flags
, /* I - Results flags */
597 uint32_t interfaceIndex
, /* I - Interface number */
598 DNSServiceErrorType errorCode
, /* I - Error, if any */
599 const char *fullName
, /* I - Full service name */
600 const char *hostTarget
, /* I - Hostname */
601 uint16_t port
, /* I - Port number */
602 uint16_t txtLen
, /* I - Length of TXT record */
603 const unsigned char *txtRecord
, /* I - TXT record data */
604 void *context
) /* I - Pointer to URI buffer */
606 const char *scheme
; /* URI scheme */
607 char rp
[257]; /* Remote printer */
608 const void *value
; /* Value from TXT record */
609 uint8_t valueLen
; /* Length of value */
613 "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
614 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
615 "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef
, flags
,
616 interfaceIndex
, errorCode
, fullName
, hostTarget
, port
, txtLen
,
620 * Figure out the scheme from the full name...
623 if (strstr(fullName
, "._ipp"))
625 else if (strstr(fullName
, "._printer."))
627 else if (strstr(fullName
, "._pdl-datastream."))
630 scheme
= "riousbprint";
633 * Extract the "remote printer" key from the TXT record...
636 if ((value
= TXTRecordGetValuePtr(txtLen
, txtRecord
, "rp",
640 * Convert to resource by concatenating with a leading "/"...
644 memcpy(rp
, value
, valueLen
);
645 rp
[valueLen
+ 1] = '\0';
651 * Assemble the final device URI...
654 httpAssembleURI(HTTP_URI_CODING_ALL
, (char *)context
, HTTP_MAX_URI
, scheme
,
655 NULL
, hostTarget
, ntohs(port
), rp
);
657 fprintf(stderr
, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context
);
659 #endif /* HAVE_DNSSD */