]>
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 | * | |
19 | */ | |
20 | ||
21 | /* | |
22 | * Include necessary headers. | |
23 | */ | |
24 | ||
25 | #include "backend-private.h" | |
26 | #include <limits.h> | |
27 | #ifdef __hpux | |
28 | # include <sys/time.h> | |
29 | #else | |
30 | # include <sys/select.h> | |
31 | #endif /* __hpux */ | |
32 | #ifdef HAVE_DNSSD | |
33 | # include <dns_sd.h> | |
34 | #endif /* HAVE_DNSSD */ | |
35 | ||
36 | ||
37 | /* | |
38 | * Local functions... | |
39 | */ | |
40 | ||
41 | #ifdef 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 */ | |
49 | ||
50 | ||
51 | /* | |
52 | * 'backendCheckSideChannel()' - Check the side-channel for pending requests. | |
53 | */ | |
54 | ||
55 | ||
56 | void | |
57 | backendCheckSideChannel( | |
58 | int snmp_fd, /* I - SNMP socket */ | |
59 | http_addr_t *addr) /* I - Address of device */ | |
60 | { | |
61 | fd_set input; /* Select input set */ | |
62 | struct timeval timeout; /* Select timeout */ | |
63 | ||
64 | ||
65 | FD_ZERO(&input); | |
66 | FD_SET(CUPS_SC_FD, &input); | |
67 | ||
68 | timeout.tv_sec = timeout.tv_usec = 0; | |
69 | ||
70 | if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0) | |
71 | backendNetworkSideCB(-1, -1, snmp_fd, addr, 0); | |
72 | } | |
73 | ||
74 | ||
75 | /* | |
76 | * 'backendNetworkSideCB()' - Handle common network side-channel commands. | |
77 | */ | |
78 | ||
79 | void | |
80 | backendNetworkSideCB( | |
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? */ | |
86 | { | |
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 */ | |
92 | ||
93 | ||
94 | datalen = sizeof(data); | |
95 | ||
96 | if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) | |
97 | { | |
98 | _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n")); | |
99 | return; | |
100 | } | |
101 | ||
102 | switch (command) | |
103 | { | |
104 | case CUPS_SC_CMD_DRAIN_OUTPUT : | |
105 | /* | |
106 | * Our sockets disable the Nagle algorithm and data is sent immediately. | |
107 | */ | |
108 | ||
109 | if (device_fd < 0) | |
110 | status = CUPS_SC_STATUS_NOT_IMPLEMENTED; | |
111 | else if (backendDrainOutput(print_fd, device_fd)) | |
112 | status = CUPS_SC_STATUS_IO_ERROR; | |
113 | else | |
114 | status = CUPS_SC_STATUS_OK; | |
115 | ||
116 | datalen = 0; | |
117 | break; | |
118 | ||
119 | case CUPS_SC_CMD_GET_BIDI : | |
120 | data[0] = use_bc; | |
121 | datalen = 1; | |
122 | break; | |
123 | ||
124 | case CUPS_SC_CMD_GET_DEVICE_ID : | |
125 | if (snmp_fd >= 0) | |
126 | { | |
127 | cups_snmp_t packet; /* Packet from printer */ | |
128 | static const int ppmPrinterIEEE1284DeviceId[] = | |
129 | { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; | |
130 | ||
131 | if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(), | |
132 | CUPS_ASN1_GET_REQUEST, 1, | |
133 | ppmPrinterIEEE1284DeviceId)) | |
134 | { | |
135 | if (_cupsSNMPRead(snmp_fd, &packet, 1.0) && | |
136 | packet.object_type == CUPS_ASN1_OCTET_STRING) | |
137 | { | |
138 | strlcpy(data, packet.object_value.string, sizeof(data)); | |
139 | datalen = (int)strlen(data); | |
140 | break; | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | if ((device_id = getenv("1284DEVICEID")) != NULL) | |
146 | { | |
147 | strlcpy(data, device_id, sizeof(data)); | |
148 | datalen = (int)strlen(data); | |
149 | break; | |
150 | } | |
151 | ||
152 | default : | |
153 | status = CUPS_SC_STATUS_NOT_IMPLEMENTED; | |
154 | datalen = 0; | |
155 | break; | |
156 | } | |
157 | ||
158 | cupsSideChannelWrite(command, status, data, datalen, 1.0); | |
159 | } | |
160 | ||
161 | ||
162 | /* | |
163 | * 'backendResolveURI()' - Get the device URI, resolving as needed. | |
164 | */ | |
165 | ||
166 | const char * /* O - Device URI */ | |
167 | backendResolveURI(char **argv) /* I - Command-line arguments */ | |
168 | { | |
169 | const char *uri; /* Device URI */ | |
170 | char scheme[32], /* URI components... */ | |
171 | userpass[256], | |
172 | hostname[1024], | |
173 | resource[1024]; | |
174 | int port; | |
175 | http_uri_status_t status; /* URI decode status */ | |
176 | ||
177 | /* | |
178 | * Get the device URI... | |
179 | */ | |
180 | ||
181 | uri = cupsBackendDeviceURI(argv); | |
182 | ||
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) | |
187 | { | |
188 | fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status); | |
189 | exit (CUPS_BACKEND_STOP); | |
190 | } | |
191 | ||
192 | /* | |
193 | * Resolve it as needed... | |
194 | */ | |
195 | ||
196 | if (strstr(hostname, "._tcp")) | |
197 | { | |
198 | #ifdef HAVE_DNSSD | |
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 */ | |
204 | ||
205 | /* | |
206 | * Separate the hostname into service name, registration type, and domain... | |
207 | */ | |
208 | ||
209 | regtype = strchr(hostname, '.'); | |
210 | *regtype++ = '\0'; | |
211 | ||
212 | domain = regtype + strlen(regtype) - 1; | |
213 | if (domain > regtype && *domain == '.') | |
214 | *domain = '\0'; | |
215 | ||
216 | for (domain = strchr(regtype, '.'); | |
217 | domain; | |
218 | domain = strchr(domain + 1, '.')) | |
219 | if (domain[1] != '_') | |
220 | break; | |
221 | ||
222 | if (domain) | |
223 | *domain++ = '\0'; | |
224 | ||
225 | fprintf(stderr, | |
226 | "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n", | |
227 | hostname, regtype, domain ? domain : "(null)"); | |
228 | ||
229 | if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain, | |
230 | resolve_callback, | |
231 | resolved_uri) == kDNSServiceErr_NoError) | |
232 | { | |
233 | if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError) | |
234 | uri = NULL; | |
235 | else | |
236 | uri = resolved_uri; | |
237 | ||
238 | DNSServiceRefDeallocate(ref); | |
239 | } | |
240 | else | |
241 | #endif /* HAVE_DNSSD */ | |
242 | ||
243 | uri = NULL; | |
244 | ||
245 | if (!uri) | |
246 | { | |
247 | fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri); | |
248 | exit(CUPS_BACKEND_STOP); | |
249 | } | |
250 | } | |
251 | ||
252 | return (uri); | |
253 | } | |
254 | ||
255 | ||
256 | #ifdef HAVE_DNSSD | |
257 | /* | |
258 | * 'resolve_callback()' - Build a device URI for the given service name. | |
259 | */ | |
260 | ||
261 | static void | |
262 | resolve_callback( | |
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 */ | |
273 | { | |
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 */ | |
278 | ||
279 | ||
280 | fprintf(stderr, | |
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, | |
285 | txtRecord, context); | |
286 | ||
287 | /* | |
288 | * Figure out the scheme from the full name... | |
289 | */ | |
290 | ||
291 | if (strstr(fullName, "._ipp")) | |
292 | scheme = "ipp"; | |
293 | else if (strstr(fullName, "._printer.")) | |
294 | scheme = "lpd"; | |
295 | else if (strstr(fullName, "._pdl-datastream.")) | |
296 | scheme = "socket"; | |
297 | else | |
298 | scheme = "riousbprint"; | |
299 | ||
300 | /* | |
301 | * Extract the "remote printer" key from the TXT record... | |
302 | */ | |
303 | ||
304 | if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp", | |
305 | &valueLen)) != NULL) | |
306 | { | |
307 | /* | |
308 | * Convert to resource by concatenating with a leading "/"... | |
309 | */ | |
310 | ||
311 | rp[0] = '/'; | |
312 | memcpy(rp, value, valueLen); | |
313 | rp[valueLen + 1] = '\0'; | |
314 | } | |
315 | else | |
316 | rp[0] = '\0'; | |
317 | ||
318 | /* | |
319 | * Assemble the final device URI... | |
320 | */ | |
321 | ||
322 | httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme, | |
323 | NULL, hostTarget, ntohs(port), rp); | |
324 | ||
325 | fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context); | |
326 | } | |
327 | #endif /* HAVE_DNSSD */ | |
328 | ||
329 | ||
330 | /* | |
331 | * End of "$Id$". | |
332 | */ |