]>
Commit | Line | Data |
---|---|---|
7a14d768 MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * Common network APIs for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 2007-2008 by Apple Inc. | |
7 | * Copyright 2006-2007 by Easy Software Products, all rights reserved. | |
8 | * | |
9 | * These coded instructions, statements, and computer programs are the | |
10 | * property of Apple Inc. and are protected by Federal copyright | |
7a14d768 MS |
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/". | |
14 | * | |
15 | * This file is subject to the Apple OS-Developed Software exception. | |
16 | * | |
17 | * Contents: | |
18 | * | |
a0f6818e MS |
19 | * backendCheckSideChannel() - Check the side-channel for pending requests. |
20 | * backendNetworkSideCB() - Handle common network side-channel commands. | |
21 | * backendResolveURI() - Get the device URI, resolving as needed. | |
22 | * resolve_callback() - Build a device URI for the given service name. | |
7a14d768 MS |
23 | */ |
24 | ||
25 | /* | |
26 | * Include necessary headers. | |
27 | */ | |
28 | ||
29 | #include "backend-private.h" | |
30 | #include <limits.h> | |
31 | #ifdef __hpux | |
32 | # include <sys/time.h> | |
33 | #else | |
34 | # include <sys/select.h> | |
35 | #endif /* __hpux */ | |
36 | #ifdef HAVE_DNSSD | |
37 | # include <dns_sd.h> | |
38 | #endif /* HAVE_DNSSD */ | |
39 | ||
40 | ||
41 | /* | |
42 | * Local functions... | |
43 | */ | |
44 | ||
45 | #ifdef HAVE_DNSSD | |
46 | static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, | |
47 | uint32_t interfaceIndex, | |
48 | DNSServiceErrorType errorCode, | |
49 | const char *fullName, const char *hostTarget, | |
50 | uint16_t port, uint16_t txtLen, | |
51 | const unsigned char *txtRecord, void *context); | |
52 | #endif /* HAVE_DNSSD */ | |
53 | ||
54 | ||
55 | /* | |
56 | * 'backendCheckSideChannel()' - Check the side-channel for pending requests. | |
57 | */ | |
58 | ||
59 | ||
60 | void | |
61 | backendCheckSideChannel( | |
62 | int snmp_fd, /* I - SNMP socket */ | |
63 | http_addr_t *addr) /* I - Address of device */ | |
64 | { | |
65 | fd_set input; /* Select input set */ | |
66 | struct timeval timeout; /* Select timeout */ | |
67 | ||
68 | ||
69 | FD_ZERO(&input); | |
70 | FD_SET(CUPS_SC_FD, &input); | |
71 | ||
72 | timeout.tv_sec = timeout.tv_usec = 0; | |
73 | ||
74 | if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0) | |
75 | backendNetworkSideCB(-1, -1, snmp_fd, addr, 0); | |
76 | } | |
77 | ||
78 | ||
79 | /* | |
80 | * 'backendNetworkSideCB()' - Handle common network side-channel commands. | |
81 | */ | |
82 | ||
83 | void | |
84 | backendNetworkSideCB( | |
85 | int print_fd, /* I - Print file or -1 */ | |
86 | int device_fd, /* I - Device file or -1 */ | |
87 | int snmp_fd, /* I - SNMP socket */ | |
88 | http_addr_t *addr, /* I - Address of device */ | |
89 | int use_bc) /* I - Use back-channel data? */ | |
90 | { | |
91 | cups_sc_command_t command; /* Request command */ | |
92 | cups_sc_status_t status; /* Request/response status */ | |
93 | char data[2048]; /* Request/response data */ | |
94 | int datalen; /* Request/response data size */ | |
95 | const char *device_id; /* 1284DEVICEID env var */ | |
96 | ||
97 | ||
98 | datalen = sizeof(data); | |
99 | ||
100 | if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) | |
101 | { | |
102 | _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n")); | |
103 | return; | |
104 | } | |
105 | ||
106 | switch (command) | |
107 | { | |
108 | case CUPS_SC_CMD_DRAIN_OUTPUT : | |
109 | /* | |
110 | * Our sockets disable the Nagle algorithm and data is sent immediately. | |
111 | */ | |
112 | ||
113 | if (device_fd < 0) | |
114 | status = CUPS_SC_STATUS_NOT_IMPLEMENTED; | |
115 | else if (backendDrainOutput(print_fd, device_fd)) | |
116 | status = CUPS_SC_STATUS_IO_ERROR; | |
117 | else | |
118 | status = CUPS_SC_STATUS_OK; | |
119 | ||
120 | datalen = 0; | |
121 | break; | |
122 | ||
123 | case CUPS_SC_CMD_GET_BIDI : | |
124 | data[0] = use_bc; | |
125 | datalen = 1; | |
126 | break; | |
127 | ||
128 | case CUPS_SC_CMD_GET_DEVICE_ID : | |
129 | if (snmp_fd >= 0) | |
130 | { | |
131 | cups_snmp_t packet; /* Packet from printer */ | |
132 | static const int ppmPrinterIEEE1284DeviceId[] = | |
133 | { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; | |
134 | ||
135 | if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(), | |
136 | CUPS_ASN1_GET_REQUEST, 1, | |
137 | ppmPrinterIEEE1284DeviceId)) | |
138 | { | |
139 | if (_cupsSNMPRead(snmp_fd, &packet, 1.0) && | |
140 | packet.object_type == CUPS_ASN1_OCTET_STRING) | |
141 | { | |
142 | strlcpy(data, packet.object_value.string, sizeof(data)); | |
143 | datalen = (int)strlen(data); | |
144 | break; | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
149 | if ((device_id = getenv("1284DEVICEID")) != NULL) | |
150 | { | |
151 | strlcpy(data, device_id, sizeof(data)); | |
152 | datalen = (int)strlen(data); | |
153 | break; | |
154 | } | |
155 | ||
156 | default : | |
157 | status = CUPS_SC_STATUS_NOT_IMPLEMENTED; | |
158 | datalen = 0; | |
159 | break; | |
160 | } | |
161 | ||
162 | cupsSideChannelWrite(command, status, data, datalen, 1.0); | |
163 | } | |
164 | ||
165 | ||
166 | /* | |
167 | * 'backendResolveURI()' - Get the device URI, resolving as needed. | |
168 | */ | |
169 | ||
170 | const char * /* O - Device URI */ | |
171 | backendResolveURI(char **argv) /* I - Command-line arguments */ | |
172 | { | |
173 | const char *uri; /* Device URI */ | |
174 | char scheme[32], /* URI components... */ | |
175 | userpass[256], | |
176 | hostname[1024], | |
177 | resource[1024]; | |
178 | int port; | |
179 | http_uri_status_t status; /* URI decode status */ | |
180 | ||
181 | /* | |
182 | * Get the device URI... | |
183 | */ | |
184 | ||
185 | uri = cupsBackendDeviceURI(argv); | |
186 | ||
187 | if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, | |
188 | sizeof(scheme), userpass, sizeof(userpass), | |
189 | hostname, sizeof(hostname), &port, | |
190 | resource, sizeof(resource))) < HTTP_URI_OK) | |
191 | { | |
192 | fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status); | |
193 | exit (CUPS_BACKEND_STOP); | |
194 | } | |
195 | ||
196 | /* | |
197 | * Resolve it as needed... | |
198 | */ | |
199 | ||
969307f0 | 200 | if (strstr(resource, "._tcp") || strstr(hostname, "._tcp")) |
7a14d768 MS |
201 | { |
202 | #ifdef HAVE_DNSSD | |
203 | DNSServiceRef ref; /* DNS-SD service reference */ | |
969307f0 MS |
204 | char *full_name, /* Full (service) name */ |
205 | *regtype, /* Pointer to type in hostname */ | |
7a14d768 MS |
206 | *domain; /* Pointer to domain in hostname */ |
207 | static char resolved_uri[HTTP_MAX_URI]; | |
208 | /* Resolved device URI */ | |
209 | ||
210 | /* | |
211 | * Separate the hostname into service name, registration type, and domain... | |
212 | */ | |
213 | ||
969307f0 MS |
214 | if (strstr(resource, "._tcp")) |
215 | full_name = resource + 1; | |
216 | else | |
217 | full_name = hostname; | |
218 | ||
219 | regtype = strchr(full_name, '.'); | |
7a14d768 MS |
220 | *regtype++ = '\0'; |
221 | ||
222 | domain = regtype + strlen(regtype) - 1; | |
223 | if (domain > regtype && *domain == '.') | |
224 | *domain = '\0'; | |
225 | ||
226 | for (domain = strchr(regtype, '.'); | |
227 | domain; | |
228 | domain = strchr(domain + 1, '.')) | |
229 | if (domain[1] != '_') | |
230 | break; | |
231 | ||
232 | if (domain) | |
233 | *domain++ = '\0'; | |
234 | ||
235 | fprintf(stderr, | |
236 | "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n", | |
969307f0 | 237 | full_name, regtype, domain ? domain : "(null)"); |
7a14d768 | 238 | |
969307f0 | 239 | if (DNSServiceResolve(&ref, 0, 0, full_name, regtype, domain, |
7a14d768 MS |
240 | resolve_callback, |
241 | resolved_uri) == kDNSServiceErr_NoError) | |
242 | { | |
243 | if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError) | |
244 | uri = NULL; | |
245 | else | |
246 | uri = resolved_uri; | |
247 | ||
248 | DNSServiceRefDeallocate(ref); | |
249 | } | |
250 | else | |
251 | #endif /* HAVE_DNSSD */ | |
252 | ||
253 | uri = NULL; | |
254 | ||
255 | if (!uri) | |
256 | { | |
257 | fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri); | |
258 | exit(CUPS_BACKEND_STOP); | |
259 | } | |
260 | } | |
261 | ||
262 | return (uri); | |
263 | } | |
264 | ||
265 | ||
266 | #ifdef HAVE_DNSSD | |
267 | /* | |
268 | * 'resolve_callback()' - Build a device URI for the given service name. | |
269 | */ | |
270 | ||
271 | static void | |
272 | resolve_callback( | |
273 | DNSServiceRef sdRef, /* I - Service reference */ | |
274 | DNSServiceFlags flags, /* I - Results flags */ | |
275 | uint32_t interfaceIndex, /* I - Interface number */ | |
276 | DNSServiceErrorType errorCode, /* I - Error, if any */ | |
277 | const char *fullName, /* I - Full service name */ | |
278 | const char *hostTarget, /* I - Hostname */ | |
279 | uint16_t port, /* I - Port number */ | |
280 | uint16_t txtLen, /* I - Length of TXT record */ | |
281 | const unsigned char *txtRecord, /* I - TXT record data */ | |
282 | void *context) /* I - Pointer to URI buffer */ | |
283 | { | |
284 | const char *scheme; /* URI scheme */ | |
285 | char rp[257]; /* Remote printer */ | |
286 | const void *value; /* Value from TXT record */ | |
287 | uint8_t valueLen; /* Length of value */ | |
288 | ||
289 | ||
290 | fprintf(stderr, | |
291 | "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, " | |
292 | "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, " | |
293 | "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags, | |
294 | interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, | |
295 | txtRecord, context); | |
296 | ||
297 | /* | |
298 | * Figure out the scheme from the full name... | |
299 | */ | |
300 | ||
301 | if (strstr(fullName, "._ipp")) | |
302 | scheme = "ipp"; | |
303 | else if (strstr(fullName, "._printer.")) | |
304 | scheme = "lpd"; | |
305 | else if (strstr(fullName, "._pdl-datastream.")) | |
306 | scheme = "socket"; | |
307 | else | |
308 | scheme = "riousbprint"; | |
309 | ||
310 | /* | |
311 | * Extract the "remote printer" key from the TXT record... | |
312 | */ | |
313 | ||
314 | if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp", | |
315 | &valueLen)) != NULL) | |
316 | { | |
317 | /* | |
318 | * Convert to resource by concatenating with a leading "/"... | |
319 | */ | |
320 | ||
321 | rp[0] = '/'; | |
a0f6818e | 322 | memcpy(rp + 1, value, valueLen); |
7a14d768 MS |
323 | rp[valueLen + 1] = '\0'; |
324 | } | |
325 | else | |
326 | rp[0] = '\0'; | |
327 | ||
328 | /* | |
329 | * Assemble the final device URI... | |
330 | */ | |
331 | ||
332 | httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme, | |
333 | NULL, hostTarget, ntohs(port), rp); | |
334 | ||
335 | fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context); | |
336 | } | |
337 | #endif /* HAVE_DNSSD */ | |
338 | ||
339 | ||
340 | /* | |
341 | * End of "$Id$". | |
342 | */ |